sma*_*dan 5 powershell rounding
我很难弄清楚为什么有时两个舍入值相减会得到一个非舍入值。就像 2.2 - 1.1 = 1.10000001 一样。
我在 PowerShell 中有这样的脚本块:
foreach($disk in $disks)
{
$size = $disk.Size
$freespace = $disk.FreeSpace
$percentFree = [Math]::Round(($freespace / $size) * 100)
$sizeGB = [Math]::Round($size / 1073741824, 2)
$freeSpaceGB = [Math]::Round($freespace / 1073741824, 2)
$usedSpaceGB = $sizeGB - $freeSpaceGB
#view the variable values in every iteration
Write-Debug "`$size = $size"
Write-Debug "`$freespace = $freespace"
Write-Debug "`$percentFree = $percentFree%"
Write-Debug "`$sizeGB = $sizeGB"
Write-Debug "`$freeSpaceGB = $freeSpaceGB"
Write-Debug "`$usedSpaceGB = $usedSpaceGB"
}
Run Code Online (Sandbox Code Playgroud)
令人麻烦的部分是:
$usedSpaceGB = $sizeGB - $freeSpaceGB
Run Code Online (Sandbox Code Playgroud)
[Math]::Round() 方法似乎按预期工作,因为我可以看到存储在 $sizeGB 和 $freeSpaceGB 变量中的舍入值。以下是一些调试输出示例:
我将此数据导出到 HTML 文件,因此该表看起来很奇怪,因为该值未四舍五入:
现在我通过对减法结果进行舍入来“修复”这个问题,但我想知道为什么会发生这种情况。我希望有人能帮助我了解发生了什么事。
好吧,让我们尝试一下这个答案......
我假设$disks是实例的集合Win32_LogicalDisk,在这种情况下FreeSpace和Size属性是整数类型(具体来说,UInt64)。如果$disks包含其他类型,则这两个属性可能是某种整数,因为我们正在处理字节计数。
这与问题有点无关,但在这一行中......
$percentFree = [Math]::Round(($freespace / $size) * 100)
Run Code Online (Sandbox Code Playgroud)
...即使您正在调用四舍五入到最接近的整数的重载,$percentFree也会包含 a ,因为这是该方法的返回类型。您可以通过评估来检查这一点...DoubleMath.Round
$percentFree.GetType()
Run Code Online (Sandbox Code Playgroud)
如果您想要/期望$percentFree包含整数类型,那么您需要将其转换为一,如下所示......
$percentFree = [UInt64] [Math]::Round(($freespace / $size) * 100)
Run Code Online (Sandbox Code Playgroud)
当您使用Math.Round四舍五入到最接近的百位时,上述内容也适用......
$sizeGB = [Math]::Round($size / 1073741824, 2)
$freeSpaceGB = [Math]::Round($freespace / 1073741824, 2)
Run Code Online (Sandbox Code Playgroud)
...当然,因为该方法重载必须返回浮点类型,因为根据定义,整数类型无法存储值的小数部分。因此,$sizeGB和$freeSpaceGB包含浮点值(特别是Double),所以当这一行...
$usedSpaceGB = $sizeGB - $freeSpaceGB
Run Code Online (Sandbox Code Playgroud)
...被执行$usedSpaceGB还将包含 a Double,在这种情况下,只要它能够准确表示结果值,所有的赌注都将被关闭。
希望这能解释为什么会发生这种情况。至于如何改进代码,首先我建议不要对中间值进行任何舍入......
$sizeGB = $size / 1073741824
$freeSpaceGB = $freespace / 1073741824
$usedSpaceGB = [Math]::Round($sizeGB - $freeSpaceGB, 2)
Run Code Online (Sandbox Code Playgroud)
...可以更清楚、简洁地写为...
$sizeGB = $size / 1GB
$freeSpaceGB = $freespace / 1GB
$usedSpaceGB = [Math]::Round($sizeGB - $freeSpaceGB, 2)
Run Code Online (Sandbox Code Playgroud)
这不会消除您所看到的浮点近似值,但$usedSpaceGB会更接近实际值,因为您不是基于$sizeGB和的已舍入(会丢弃一些信息)值进行计算$freeSpaceGB。
在前面的代码片段中,$usedSpaceGB仍然是 a Double,因此它仍然有可能计算出某个无法准确表示的值。由于该值正在被格式化以供显示,否则必须序列化为string(作为 HTML)我会忘记Math.Round并让string格式化为您处理舍入,就像这样......
$usedSpaceGBText = (($size - $freeSpace) / 1GB).ToString('N2')
Run Code Online (Sandbox Code Playgroud)
...或这个...
$usedSpaceGBText = '{0:N2}' -f (($size - $freeSpace) / 1GB)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4870 次 |
| 最近记录: |