将 float 转换为 double 会丢失精度 C# [英] Converting float to double loses precision C#

查看:96
本文介绍了将 float 转换为 double 会丢失精度 C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码

    double temp3 = 61.01;

    //This can actually be various other types, but float is the one that causes problems
    dynamic temp = 61.01f;
    double temp2 = (double)Convert.ChangeType(temp, typeof(double));

    double newValue = temp2 - temp3;

    //newValue should == 0 but it does not

    Console.WriteLine(String.Format("  {0:F20}", temp));
    Console.WriteLine(String.Format("  {0:F20}", temp2));
    Console.WriteLine(String.Format("  {0:F20}", temp3));
    Console.WriteLine(String.Format("  {0:F20}", newValue));

产生什么

61.01000000000000000000

61.01000000000000000000

61.00999832153320000000

61.00999832153320000000

61.01000000000000000000

61.01000000000000000000

-0.00000167846679488548

-0.00000167846679488548

为什么 Convert.ChangeType 失去精度?

Why is Convert.ChangeType losing precision?

我们使用 Convert.ChangeType 是因为使用了一个动态变量,可以是 byte/uint/float/double 等

We are using Convert.ChangeType because of the use of a dynamic variable which can be byte/uint/float/double etc

推荐答案

这个问题中观察到的问题主要是由于 Microsoft 的格式选择引起的,特别是 Microsoft 软件无法显示确切值,因为它限制了使用的位数即使格式字符串需要更多数字,也可以转换为十进制.此外,它在转换 float 时使用的位数比转换 double 时少.因此,如果格式化具有相同值的 floatdouble,结果可能会有所不同,因为 float 格式将使用较少的有效数字.

The issue observed in this question is caused largely by Microsoft’s choice of formatting, notably that Microsoft software fails to show the exact values because it limits the number of digits used to convert to decimal even when the format string requests more digits. Furthermore, it uses fewer digits when converting float than when converting double. Thus, if a float and double with the same value are formatted, the results may be different because the float formatting will use fewer significant digits.

下面,我将问题中的代码语句一一梳理一遍.综上所述,问题的关键在于值 61.0099983215332 为 float 时格式为61.0100000000000",double 时格式为61.0099983215332".这纯粹是微软的格式选择,并不是浮点运算的性质造成的.

Below, I go through the code statements in the question one by one. In summary, the crux of the matter is that the value 61.0099983215332 is formatted as "61.0100000000000" when it is a float and "61.0099983215332" when it is a double. This is purely Microsoft’s choice of formatting and is not caused by the nature of floating-point arithmetic.

语句 double temp3 = 61.01temp3 初始化为 61.00999999999999801048033987171947956085205078125.由于二进制浮点格式的性质,对 61.01 的这种更改是必要的——它不能准确表示 61.01,因此使用 double 中可表示的最接近的值.

The statement double temp3 = 61.01 initializes temp3 to exactly 61.00999999999999801048033987171947956085205078125. This change from 61.01 is necessary due to the nature of a binary floating-point format—it cannot represent exactly 61.01, so the nearest value representable in double is used.

语句 dynamic temp = 61.01ftemp 初始化为 61.009998321533203125.与 double 一样,使用了最近的可表示值,但是,由于 float 的精度较低,最近的值不像 double案例.

The statement dynamic temp = 61.01f initializes temp to exactly 61.009998321533203125. As with double, the nearest representable value has been used, but, since float has less precision, the nearest value is not as close as in the double case.

语句 double temp2 = (double)Convert.ChangeType(temp, typeof(double));temp 转换为 doubletemp 具有相同的值,因此它的值为 61.009998321533203125.

The statement double temp2 = (double)Convert.ChangeType(temp, typeof(double)); converts temp to a double that has the same value as temp, so it has the value 61.009998321533203125.

语句 double newValue = temp2 - temp3; 正确地将两个值相减,得到准确结果 0.00000167846679488548033987171947956085205078125,没有错误.

The statement double newValue = temp2 - temp3; correctly subtracts the two values, producing the exact result 0.00000167846679488548033987171947956085205078125, with no error.

语句Console.WriteLine(String.Format(" {0:F20}", temp));格式化名为tempfloat>.格式化 float 涉及调用 Single.ToString.微软的文档有点含糊.它说,默认情况下,只返回七位(十进制)精度的数字.它说使用 GR 格式最多可达九个,而 F20 既不使用 G 也不使用 R.所以我相信只使用了七位数字.当 61.009998321533203125 四舍五入为七位有效十进制数字时,结果为61.01000".ToString 方法然后将其填充到小数点后的 20 位,产生61.01000000000000000000".

The statement Console.WriteLine(String.Format(" {0:F20}", temp)); formats the float named temp. Formatting a float involves callling Single.ToString. Microsoft‘s documentation is a bit vague. It says that, by default, only seven (decimal) digits of precision are returned. It says to use G or R formats to get up to nine, and F20 uses neither G nor R. So I believe only seven digits are used. When 61.009998321533203125 is rounded to seven significant decimal digits, the result is "61.01000". The ToString method then pads this to twenty digits after the decimal point, producing "61.01000000000000000000".

接下来我将处理您的第三个 WriteLine 语句,然后再回到第二个.

I will address your third WriteLine statement next and come back to the second one afterward.

语句Console.WriteLine(String.Format(" {0:F20}", temp3));格式化名为temp3double>.由于 temp3doubleDouble.ToString 被调用.此方法使用 15 位精度(除非使用了 GR).61.0099999999999801048033987171947956085205078125四舍五入为15位有效十进制数字时,结果为61.0100000000000".ToString 方法然后将其填充到小数点后的 20 位,产生61.01000000000000000000".

The statement Console.WriteLine(String.Format(" {0:F20}", temp3)); formats the double named temp3. Since temp3 is a double, Double.ToString is called. This method uses 15 digits of precision (unless G orR are used). When 61.00999999999999801048033987171947956085205078125 is rounded to 15 significant decimal digits, the result is "61.0100000000000". The ToString method then pads this to twenty digits after the decimal point, producing "61.01000000000000000000".

语句Console.WriteLine(String.Format(" {0:F20}", temp2));格式化名为temp2double>.temp2 是一个 double,它包含来自 float temp 的值,所以它包含 61.009998321533203125.将其转换为 15 位有效十进制数字时,结果为61.0099983215332".ToString 方法然后将其填充到小数点后的 20 位,产生61.00999832153320000000".

The statement Console.WriteLine(String.Format(" {0:F20}", temp2)); formats the double named temp2. temp2 is a double that contains the value from the float temp, so it contains 61.009998321533203125. When this is converted to 15 significant decimal digits, the result is "61.0099983215332". The ToString method then pads this to twenty digits after the decimal point, producing "61.00999832153320000000".

最后,语句 Console.WriteLine(String.Format(" {0:F20}", newValue)); 格式化 newValue.将 .00000167846679488548033987171947956085205078125 格式化为 15 位有效数字会产生0.00000167846679488548".

Finally, the statement Console.WriteLine(String.Format(" {0:F20}", newValue)); formats newValue. Formatting .00000167846679488548033987171947956085205078125 to 15 significant digits produces "0.00000167846679488548".

这篇关于将 float 转换为 double 会丢失精度 C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆