我很难弄清楚为什么有时两个舍入值的减法会给我一个非舍入值。就像如果 2.2 - 1.1 = 1.10000001。
我在 PowerShell 中有这个脚本 block :
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"
}
令人不安的部分是:
$usedSpaceGB = $sizeGB - $freeSpaceGB
[Math]::Round() 方法似乎按预期工作,因为我可以看到存储在 $sizeGB 和 $freeSpaceGB 变量中的舍入值。以下是一些调试输出示例:
我将这些数据导出到一个 HTML 文件中,因此表格看起来很奇怪,这些值没有四舍五入:
现在我通过舍入也“修复”了减法结果,但我想知道为什么会这样。我希望有人可以帮助我了解发生了什么。
最佳答案
好吧,让我们试试这个作为答案......
我假设 $disks
是 Win32_LogicalDisk
的集合实例,在这种情况下 FreeSpace
和 Size
属性是整数类型(特别是 UInt64
)。如果 $disks
包含一些其他类型,这两个属性可能是某种整数,因为我们正在处理字节数。
这与这个问题有些无关,但在这一行中......
$percentFree = [Math]::Round(($freespace / $size) * 100)
...
$percentFree
将包含 Double
即使你调用 the Math.Round
overload that rounds to the nearest integer因为那是该方法的返回类型。您可以通过评估来检查...$percentFree.GetType()
如果你想要/期待
$percentFree
要包含一个整数类型,那么你需要将它转换为一个,就像这样......$percentFree = [UInt64] [Math]::Round(($freespace / $size) * 100)
当您使用
Math.Round
时,上述内容也适用。四舍五入到最接近的百分之一...$sizeGB = [Math]::Round($size / 1073741824, 2)
$freeSpaceGB = [Math]::Round($freespace / 1073741824, 2)
...因为,当然,该方法重载必须返回浮点类型,因为根据定义,整数类型不能存储值的小数部分。因此,
$sizeGB
和 $freeSpaceGB
包含浮点值(特别是 Double
)所以当这条线......$usedSpaceGB = $sizeGB - $freeSpaceGB
...被执行
$usedSpaceGB
还将包含 Double
, 在这种情况下,所有赌注都被取消 being able to exactly represent the resulting value .希望这能解释为什么会发生这种情况。至于如何改进您的代码,首先我建议不要对中间值进行任何舍入......
$sizeGB = $size / 1073741824
$freeSpaceGB = $freespace / 1073741824
$usedSpaceGB = [Math]::Round($sizeGB - $freeSpaceGB, 2)
...可以更清晰简洁地写成...
$sizeGB = $size / 1GB
$freeSpaceGB = $freespace / 1GB
$usedSpaceGB = [Math]::Round($sizeGB - $freeSpaceGB, 2)
这不会像您看到的那样消除浮点近似,但是
$usedSpaceGB
将更接近实际值,因为您没有根据 $sizeGB
的已舍入(丢弃一些信息)值进行计算和 $freeSpaceGB
.在前面的片段中,
$usedSpaceGB
仍然是 Double
所以它仍然有可能计算到一些无法准确表示的值。由于该值正在格式化以供显示,否则必须序列化为 string
(作为 HTML)我会忘记 Math.Round
让 string
formatting像这样为你处理四舍五入...$usedSpaceGBText = (($size - $freeSpace) / 1GB).ToString('N2')
...或这个...
$usedSpaceGBText = '{0:N2}' -f (($size - $freeSpace) / 1GB)
关于PowerShell [Math]::Round 有时不舍入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46286675/