Double to string conversion without scientific notation

前端 未结 17 1470
無奈伤痛
無奈伤痛 2020-11-22 15:33

How to convert a double into a floating-point string representation without scientific notation in the .NET Framework?

\"Small\" samples (effective numbers may be of

17条回答
  •  旧时难觅i
    2020-11-22 16:02

    The problem using #.###...### or F99 is that it doesn't preserve precision at the ending decimal places, e.g:

    String t1 = (0.0001/7).ToString("0." + new string('#', 339)); // 0.0000142857142857143
    String t2 = (0.0001/7).ToString("r");                         //      1.4285714285714287E-05
    

    The problem with DecimalConverter.cs is that it is slow. This code is the same idea as Sasik's answer, but twice as fast. Unit test method at bottom.

    public static class RoundTrip {
    
        private static String[] zeros = new String[1000];
    
        static RoundTrip() {
            for (int i = 0; i < zeros.Length; i++) {
                zeros[i] = new String('0', i);
            }
        }
    
        private static String ToRoundTrip(double value) {
            String str = value.ToString("r");
            int x = str.IndexOf('E');
            if (x < 0) return str;
    
            int x1 = x + 1;
            String exp = str.Substring(x1, str.Length - x1);
            int e = int.Parse(exp);
    
            String s = null;
            int numDecimals = 0;
            if (value < 0) {
                int len = x - 3;
                if (e >= 0) {
                    if (len > 0) {
                        s = str.Substring(0, 2) + str.Substring(3, len);
                        numDecimals = len;
                    }
                    else
                        s = str.Substring(0, 2);
                }
                else {
                    // remove the leading minus sign
                    if (len > 0) {
                        s = str.Substring(1, 1) + str.Substring(3, len);
                        numDecimals = len;
                    }
                    else
                        s = str.Substring(1, 1);
                }
            }
            else {
                int len = x - 2;
                if (len > 0) {
                    s = str[0] + str.Substring(2, len);
                    numDecimals = len;
                }
                else
                    s = str[0].ToString();
            }
    
            if (e >= 0) {
                e = e - numDecimals;
                String z = (e < zeros.Length ? zeros[e] : new String('0', e));
                s = s + z;
            }
            else {
                e = (-e - 1);
                String z = (e < zeros.Length ? zeros[e] : new String('0', e));
                if (value < 0)
                    s = "-0." + z + s;
                else
                    s = "0." + z + s;
            }
    
            return s;
        }
    
        private static void RoundTripUnitTest() {
            StringBuilder sb33 = new StringBuilder();
            double[] values = new [] { 123450000000000000.0, 1.0 / 7, 10000000000.0/7, 100000000000000000.0/7, 0.001/7, 0.0001/7, 100000000000000000.0, 0.00000000001,
             1.23e-2, 1.234e-5, 1.2345E-10, 1.23456E-20, 5E-20, 1.23E+2, 1.234e5, 1.2345E10, -7.576E-05, 1.23456e20, 5e+20, 9.1093822E-31, 5.9736e24, double.Epsilon };
    
            foreach (int sign in new [] { 1, -1 }) {
                foreach (double val in values) {
                    double val2 = sign * val;
                    String s1 = val2.ToString("r");
                    String s2 = ToRoundTrip(val2);
    
                    double val2_ = double.Parse(s2);
                    double diff = Math.Abs(val2 - val2_);
                    if (diff != 0) {
                        throw new Exception("Value {0} did not pass ToRoundTrip.".Format2(val.ToString("r")));
                    }
                    sb33.AppendLine(s1);
                    sb33.AppendLine(s2);
                    sb33.AppendLine();
                }
            }
        }
    }
    

提交回复
热议问题