about_Arithmetic_Operators

简短说明

介绍在 PowerShell 中执行算术的运算符。

长说明

算术运算符用于计算数值。 可以使用一个或多个算术运算符对值进行加减乘除,以及计算除法运算的余数(模数)。

加法运算符 (+) 和乘法运算符 (*) 也可对字符串、数组和哈希表进行操作。 加法运算符可连接输入。 乘法运算符可返回输入的多个副本。 甚至可以在算术语句中混合对象类型。 用于计算语句的方法由表达式中最左侧对象的类型确定。

从 PowerShell 2.0 开始,所有算术运算符都能处理 64 位数字。

从 PowerShell 3.0 开始,将添加 -shr(向右移位)和 -shl(向左移位),以支持 PowerShell 中的按位算术。 按位运算符仅适用于整数类型。

PowerShell 支持以下算术运算符:

  • 加 (+) - 加上数字、连接字符串、数组和哈希表

    6 + 2                        # result = 8
    "file" + "name"              # result = "filename"
    @(1, "one") + @(2.0, "two")  # result = @(1, "one", 2.0, "two")
    @{"one" = 1} + @{"two" = 2}  # result = @{"one" = 1; "two" = 2}
    
  • 减 (-) - 减去或求反数字

    6 - 2   # result = 4
    - -6    # result = 6
    (Get-Date).AddDays(-1) # Yesterday's date
    
  • 乘 (*) - 将数字或复制字符串和数组乘以指定的次数

    6 * 2       # result = 12
    @("!") * 4  # result = @("!","!","!","!")
    "!" * 3     # result = "!!!"
    
  • 除 (/) - 除以数字

    6 / 2  # result = 3
    
  • 模数 (%) - 返回除法运算的余数。

    7 % 2  # result = 1
    
  • 按位 AND (-band)

    5 -band 3  # result = 1
    
  • 按位 NOT (-bnot)

    -bnot 5  # result = -6
    
  • 按位 OR (-bor)

    5 -bor 0x03  # result = 7
    
  • 按位 XOR (-bxor)

    5 -bxor 3   # result = 6
    
  • 向左移位 (-shl)

    102 -shl 2  # result = 408
    
  • 向右移位 (-shr)

    102 -shr 2  # result = 25
    

运算符优先级

PowerShell 按以下顺序处理算术运算符:

优先顺序 运算符 说明
1 () 括号
2 - 对于负数或一元运算符
3 */、、 % 对于乘法和除法
4 +, - 对于加法和减法
5 -band, -bnot 对于按位运算
5 -bor, -bxor 对于按位运算
5 -shr, -shl 对于按位运算

PowerShell 根据优先规则从左到右处理表达式。 以下示例演示了优先规则的效果:

3+6/3*4    # result = 11
3+6/(3*4)  # result = 3.5
(3+6)/3*4  # result = 12

PowerShell 计算表达式的顺序可能与你使用的其他编程和脚本语言不同。 以下示例演示了一个复杂的赋值语句。

$a = 0
$b = @(1,2)
$c = @(-1,-2)

$b[$a] = $c[$a++]

在此示例中,表达式 $a++ 是在 $b[$a] 之前计算的。 计算 $a++ 会更改 $a 在语句 $c[$a++] 中使用之后但在 $b[$a] 中使用之前的值。 $b[$a] 中的变量 $a 等于 1,而不是 0。 因此,该语句将值赋给 $b[1],而不是 $b[0]

上面的代码等效于:

$a = 0
$b = @(1,2)
$c = @(-1,-2)

$tmp = $c[$a]
$a = $a + 1
$b[$a] = $tmp

除法和舍入

当除法运算的商是整数时,PowerShell 会将值舍入到最接近的整数。 当值是 .5 时,将舍入到最接近的偶数整数。

以下示例演示舍入到最接近的偶数整数的效果。

PS> [int]( 5 / 2 )  # Result is rounded down
2

PS> [int]( 7 / 2 )  # Result is rounded up
4

可以使用 [Math] 类获取不同的舍入行为。

PS> [int][Math]::Round(5 / 2,[MidpointRounding]::AwayFromZero)
3

PS> [int][Math]::Ceiling(5 / 2)
3

PS> [int][Math]::Floor(5 / 2)
2

有关详细信息,请参阅 Math.Round 方法。

用于适应结果的类型转换

PowerShell 会自动选择最能表达结果的 .NET 数值类型,而不会失去精度。 例如:

2 + 3.1
(2).GetType().FullName
(2 + 3.1).GetType().FullName
5.1
System.Int32
System.Double

如果操作的结果对于类型太大,结果的类型将扩大以适应结果,如以下示例所示:

(512MB).GetType().FullName
(512MB * 512MB).GetType().FullName
System.Int32
System.Double

结果的类型并不总是与其中一个操作数相同。 在以下示例中,负值不能强制转换为无符号整数,而无符号整数太大,无法强制转换为 Int32

([int32]::minvalue + [uint32]::maxvalue).gettype().fullname
System.Int64

在此示例中,Int64 可以容纳这两种类型。

System.Decimal 类型是一个例外。 如果任一操作数具有十进制类型,则结果为十进制类型。 十进制值的任何过大结果都是错误。

PS> [Decimal]::maxvalue
79228162514264337593543950335

PS> [Decimal]::maxvalue + 1
RuntimeException: Value was either too large or too small for a Decimal.

精度的潜在损失

只要有超出类型范围的结果,就有可能由于类型转换而丢失精度。 例如,添加足够大的 [long] 操作数并 [int] 导致操作数转换为 [double]。 在此示例中, 9223372036854775807 是整数 [long] 的最大值。 添加到值会溢出范围 [long]

PS> (9223372036854775807 + 2).GetType().FullName
System.Double

将结果强制转换为 [ulong] 生成不准确的结果,因为操作数被强制转换为 [double] 第一个结果。

PS> [ulong](9223372036854775807 + 2)
9223372036854775808

首先 [ulong] 定义更大的值会避免问题并生成正确的结果。

PS> 9223372036854775807ul + 2
9223372036854775809

但是,超出结果[double]的范围[ulong]

PS> ([ulong]::MaxValue + 1).GetType().FullName
System.Double

Bigint 算术

[bigint] 数字执行算术运算时,PowerShell 使用将所有操作数 [bigint]转换为,这会导致截断非整数值。 例如,在转换为时,该值[double]1.9将被1截断为 [bigint]

PS> [bigint]1 / 1.9
1
PS> 1 / [bigint]1.9
1

此行为不同于其他数值类型的行为。 在此示例中,[int]将结果除以[double][double]结果。 强制转换为1.9[int]向上舍入值2

PS> 1 / 1.9
0.526315789473684
PS> 1 / [int]1.9
0.5

加上和乘以非数值类型

可以加上数字、字符串、数组和哈希表。 也可以将数字、字符串和数组相乘。 但是,不能将哈希表相乘。

加上字符串、数组或哈希表时,元素将连接。 连接集合(如数组或哈希表)时,会创建一个新对象,其中包含这两个集合中的对象。 如果你尝试连接具有相同键的哈希表,运算将失败。

例如,以下命令会创建两个数组,然后添加它们:

$a = 1,2,3
$b = "A","B","C"
$a + $b
1
2
3
A
B
C

还可以对不同类型的对象执行算术运算。 PowerShell 执行的运算由运算中最左侧对象的 Microsoft .NET 类型确定。 PowerShell 尝试将运算中的所有对象转换为第一个对象的 .NET 类型。 如果成功转换对象,它将执行适用于第一个对象的 .NET 类型的运算。 如果它无法转换任何对象,运算将失败。

以下示例演示如何在包含不同对象类型的运算中使用加法和乘法运算符。

$array = 1,2,3
$red = [ConsoleColor]::Red
$blue = [ConsoleColor]::Blue

"file" + 16      # result = "file16"
$array + 16      # result = 1,2,3,16
$array + "file"  # result = 1,2,3,"file"
$array * 2       # result = 1,2,3,1,2,3
"file" * 3       # result = "filefilefile"
$blue + 3        # result = Red
$red - 3         # result = Blue
$blue - $red     # result = -3
+ '123'          # result = 123

由于用于计算语句的方法由最左侧的对象确定,因此 PowerShell 中的加法和乘法并不严格是可交换的。 例如,(a + b) 并不总是等于 (b + a)(ab) 并不总是等于 (ba)

以下示例演示了此原则:

PS> "file" + 16
file16

PS> 16 + "file"
InvalidArgument: can't convert value "file" to type "System.Int32". Error:
"Input string wasn't in a correct format."

哈希表的情况略有不同。 可以将哈希表添加到另一个哈希表,只要添加的哈希表没有重复键。

以下示例演示如何向彼此添加哈希表。

$hash1 = @{a=1; b=2; c=3}
$hash2 = @{c1="Server01"; c2="Server02"}
$hash1 + $hash2
Name                           Value
----                           -----
c2                             Server02
a                              1
b                              2
c1                             Server01
c                              3

下面的示例会引发错误,因为其中一个键在两个哈希表中重复。

$hash1 = @{a=1; b=2; c=3}
$hash2 = @{c1="Server01"; c="Server02"}
$hash1 + $hash2
OperationStopped:
Line |
   3 |  $hash1 + $hash2
     |  ~~~~~~~~~~~~~~~
     | Item has already been added. Key in dictionary: 'c'  Key being added: 'c'

此外,还可以向数组添加哈希表;并且,整个哈希表将成为数组中的项。

$array1 = @(0, "Hello World", [datetime]::Now)
$hash1 = @{a=1; b=2}
$array2 = $array1 + $hash1
$array2
0
Hello World

Monday, June 12, 2017 3:05:46 PM

Key   : a
Value : 1
Name  : a

Key   : b
Value : 2
Name  : b

但是,不能向哈希表添加任何其他类型。

$hash1 + 2
InvalidOperation: A hash table can only be added to another hash table.

尽管加法运算符非常有用,但会使用赋值运算符将元素添加到哈希表和数组。 有关详细信息,请参阅 about_assignment_operators。 以下示例使用 += 赋值运算符将项添加到数组:

$array = @()
(0..2).foreach{ $array += $_ }
$array
0
1
2

算术运算符和变量

还可以将算术运算符与变量一起使用。 运算符作用于变量的值。 以下示例演示如何对变量使用算术运算符:

PS> $intA = 6
PS> $intB = 4
PS> $intA + $intB
10

PS> $a = "Power"
PS> $b = "Shell"
PS> $a + $b
PowerShell

算术运算符和命令

通常,在表达式中使用具有数字、字符串和数组的算术运算符。 但是,也可以将算术运算符与命令返回的对象和这些对象的属性一起使用。

以下示例演示如何在表达式中使用算术运算符和 PowerShell 命令:

(Get-Date) + (New-TimeSpan -day 1)

括号运算符按该顺序强制计算 Get-Date cmdlet 和 New-TimeSpan -Day 1 cmdlet 表达式。 然后使用 + 运算符加上这两个结果。

Get-Process | Where-Object { ($_.ws * 2) -gt 50mb }
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
   1896      39    50968      30620   264 1,572.55   1104 explorer
  12802      78   188468      81032   753 3,676.39   5676 OUTLOOK
    660       9    36168      26956   143    12.20    988 PowerShell
    561      14     6592      28144   110 1,010.09    496 services
   3476      80    34664      26092   234 ...45.69    876 svchost
    967      30    58804      59496   416   930.97   2508 WINWORD

在上述表达式中,每个进程工作空间 ($_.ws) 乘以 2;并且结果与 50mb 进行比较,以确定它是否大于该值。

位运算符

PowerShell 支持标准按位运算符,包括按位 AND (-band)、包含性和排除性按位 OR 运算符(-bor-bxor),以及按位 NOT (-bnot)。

从 PowerShell 2.0 开始,所有按位运算符都使用 64 位整数。

从 PowerShell 3.0 开始,引入了 -shr(向右移位)和 -shl(向左移位)以支持 PowerShell 中的按位算术。

PowerShell 支持以下按位运算符。

运算符 说明 表达式 结果
-band 位与 10 -band 3 2
-bor 按位 OR(包含) 10 -bor 3 11
-bxor 按位 OR(排除) 10 -bxor 3 9
-bnot 按位“非” -bNot 10 -11
-shl 左移 102 -shl 2 408
-shr 右移 102 -shr 1 51

按位运算符作用于值的二进制格式。 例如,数字 10 的位结构为 00001010(基于 1 字节),数字 3 的位结构为 00000011。 使用按位运算符比较 10 与 3 时,将比较每个字节中的单个位。

在按位 AND 运算中,仅当两个输入位均为 1 时,生成的位才设置为 1。

1010      (10)
0011      ( 3)
--------------  bAND
0010      ( 2)

在按位 OR(包含)运算中,当任一位或两个输入位均为 1 时,生成的位设置为 1。 仅当两个输入位都设置为 0 时,生成的位才设置为 0。

1010      (10)
0011      ( 3)
--------------  bOR (inclusive)
1011      (11)

在按位 OR(排除)运算中,仅当一个输入位为 1 时,生成的位才设置为 1。

1010      (10)
0011      ( 3)
--------------  bXOR (exclusive)
1001      ( 9)

按位 NOT 运算符是一元运算符,它生成值的二进制补数。 1 位设置为 0,0 位设置为 1。

例如,0 的二进制补数为 -1、最大无符号整数 (0xFFFFFFFF),而 -1 的二进制补数为 0。

-bNot 10
-11
0000 0000 0000 1010  (10)
------------------------- bNOT
1111 1111 1111 0101  (-11, 0xFFFFFFF5)

在按位向左移位运算中,所有位都向左移动“n”位,其中“n”是右操作数的值。 0 插入到 1 位的位置。

表达 结果 二进制结果
21 -shl 0 21 0001 0101
21 -shl 1 42 0010 1010
21 -shl 2 84 0101 0100

在按位向右移位运算中,所有位都向右移动“n”位,其中“n”由右操作数指定。 向右移位运算符 (-shr) 在移动有符号值时将符号位复制到最左侧的位置。 对于无符号值,0 插入到最左侧的位置。

表达式 结果 二进制 Hex
21 -shr 0 21 00010101 0x15
21 -shr 1 10 00001010 0x0A
21 -shr 2 5 00000101 0x05
21 -shr 31 0 00000000 0x00
21 -shr 32 21 00010101 0x15
21 -shr 64 21 00010101 0x15
21 -shr 65 10 00001010 0x0A
21 -shr 66 5 00000101 0x05
[int]::MaxValue -shr 1 1073741823 00111111111111111111111111111111 0x3FFFFFFF
[int]::MinValue -shr 1 -1073741824 11000000000000000000000000000000 0xC0000000
-1 -shr 1 -1 11111111111111111111111111111111 0xFFFFFFFF
(-21 -shr 1) -11 11111111111111111111111111110101 0xFFFFFFF5
(-21 -shr 2) -6 11111111111111111111111111111010 0xFFFFFFF4

另请参阅