Powershell:将分数转换为整数 - 令人惊讶的舍入行为
Powershell: convert a fraction to an integer - surprising rounding behavior
我有一个关于带小数的整数的有趣问题。
假设我执行以下操作:
[int] $a = 5/2
$a
我已经试了 10 次了,powershell 总是 returns 2
有没有办法强制 Powershell 在这种情况下向上或向下舍入,默认情况下是否设置为向下舍入?
我假设取决于机器和 Powershell 环境,我可能在某些时候得到 3 个,在其他时候得到 2 个。
[Math]::Floor($a) --> 2
[Math]::Ceiling($a)--> 3
[Math]::Round($a) --> 2
Floor
会给出前面的整数,Ceiling
会给出后面的整数。
但是如果你想向上舍入,使用 Round
函数,它将遵循中点舍入( 中点舍入在历史上远离零 ),如下所示 -
[Math]::Round(2.50) --> 2
[Math]::Round(2.51) --> 3
[Math]::Round(2.49) --> 2
[math]::Round(2.50,[System.MidpointRounding]::AwayFromZero) --> 3
[math]::Round(2.49,[System.MidpointRounding]::AwayFromZero) --> 2
[math]::Round(2.51,[System.MidpointRounding]::AwayFromZero) --> 3
您可以根据需要使用任一功能。
很有帮助,但有一些令人困惑的方面。
一般来说,将小数转换为整数总是涉及到四舍五入的形式;在 casting 和 implicit 转换的上下文中,编程语言通常使用 rounding to the nearest integer[=195= 的形式]. 特殊注意事项适用于小数部分正好是.5
的模糊情况,其中多于一个存在策略 - 不同的编程语言采用不同的策略。
在构建 PowerShell 的 .NET Framework 的上下文中,这些策略的 总称 是 中点四舍五入,下面使用的具体策略名称指中点(.5
)为half 为简洁起见(以下示例使用 PowerShell 语法,但适用于 所有 .NET 语言)。
将转换为[int]
总是采用half-to-even四舍五入,其中小数部分为.5
的数字四舍五入到最接近的 even 整数(无论正数还是负数):
[int] 2.5
-> 2
(!) 情境向下舍入,因为整数部分恰好是偶数 和阳性
[int] 3.5
-> 4
情境 向上-四舍五入
- 此舍入策略也适用于 隐式 到 PowerShell 有时执行的整数类型的转换 - 请参阅上一节。
- PowerShell 语法陷阱:强制转换的优先级高于
/
,因此 [int] 5/2
无效 如预期;使用 [int] (5/2)
.
要控制中点舍入行为,请使用.NET [Math]
class' Round()
方法:
用[int] [Math]::Round($number, [MidpointRounding]::AwayFromZero)
得到half-away-from-zero rounding(分数为 .5
的数字四舍五入到最接近的整数,其 absolute 值是 larger)。
[Math]::Round(2.5, [MidpointRounding]::AwayFromZero)
-> 3
[Math]::Round(-2.5, [MidpointRounding]::AwayFromZero)
-> -3
- 注意:
[Math]
方法(通常)return a [double]
,因此您可能必须将结果转换为 [int]
(或不同的整数类型)得到一个真正的整数。
请注意,[Math]::Round()
不仅提供到-整数 舍入,而且还提供特定数量的小数位数;例如,
[Math]::Round(2.55, 1, [MidpointRounding]::AwayFromZero)
产生 2.6
. 谢谢,Ansgar Wiechers.
其他形式的四舍五入:那些与小数部分(0
除外)的具体值无关的:
使用[Math]::Truncate($number)
得到toward-zero四舍五入(去掉小数部分):
[Math]::Truncate(2.1)
-> 2
; 2.5
和 2.9
同上,例如
[Math]::Truncate(-2.1)
-> -2
使用[Math]::Ceiling($number)
得到toward-positive-infinity四舍五入(四舍五入到最接近的 greater-or-equal 整数):
[Math]::Ceiling(2.1)
-> 3
[Math]::Ceiling(-2.1)
-> -2
(!)
使用[int] [Math]::Floor($number)
得到toward-negative-infinity四舍五入(向下舍入到最接近的 smaller-or-equal 整数):
[Math]::Floor(2.1)
-> 2
[Math]::Floor(-2.1)
-> -3
(!)
可选的进一步阅读:
PowerShell 执行 隐式 转换的示例,其中使用了此策略:
1..(2.5)
产生数组 1, 2
,因为 range-operator 表达式的端点 2.5
被强制为 [int]
2
,所以表达式实际上与 1..2
相同
由于 PowerShell 建立在 .NET Framework 之上,因此最终 [Convert]::ToInt32()
被调用。
也许令人惊讶的 round-half-to-even 策略背后的意图是 "to minimize the expected error when summing over rounded figures", according to Wikipedia.
维基百科关于舍入的页面有一个关于 rounding functions across programming languages 的部分。
与 .NET 相比,JavaScript,例如,采用 half-up 舍入(Math.round(2.5)
-> 3
, Math.round(-2.5)
-> -2
) - .NET 甚至不提供的 midpoint-rounding 模式。
我有一个关于带小数的整数的有趣问题。
假设我执行以下操作:
[int] $a = 5/2
$a
我已经试了 10 次了,powershell 总是 returns 2
有没有办法强制 Powershell 在这种情况下向上或向下舍入,默认情况下是否设置为向下舍入?
我假设取决于机器和 Powershell 环境,我可能在某些时候得到 3 个,在其他时候得到 2 个。
[Math]::Floor($a) --> 2
[Math]::Ceiling($a)--> 3
[Math]::Round($a) --> 2
Floor
会给出前面的整数,Ceiling
会给出后面的整数。
但是如果你想向上舍入,使用 Round
函数,它将遵循中点舍入( 中点舍入在历史上远离零 ),如下所示 -
[Math]::Round(2.50) --> 2
[Math]::Round(2.51) --> 3
[Math]::Round(2.49) --> 2
[math]::Round(2.50,[System.MidpointRounding]::AwayFromZero) --> 3
[math]::Round(2.49,[System.MidpointRounding]::AwayFromZero) --> 2
[math]::Round(2.51,[System.MidpointRounding]::AwayFromZero) --> 3
您可以根据需要使用任一功能。
一般来说,将小数转换为整数总是涉及到四舍五入的形式;在 casting 和 implicit 转换的上下文中,编程语言通常使用 rounding to the nearest integer[=195= 的形式]. 特殊注意事项适用于小数部分正好是.5
的模糊情况,其中多于一个存在策略 - 不同的编程语言采用不同的策略。
在构建 PowerShell 的 .NET Framework 的上下文中,这些策略的 总称 是 中点四舍五入,下面使用的具体策略名称指中点(.5
)为half 为简洁起见(以下示例使用 PowerShell 语法,但适用于 所有 .NET 语言)。
将转换为
[int]
总是采用half-to-even四舍五入,其中小数部分为.5
的数字四舍五入到最接近的 even 整数(无论正数还是负数):[int] 2.5
->2
(!) 情境向下舍入,因为整数部分恰好是偶数 和阳性[int] 3.5
->4
情境 向上-四舍五入- 此舍入策略也适用于 隐式 到 PowerShell 有时执行的整数类型的转换 - 请参阅上一节。
- PowerShell 语法陷阱:强制转换的优先级高于
/
,因此[int] 5/2
无效 如预期;使用[int] (5/2)
.
要控制中点舍入行为,请使用.NET
[Math]
class'Round()
方法:用
[int] [Math]::Round($number, [MidpointRounding]::AwayFromZero)
得到half-away-from-zero rounding(分数为.5
的数字四舍五入到最接近的整数,其 absolute 值是 larger)。[Math]::Round(2.5, [MidpointRounding]::AwayFromZero)
->3
[Math]::Round(-2.5, [MidpointRounding]::AwayFromZero)
->-3
- 注意:
[Math]
方法(通常)return a[double]
,因此您可能必须将结果转换为[int]
(或不同的整数类型)得到一个真正的整数。
请注意,[Math]::Round()
不仅提供到-整数 舍入,而且还提供特定数量的小数位数;例如,
[Math]::Round(2.55, 1, [MidpointRounding]::AwayFromZero)
产生 2.6
. 谢谢,Ansgar Wiechers.
其他形式的四舍五入:那些与小数部分(0
除外)的具体值无关的:
使用
[Math]::Truncate($number)
得到toward-zero四舍五入(去掉小数部分):[Math]::Truncate(2.1)
->2
;2.5
和2.9
同上,例如[Math]::Truncate(-2.1)
->-2
使用
[Math]::Ceiling($number)
得到toward-positive-infinity四舍五入(四舍五入到最接近的 greater-or-equal 整数):[Math]::Ceiling(2.1)
->3
[Math]::Ceiling(-2.1)
->-2
(!)
使用
[int] [Math]::Floor($number)
得到toward-negative-infinity四舍五入(向下舍入到最接近的 smaller-or-equal 整数):[Math]::Floor(2.1)
->2
[Math]::Floor(-2.1)
->-3
(!)
可选的进一步阅读:
PowerShell 执行 隐式 转换的示例,其中使用了此策略:
1..(2.5)
产生数组 1, 2
,因为 range-operator 表达式的端点 2.5
被强制为 [int]
2
,所以表达式实际上与 1..2
由于 PowerShell 建立在 .NET Framework 之上,因此最终 [Convert]::ToInt32()
被调用。
也许令人惊讶的 round-half-to-even 策略背后的意图是 "to minimize the expected error when summing over rounded figures", according to Wikipedia.
维基百科关于舍入的页面有一个关于 rounding functions across programming languages 的部分。
与 .NET 相比,JavaScript,例如,采用 half-up 舍入(Math.round(2.5)
-> 3
, Math.round(-2.5)
-> -2
) - .NET 甚至不提供的 midpoint-rounding 模式。