使用往返浮动到字符串

Posted

技术标签:

【中文标题】使用往返浮动到字符串【英文标题】:float to string using roundtrip 【发布时间】:2014-12-04 20:09:15 【问题描述】:

我正在尝试将浮点数转换为它的字符串表示形式,但结果不以科学记数法出现。

我第一次尝试:

ToString("0." + new string('#', 7))

但这似乎不适用于大值。例如:

float largeNumber = 12345678f;
string str = largeNumber.ToString("0." + new string('#', 7));

结果为@​​987654323@

然后我尝试了ToString("R")

这适用于上面的大数字,但如果数字太大,它会以科学计数法显示它们。例如5000000000f 的结果是"5E+09"。而像0.0005 这样的小数字会导致0.0004999999966

我也尝试过将 2 混合,但在某些情况下我仍然得到科学记数法。

我的测试程序粘贴在下面。我很欣赏会有精度问题,但我想知道我是否可以做得比我现有的更好?

class Program

    static void Main(string[] args)
    
        Write(0.123456789f);
        Write(0.12345678f);
        Write(0.1234567f);
        Write(0.123456f);
        Write(0.12345f);
        Write(0.1234f);
        Write(0.123f);
        Write(0.12f);
        Write(0.1f);
        Write(1);
        Write(12);
        Write(123);
        Write(1234);
        Write(12345);
        Write(123456);
        Write(1234567);
        Write(12345678);
        Write(123456789);

        Console.WriteLine();

        float f = 5000000000f;
        for (int i = 0; i < 17; ++i)
        
            Write(f);
            f /= 10;
        

        Console.WriteLine();

        f = 5000000000f;
        for (int i = 0; i < 17; ++i)
        
            Write(f < 1 ? f + 1 : f);
            f /= 10;
        

        Console.Read();
    

    static void Write(float f)
    
        //string str = f.ToString("0." + new string('#', 7));
        //string str = f.ToString("R");
        string str = Math.Abs(f) < 1 ? f.ToString("0." + new string('#', 7)) : f.ToString("R");

        Console.WriteLine(str);
    

【问题讨论】:

【参考方案1】:

问题是float 只支持 7 位精度。没有办法在浮点数中精确表示12345678f,因此它被转换为最接近的可表示浮点值,即12345680f。关键不是数字的大小,而是精度的位数。

另外,0.0005 不能准确地用二进制浮点数表示;最接近 0.0005 的 8 位二进制浮点数是 0.0004999999966

decimal 支持更高的精度,并且可以使用标准的 N 格式说明符精确地表示 base-10 数字。

【讨论】:

为什么 float f2 = 12345678f;字符串 str = f2.ToString("R");那么工作呢? @pastillman 在某些情况下可以进行(智能)舍入。所以 f2 仍然是 f2 的样子,但是它打印的东西有点圆。 根据我对往返的理解,ToString("R") 不应该进行任何舍入 试试123456789f - "R" 不会给你同样的号码 当然,但是 '12345678f' 可以,所以这不意味着它是可表示的吗?【参考方案2】:

试试这个:

largeNumber.ToString("r")

您可以在此处找到可用格式的列表: http://msdn.microsoft.com/en-us/library/dwhawy9k%28v=vs.110%29.aspx

【讨论】:

文档不鼓励使用 R 格式。 “对于 Double 和 Single 值,它的性能也相对较差”【参考方案3】:

格式字符串中的0不是零,它代表“非零数字,零零”,而“#”代表“非零数字,零零”。

对于大于零的数字,您可以使用 f.ToString("0." + new string('#', 7)) 格式

我刚刚在 PowerShell 中对其进行了测试,它对我来说很好,虽然它可能使用双精度或小数:

PS C:\> $test = "0:0.0######"
PS C:\> $test -f 0.5
0,5
PS C:\> $test -f 0.4443423
0,4443423
PS C:\> $test -f 123.4443423
123,4443423
PS C:\> $test -f 45425123.4443423
45425123,4443423

果然,问题好像出在floatprecision:

PS C:\> $test -f [float]45425123.4443423
45425120,0

【讨论】:

以上是关于使用往返浮动到字符串的主要内容,如果未能解决你的问题,请参考以下文章

从 EditText 到浮动的字符串

在 Golang 中以最小宽度浮动到字符串

获得只有 3 位小数和 +/- 符号的往返 Double

带有负浮动的字符串浮动? [复制]

使用 stringstream 浮动的字符串

Android 蓝牙 LE - 读取浮动特性