这是C#SqlDecimal算术错误吗?

我正在尝试实现SQL Server Vardecimal解压缩.值每10位存储为3位十进制数.但在实施过程中,我发现数学的奇怪行为.这是我做的简单测试private SqlDecimal Test() {SqlDecimal mantissa = 0;SqlDecimal sign = -1;byte e...

我正在尝试实现SQL Server Vardecimal解压缩.值每10位存储为3位十进制数.但在实施过程中,我发现数学的奇怪行为.这是我做的简单测试

private SqlDecimal Test() {

  SqlDecimal mantissa = 0;
  SqlDecimal sign = -1;
  byte exponent = 0x20;
  int numDigits = 0;

  // -999999999999999999999999999999999.99999

  for (int i = 0; i < 13; i++) {

    int temp = 999;

    //equal to mantissa = mantissa * 1000 + temp;
    numDigits += 3;
    int pwr = exponent - (numDigits - 1);
    mantissa += temp * (SqlDecimal)Math.Pow(10, pwr);
  }

  return sign * mantissa;
}

前两次传球很好,我有

999000000000000000000000000000000
999999000000000000000000000000000

但第三个

999999998999999999999980020000000

是C#SqlDecimal数学中的一些错误还是我做错了什么?

解决方法:

这是您如何构建要在此处添加的值的问题:

mantissa += temp * (SqlDecimal)Math.Pow(10, pwr);

当pwr为24时,问题就出现了.你可以在这里看得很清楚:

Console.WriteLine((SqlDecimal) Math.Pow(10, 24));

我的盒子上的输出是:

999999999999999980000000

现在我不确切知道它来自哪里 – 但最简单的是完全删除浮点运算.虽然它可能效率不高,但这是一种避免问题的简单方法:

static SqlDecimal PowerOfTen(int power)
{
    // Note: only works for non-negative power values at the moment!
    // (To handle negative input, divide by 10 on each iteration instead.)
    SqlDecimal result = 1;
    for (int i = 0; i < power; i++)
    {
        result = result * 10;
    }
    return result;
}

如果您然后将行更改为:

mantissa += temp * PowerOfTen(pwr);

然后你会得到你期望的结果 – 至少当pwr大于零时.虽然应该很容易修复PowerOfTen来处理负值.

本文标题为:这是C#SqlDecimal算术错误吗?

基础教程推荐