11

我们有一个有趣的问题是我们需要确定用户输入(文本框)的小数精度。本质上我们需要知道输入的小数位数,然后返回一个精度数,最好用例子来说明:

输入 4500 将产生结果 1
输入 4500.1 将产生结果 0.1
输入 4500.00 将产生结果 0.01
输入 4500.450 将产生结果 0.001

我们正在考虑使用字符串,找到小数点分隔符,然后计算结果。只是想知道是否有更简单的解决方案。

4

7 回答 7

19

我认为你应该按照你的建议去做——使用小数点的位置。明显的缺点可能是您必须自己考虑国际化。

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;
}
于 2010-07-19T14:25:42.403 回答
11

只是想知道是否有更简单的解决方案。

不。

使用字符串:

string[] res = inputstring.Split('.');
int precision = res[1].Length;
于 2010-07-19T14:24:28.853 回答
8

由于您的最后一个示例表明尾随零很重要,因此我会排除任何数值解决方案并进行字符串操作。

于 2010-07-19T14:20:26.983 回答
3

不,没有更简单的解决方案,您必须检查字符串。如果将"4500"和转换"4500.00"为数字,它们都将成为值4500,因此您无法判断小数分隔符后面有多少个非值数字。

于 2010-07-19T14:21:59.760 回答
2

有趣的是,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

如果您跟踪输入精度的动机纯粹是出于输入和输出原因,那么这可能足以解决您的问题。

于 2010-07-19T14:29:39.443 回答
1

这是使用字符串的可能解决方案;

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,如果您想深入研究一下,这看起来可能很有趣。

于 2010-07-19T14:34:54.923 回答
1

使用字符串很容易。

如果没有“.” 在字符串中,返回 1。

否则返回“0.”,后跟 n-1 个“0”,后跟一个“1”,其中 n 是小数点后字符串的长度。

于 2010-07-19T14:24:12.177 回答