截断双倍到x有效数字

时间:2016-08-27 03:30:55

标签: c#

我很乐意使用@P Daddy发布的截断扩展方法:https://stackoverflow.com/a/374470/4123190

static double TruncateToSignificantDigits(this double d, int digits){
    if(d == 0)
        return 0;

    double scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(d))) + 1 - digits);
    return scale * Math.Truncate(d / scale);
}

这大部分按预期工作但我遇到了失败的情况,999999999999999到3位数给出了990000000000000.这是一个表示失败的小提琴:https://dotnetfiddle.net/4tN7nv

对于我的特定用例,我需要使用双打,并且需要使用它们提供的全部范围。虽然失败案例看起来是由某些浮点怪异引起的,但显然有可能将数字转换为截断版本,因为将其转换为字符串,截断它,然后将其转换回double将保持预期结果。

如何改善这一点以适应所有双打?

2 个答案:

答案 0 :(得分:0)

行。我发现它是各种数学函数准确性的一个问题,所以当我意识到我们可以通过使用字符串输入而不是双重来避免这些问题时,我正在用一堆复杂的方法解决问题。输入。输出仍然是两倍 - 只有输入已更改为字符串。所以你可以使用value.ToString()。

来调用函数

请注意,这最多只能产生9位精度。我认为这是绰绰有余,因为你在谈论截断到三位数。如果您需要超过九位数,请告诉我,我会回到绘图板(这是可能的)。

以下是修改后的方法:

public void testTruncate()
    {

        for (int i = 3; i < 1000; i++)
        {
            string testNumber = "";
            if (Math.Log10(Math.Pow(10, i)) > 9)
            {
                testNumber = (Math.Pow(10, i) / Math.Pow(10, i - 9) - 1).ToString();
                for (int d = 0; d < Math.Log10(Math.Pow(10, i)) - testNumber.Length; d++)
                {
                    testNumber += "0";
                }
                if (double.Parse(testNumber) > double.MaxValue)
                {
                    break;
                }
            }
            else
            {
                 testNumber = (Math.Pow(10, i) - 1).ToString();
            }
          Console.WriteLine(testNumber+" truncated to "+  doTruncate(testNumber, 3, true).ToString("N0")+"\n");
        }
    }
    public double doTruncate(string bigNumString, double numberOfDigitsToTruncateTo, bool addZeroesBack)
    {
        if (bigNumString.Length <= numberOfDigitsToTruncateTo)
        {
            return double.Parse(bigNumString);
        }
        string ret = bigNumString.Substring(0,(int)numberOfDigitsToTruncateTo);
        if (addZeroesBack)
        {
            for (int i = 0; i < bigNumString.Length - numberOfDigitsToTruncateTo; i++)
            {
                ret += "0";
            }
        }
        double answer = double.Parse(ret);
        if (answer > double.MaxValue)
        {
            return -1;//value too large 
        }
        return answer;

    }

以下是testTruncate从999到double的限制的结果.MaxValue

999截断为999

9999被截断为9,990

99999截断为99,900

999999截断为999,000

9999999截断为9,990,000

99999999截断为99,900,000

999999999截断为999,000,000

9999999990截断至9,990,000,000

9999999990截断至9,990,000,000

99999999900截断为99,900,000,000

99999999900截断为99,900,000,000

999999999000截断为999,000,000,000

999999999000截断为999,000,000,000

9999999990000截断为9,990,000,000,000

9999999990000截断为9,990,000,000,000

99999999900000截断为99,900,000,000,000

99999999900000截断为99,900,000,000,000

999999999000000截断为999,000,000,000,000

999999999000000截断为999,000,000,000,000

9999999990000000截断为9,990,000,000,000,000

9999999990000000截断为9,990,000,000,000,000

99999999900000000截断为99,900,000,000,000,000

99999999900000000截断为99,900,000,000,000,000

999999999000000000截断为999,000,000,000,000,000

999999999000000000截断为999,000,000,000,000,000

9999999990000000000截断为9,990,000,000,000,000,000

9999999990000000000截断为9,990,000,000,000,000,000

99999999900000000000截断为99,900,000,000,000,000,000

99999999900000000000截断为99,900,000,000,000,000,000

999999999000000000000截断为999,000,000,000,000,000,000

999999999000000000000截断为999,000,000,000,000,000,000

9999999990000000000000截断为9,990,000,000,000,000,000,000

9999999990000000000000截断为9,990,000,000,000,000,000,000

99999999900000000000000截断为99,900,000,000,000,000,000,000

99999999900000000000000截断为99,900,000,000,000,000,000,000

...等等...... 9999999990000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000截断至999,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000

答案 1 :(得分:0)

Imho,你根本不应该这样做,因为平点数表示的性质。如果你需要四舍五入才能在UI中显示,那么你就拥有了很好的内置ToString功能,可以为你提供精确的功能。如果需要近似地比较两个数字,则可以将有效数字字段中的两个数字和舍入位标准化。