计算给定小数的比例

Count the scale of a given decimal

如何计算 Powershell 中给定小数的小数位数?

$a = 0.0001
$b = 0.000001

$a 转换为字符串并返回 $a.Length 结果为 6...我需要 4。

我以为会有小数或数学函数,但我没有找到它,而且乱用字符串似乎很不雅。

可能有更好的数学方法,但我会这样找到小数位:

$a = 0.0001
$decimalPlaces = ("$a" -split '\.')[-1].TrimEnd('0').Length

基本上,在 . 字符处拆分字符串并获取数组中最后一个字符串的长度。将 $a 包裹在双引号中隐式调用具有不变区域性的 .ToString()(您可以将其扩展为 $a.ToString([CultureInfo]::InvariantCulture)),使此方法确定小数位数区域性不变。

.TrimEnd('0') 用于万一 $a 来自字符串,而不是正确的数字类型,可能包含不应计为小数位的尾随零。但是,如果您想要 scale 而不仅仅是使用的小数位,请将 .TrimEnd('0') 关闭,如下所示:

$decimalPlaces = ("$a" -split '\.')[-1].Length

mclayton helpfully linked to 在评论中,那里的解决方案确实可以适应 PowerShell,如果使用或转换为类型 [decimal] 是可以接受的

# Define $a as a [decimal] literal (suffix 'd')
# This internally records the scale (number of decimal places) as specified.
$a = 0.0001d 

# [decimal]::GetBits() allows extraction of the scale from the
# the internal representation:
[decimal]::GetBits($a)[-1] -shr 16 -band 0xFF # -> 4, the number of decimal places

System.Decimal.GetBits method returns 一个内部位字段数组,其最后一个元素包含位 16 - 23 中的比例(8 位,即使允许的最大比例是28),也就是上面提取的内容。

注意:PowerShell 数字文字是小数 ,没有 d 后缀 - 例如,0.0001 成为 [double] 实例,即双精度二进制浮点数。

PowerShell 根据需要自动将 [double] 转换为 [decimal] 值,但请注意,由于内部表示不同,可能存在舍入误差,并且 [double] 可以存储更大的数字比 [decimal] 可以(虽然不准确)。

A [decimal] 文字 - 后缀 d (注意 C# 使用后缀 m) - 是 完全按照指定 的比例进行解析,因此将上述内容应用于 0.000d0.010d 在这两种情况下都会产生 3;也就是说,尾随零 有意义

如果您(隐含地)从 0.0000.010[double] 实例转换,这 适用,上面分别产生 02


基于字符串的解决方案

提供比 更简洁(也是文化不变的)替代方案:

$a = 0.0001
("$a" -replace '.+\.').Length # -> 4, the number of decimal places

警告:此解决方案依赖于 [double] 数字的 默认字符串表示形式 ,无需与原始数字匹配输入格式;例如,.0100,稍后字符串化时,变为 '0.01';但是,如上所述,如果以 [decimal] 文字开头,则可以保留尾随零:.0100d 字符串化为 '0.0100'(保留输入的小数位数)。

  • "$a",使用可扩展字符串(PowerShell 的字符串插值)创建文化不变 数字的字符串表示,以确保字符串表示使用.作为小数点。

    • 实际上,PowerShell 在幕后调用 $a.ToString([cultureinfo]::InvariantCulture)[1]

    • 相比之下,.ToString()(无参数)应用当前文化的规则,在某些文化中它是, - 不是 . - 用作小数点。

    • 警告:如果您只使用 $a 作为 -replace 的 LHS,$a 隐式 字符串化,在这种情况下,你 - 奇怪地 - 获得文化 - 敏感 行为,如 .ToString() - 见 this GitHub issue.

  • -replace '.+\.' 有效地从输入字符串中删除包括小数点在内的所有字符,并且 .Length 计算结果字符串中的字符 - 小数位数.


[1] 请注意,PowerShell 中来自字符串的 casts 也使用不变区域性(实际上,调用了 ::Parse($value, [cultureinfo]::InvariantCulture)),以便按顺序要解析 culture-local 字符串表示,您需要显式使用 ::Parse() 方法;例如,[double]::Parse('1,2'),而不是 [double] '1,2'