Powershell:将分数转换为整数 - 令人惊讶的舍入行为

Aid*_*den 5 powershell integer bankers-rounding rounding

关于带小数的整数,我有一个有趣的问题.

假设我执行以下操作:

[int] $a = 5/2
$a
Run Code Online (Sandbox Code Playgroud)

我已经尝试了10次以确保,并且powershell总是返回 2

有没有办法强制Powershell在这种情况下向上或向下舍入,默认情况下它已设置为向下舍入?

我假设依赖于机器和Powershell环境,我可能在某些点得到3而在其他点得到2.

Viv*_*ngh 6

[Math]::Floor($a) --> 2
[Math]::Ceiling($a)--> 3
[Math]::Round($a) --> 2
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

您可以根据需要使用任一功能.

  • 舍入2.5到2不是基础数学.发生这种情况是因为Powershells默认的MidpointRounding模式是ToEven,因此它会将.5数字舍入到最接近的偶数整数.要使用基础数学,您可以为AwayFromZero指定MidpointRounding模式. (3认同)

mkl*_*nt0 5

Vivek Kumar的回答很有帮助,但有一些令人困惑的方面.

通常,将分数转换为整数总是涉及一种舍入形式; 在转换隐式转换的上下文中,编程语言通常使用舍入到最接近整数的形式.特殊考虑适用于数字.5的模糊情况,其小数部分是精确的,存在多个策略 - 并且不同的编程语言采用不同的策略.

在构建PowerShell 的.NET Framework环境中,这些策略的总称中点舍入,下面使用的特定策略名称将中点(.5)称为简洁的一半(以下示例使用PowerShell语法,但适用于所有 .NET语言).

  • 铸造[int] 总是采用到偶数舍入,其中具有的小数部分的数字.5被四舍五入到最接近的偶数整数(无论正或负):

    • [int] 2.5- > 2(!)情境下行,因为整数部分恰好是偶数和正数
    • [int] 3.5- > 4情景 -rounding
    • 此舍入策略也适用于PowerShell有时执行的整数类型的隐式转换 - 请参阅上一节.
    • PowerShell的语法陷阱:铸造的优先级高于/,所以[int] 5/2不能按预期工作; 用[int] (5/2).
  • 控制中点舍入行为,请使用.NET [Math]类的 Round()方法:

    • 使用[int] [Math]::Round($number, [MidpointRounding]::AwayFromZero)得到外之零取整(有一小部分的数字.5四舍五入到其最接近的整数绝对越大).

      • [Math]::Round(2.5, [MidpointRounding]::AwayFromZero) - > 3
      • [Math]::Round(-2.5, [MidpointRounding]::AwayFromZero) - > -3
      • 注意:[Math]方法(通常)返回a [double],因此您可能必须将结果转换为[int](或不同的整数类型)以获得真正的整数.

请注意,[Math]::Round()不仅提供整数舍入,还提供特定数量的小数位 ; 例如,
[Math]::Round(2.55, 1, [MidpointRounding]::AwayFromZero)收益率2.6.谢谢,Ansgar Wiechers.


其他形式的舍入:小数部分(除了0)的特定值无关的那些:

  • 使用[Math]::Truncate($number)得到朝零取整(去除小数部分):

    • [Math]::Truncate(2.1)- > 2; 同上,用于2.52.9,例如
    • [Math]::Truncate(-2.1) - > -2
  • 使用[Math]::Ceiling($number)得到朝正无穷舍入(四舍五入到最接近的更大,或相等的整数):

    • [Math]::Ceiling(2.1) - > 3
    • [Math]::Ceiling(-2.1)- > -2(!)
  • 使用[int] [Math]::Floor($number)得到朝负无穷舍入(四舍五入到最接近的较小或相等的整数):

    • [Math]::Floor(2.1) - > 2
    • [Math]::Floor(-2.1)- > -3(!)

可选进一步阅读:

PowerShell执行使用此策略的隐式转换的示例:

1..(2.5)yield数组1, 2,因为范围运算符表达式的端点2.5被强制转换[int] 2,因此表达式实际上与1..2

由于PowerShell构建于.NET Framework之上,因此最终[Convert]::ToInt32()会调用它.

根据维基百科的说法,可能出人意料的半圆甚至策略背后的意图是"在对圆形数字求和时最小化预期误差" .

维基百科关于四舍五入的页面有一节关于编程语言的舍入函数.

与.NET相比,JavaScript例如采用半向上舍入(Math.round(2.5)- > 3,Math.round(-2.5)- > -2) - 一种.NET甚至不提供的中点舍入模式.