C# 确定输入数字的十进制精度

C# 确定输入数字的十进制精度,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
输入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的答案。