在数学上确定十进制值的精度和比例

Jer*_*acs 7 .net c# math precision decimal

我一直在寻找某种方法来确定C#中十进制的比例和精度,这导致了几个SO问题,但它们似乎没有正确的答案,或者有误导性的标题(它们实际上是关于SQL服务器或一些其他数据库,而不是C#),或任何答案.我认为,以下帖子最接近我所追求的内容,但即便如此,这似乎也是错误的:

确定输入数字的小数精度

首先,似乎对规模和精度之间的差异存在一些混淆.每Google(根据MSDN):

精度是数字中的位数.Scale是数字中小数点右边的位数.

话虽如此,数字12345.67890M的标度为5,精度为10.我没有发现一个能够在C#中准确计算出来的单个代码示例.

我想制作两个辅助方法,decimal.Scale()并且decimal.Precision(),以便通过以下单元测试:

[TestMethod]
public void ScaleAndPrecisionTest()
{
    //arrange 
    var number = 12345.67890M;

    //act
    var scale = number.Scale();
    var precision = number.Precision();

    //assert
    Assert.IsTrue(precision == 10);
    Assert.IsTrue(scale == 5);
}
Run Code Online (Sandbox Code Playgroud)

但是我还没有找到一个可以做到这一点的代码片段,虽然有些人建议使用decimal.GetBits(),而其他人已经说过,将它转换为字符串并解析它.

在我看来,将它转换为字符串并解析它是一个糟糕的想法,甚至忽略了小数点的本地化问题.GetBits()然而,这种方法背后的数学对我来说就像希腊语.

任何人都可以描述用于确定decimalC#值的比例和精度的计算结果吗?

Rac*_*lan 5

这是使用GetBits()函数获得刻度的方式:

decimal x = 12345.67890M;
int[] bits = decimal.GetBits(x);
byte scale = (byte) ((bits[3] >> 16) & 0x7F); 
Run Code Online (Sandbox Code Playgroud)

我可以想到的获得精度的最佳方法是删除分数点(即,使用小数构造器在没有上述小数位的情况下重建小数),然后使用对数:

decimal x = 12345.67890M;
int[] bits = decimal.GetBits(x);
//We will use false for the sign (false =  positive), because we don't care about it.
//We will use 0 for the last argument instead of bits[3] to eliminate the fraction point.
decimal xx = new Decimal(bits[0], bits[1], bits[2], false, 0);
int precision = (int)Math.Floor(Math.Log10((double)xx)) + 1;
Run Code Online (Sandbox Code Playgroud)

现在我们可以将它们放入扩展中:

public static class Extensions{
    public static int GetScale(this decimal value){
    if(value == 0)
            return 0;
    int[] bits = decimal.GetBits(value);
    return (int) ((bits[3] >> 16) & 0x7F); 
    }

    public static int GetPrecision(this decimal value){
    if(value == 0)
        return 0;
    int[] bits = decimal.GetBits(value);
    //We will use false for the sign (false =  positive), because we don't care about it.
    //We will use 0 for the last argument instead of bits[3] to eliminate the fraction point.
    decimal d = new Decimal(bits[0], bits[1], bits[2], false, 0);
    return (int)Math.Floor(Math.Log10((double)d)) + 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个小提琴