我认为你应该按照你的建议去做 - 使用小数点的位置。明显的缺点可能是您必须自己考虑国际化。
var decimalSeparator = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator;
var position = input.IndexOf(decimalSeparator);
var precision = (position == -1) ? 0 : input.Length - position - 1;
// This may be quite unprecise.
var result = Math.Pow(0.1, precision);
您可以尝试另一件事 - Decimal 类型存储一个内部精度值。因此,您可以使用 Decimal.TryParse() 并检查返回值。也许解析算法保持了输入的精度。
最后我建议不要尝试使用浮点数。仅解析输入将删除有关尾随零的任何信息。所以你必须添加一个人为的非零数字来保存它们或做类似的把戏。您可能会遇到精度问题。最后根据浮点数找到精度也并不简单。我看到一些丑陋的数学或循环每次迭代都乘以十,直到不再有任何小数部分。并且循环带来了新的精度问题......
更新
解析成十进制有效。详情请咨询Decimal.GetBits()。
var input = "123.4560";
var number = Decimal.Parse(input);
// Will be 4.
var precision = (Decimal.GetBits(number)[3] >> 16) & 0x000000FF;
从这里使用Math.Pow(0.1, precision) 是直截了当的。
更新 2
使用 decimal.GetBits() 将分配一个 int[] 数组。如果您想避免分配,可以使用以下辅助方法,该方法使用显式布局结构直接从十进制值中获取比例:
static int GetScale(decimal d)
{
return new DecimalScale(d).Scale;
}
[StructLayout(LayoutKind.Explicit)]
struct DecimalScale
{
public DecimalScale(decimal value)
{
this = default;
this.d = value;
}
[FieldOffset(0)]
decimal d;
[FieldOffset(0)]
int flags;
public int Scale => (flags >> 16) & 0xff;
}