Powershell 添加不需要的小数(加法)
Powershell adding unwanted decimals (addition)
我正在我的一个脚本中做一些添加,这里是一些简化的代码:
foreach($entry in $arr){
...
switch($entry.AccessRights)
{
"GenericRead" {$score = 1}
"GenericWrite" {$score = 2}
"GenericAll" {$score = 3}
default {$score = 0.1}
}
$users | where {$_.username -eq $entry.username} | % {$_.aclscore+=$score}
}
你会期望输出是 123.5 之类的东西。但是在两者之间的某个点(当分数为 0.1 时)它会偏离 0.0000000000001 正负,所以我可能会得到像 66,1000000000001 甚至 84,8999999999999 这样的结果。
问题 1:为什么?
问题 2:除了四舍五入之外,我还能做些什么来解决这个问题?
在测试中,PowerShell 将变量的数据类型隐式转换为 [double]
。相反,显式转换为 [decimal]
- 双精度数据类型可以容纳范围广泛的值,但会牺牲精确度。
- 十进制使用更多的内存(12 字节与双精度中的 8 字节相反)并且值的范围更小但保留精度。
这绝不是深入比较;我建议您阅读 this table of datatypes 并在线查找更完整的解释,因为这是非常基础的并且与语言无关。
代码
foreach($entry in $arr){
...
switch($entry.AccessRights)
{
"GenericRead" {[decimal]$score = 1}
"GenericWrite" {[decimal]$score = 2}
"GenericAll" {[decimal]$score = 3}
default {[decimal]$score = 0.1}
}
$users | where {$_.username -eq $entry.username} | % {$_.aclscore+=$score}
}
编辑 - 进一步说明
double数据类型不精确的原因是binary存储的是数字,有些数字不能用二进制精确表示
Walter Mitty 的评论提供了一个很好的例子 1/3
,这个数字无法使用有限的十进制数字或二进制数字精确表示:
1/3 = 0.333333333..... [decimal]
1/3 = 0.010101010..... [binary]
同理,小数1/10
cannot be expressed exactly in binary。而它可以是十进制。
1/10 = 0.1 [decimal]
1/10 = 0.000110011.... [binary]
我正在我的一个脚本中做一些添加,这里是一些简化的代码:
foreach($entry in $arr){
...
switch($entry.AccessRights)
{
"GenericRead" {$score = 1}
"GenericWrite" {$score = 2}
"GenericAll" {$score = 3}
default {$score = 0.1}
}
$users | where {$_.username -eq $entry.username} | % {$_.aclscore+=$score}
}
你会期望输出是 123.5 之类的东西。但是在两者之间的某个点(当分数为 0.1 时)它会偏离 0.0000000000001 正负,所以我可能会得到像 66,1000000000001 甚至 84,8999999999999 这样的结果。
问题 1:为什么?
问题 2:除了四舍五入之外,我还能做些什么来解决这个问题?
在测试中,PowerShell 将变量的数据类型隐式转换为 [double]
。相反,显式转换为 [decimal]
- 双精度数据类型可以容纳范围广泛的值,但会牺牲精确度。
- 十进制使用更多的内存(12 字节与双精度中的 8 字节相反)并且值的范围更小但保留精度。
这绝不是深入比较;我建议您阅读 this table of datatypes 并在线查找更完整的解释,因为这是非常基础的并且与语言无关。
代码
foreach($entry in $arr){
...
switch($entry.AccessRights)
{
"GenericRead" {[decimal]$score = 1}
"GenericWrite" {[decimal]$score = 2}
"GenericAll" {[decimal]$score = 3}
default {[decimal]$score = 0.1}
}
$users | where {$_.username -eq $entry.username} | % {$_.aclscore+=$score}
}
编辑 - 进一步说明
double数据类型不精确的原因是binary存储的是数字,有些数字不能用二进制精确表示
Walter Mitty 的评论提供了一个很好的例子 1/3
,这个数字无法使用有限的十进制数字或二进制数字精确表示:
1/3 = 0.333333333..... [decimal]
1/3 = 0.010101010..... [binary]
同理,小数1/10
cannot be expressed exactly in binary。而它可以是十进制。
1/10 = 0.1 [decimal]
1/10 = 0.000110011.... [binary]