我们有一个有趣的问题是我们需要确定用户输入(文本框)的小数精度。本质上我们需要知道输入的小数位数,然后返回一个精度数,最好用例子来说明:
输入 4500 将产生结果 1
输入 4500.1 将产生结果 0.1
输入 4500.00 将产生结果 0.01
输入 4500.450 将产生结果 0.001
我们正在考虑使用字符串,找到小数点分隔符,然后计算结果。只是想知道是否有更简单的解决方案。
我们有一个有趣的问题是我们需要确定用户输入(文本框)的小数精度。本质上我们需要知道输入的小数位数,然后返回一个精度数,最好用例子来说明:
输入 4500 将产生结果 1
输入 4500.1 将产生结果 0.1
输入 4500.00 将产生结果 0.01
输入 4500.450 将产生结果 0.001
我们正在考虑使用字符串,找到小数点分隔符,然后计算结果。只是想知道是否有更简单的解决方案。
我认为你应该按照你的建议去做——使用小数点的位置。明显的缺点可能是您必须自己考虑国际化。
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;
}
只是想知道是否有更简单的解决方案。
不。
使用字符串:
string[] res = inputstring.Split('.');
int precision = res[1].Length;
由于您的最后一个示例表明尾随零很重要,因此我会排除任何数值解决方案并进行字符串操作。
不,没有更简单的解决方案,您必须检查字符串。如果将"4500"
和转换"4500.00"
为数字,它们都将成为值4500
,因此您无法判断小数分隔符后面有多少个非值数字。
有趣的是,Decimal
尝试保持用户输入的精度。例如,
Console.WriteLine(5.0m);
Console.WriteLine(5.00m);
Console.WriteLine(Decimal.Parse("5.0"));
Console.WriteLine(Decimal.Parse("5.00"));
具有以下输出:
5.0
5.00
5.0
5.00
如果您跟踪输入精度的动机纯粹是出于输入和输出原因,那么这可能足以解决您的问题。
这是使用字符串的可能解决方案;
static double GetPrecision(string s)
{
string[] splitNumber = s.Split('.');
if (splitNumber.Length > 1)
{
return 1 / Math.Pow(10, splitNumber[1].Length);
}
else
{
return 1;
}
}
这里有一个问题;计算 System.Decimal Precision 和 Scale,如果您想深入研究一下,这看起来可能很有趣。
使用字符串很容易。
如果没有“.” 在字符串中,返回 1。
否则返回“0.”,后跟 n-1 个“0”,后跟一个“1”,其中 n 是小数点后字符串的长度。