C# 确定输入数字的十进制精度
我们有一个有趣的问题,我们需要确定用户输入(文本框)的十进制精度。从本质上讲,我们需要知道输入的小数位数,然后返回一个精确的数字,下面的例子可以最好地说明这一点: 输入4500将产生结果1C# 确定输入数字的十进制精度,c#,decimal,precision,decimal-point,C#,Decimal,Precision,Decimal Point,我们有一个有趣的问题,我们需要确定用户输入(文本框)的十进制精度。从本质上讲,我们需要知道输入的小数位数,然后返回一个精确的数字,下面的例子可以最好地说明这一点: 输入4500将产生结果1 输入4500.1将产生0.1的结果 输入4500.00将产生0.01的结果 输入4500.450将产生结果0.001 我们正在考虑使用字符串,找到十进制分隔符,然后计算结果。只是想知道是否有一个更简单的解决方案。由于您最后的示例表明尾随的零是重要的,我将排除任何数值解,然后进行字符串操作。不,没有更简单的解决
输入4500.1将产生0.1的结果
输入4500.00将产生0.01的结果
输入4500.450将产生结果0.001
我们正在考虑使用字符串,找到十进制分隔符,然后计算结果。只是想知道是否有一个更简单的解决方案。由于您最后的示例表明尾随的零是重要的,我将排除任何数值解,然后进行字符串操作。不,没有更简单的解决方案,您必须检查字符串。如果将
“4500”
和“4500.00”
转换为数字,它们都将成为值4500
,因此您无法判断小数分隔符后面有多少非值数字。处理字符串非常简单
如果字符串中没有“.”,则返回1
否则返回“0”,后跟n-1“0”,后跟一个“1”,其中n是小数点后字符串的长度
只是想知道是否有更简单的方法
这个问题的解决办法
没有
使用字符串:
string[] res = inputstring.Split('.');
int precision = res[1].Length;
我认为你应该按照你的建议去做——使用小数点的位置。明显的缺点可能是您必须自己考虑国际化
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()
并检查返回值。也许解析算法保持了输入的精度
最后,我建议不要尝试使用浮点数。仅解析输入将删除有关尾随零的任何信息。因此,您必须添加一个人工非零数字来保存它们或执行类似的操作。您可能会遇到精度问题。最后,基于浮点数求精度也不简单。我看到一些难看的数学或循环每次迭代乘以10,直到不再有任何分数部分。循环带来了新的精度问题
更新
解析成十进制是有效的。详情请参阅
var input = "123.4560";
var number = Decimal.Parse(input);
// Will be 4.
var precision = (Decimal.GetBits(number)[3] >> 16) & 0x000000FF;
从这里开始使用Math.Pow(0.1,精度)
是直截了当的
更新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;
}
有趣的是,
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;
}
}
这里有一个问题;如果您想进一步深入研究,您可能会对此感兴趣。警告:首先确保字符串是有效的数字/最后一个字符不是“.”。要拆分的字符需要是正确的小数分隔符-+1表示小数。精度,我不知道它可以做到:)请参阅,因为OP要求“更简单的解决方案”,也许推断“性能更好”,这与仅仅解析字符串相比性能如何?您在注释中有“将是4”,但“123.4560”的精度应该是7。刻度应该是4。123.4560的精度是否为3?既然最后的0不应该算?你确定4500是1,而不是100吗?在0.0和0.1的情况下,预期的结果是什么?对我来说,这是一个令人困惑的问题。您不要求小数精度。你会问:如何得到分数部分的位数。“十进制精度”的定义就在这里:您需要使用它来获取区域设置的正确十进制分隔符。有关如何直接访问此信息,请参阅Daniel Bruckner的答案。