为什么(双)0.6f> (双)(6 / 10F)?

时间:2010-09-20 04:49:46

标签: c#

这就是我的电脑上发生的事情:

(double)(float)0.6
= 0.60000002384185791

(double)0.6f
= 0.60000002384185791

(double)(6/10f)
= 0.6

(double)(float)(6/10f)
= 0.6
6 / 10f也是一个浮点数,怎么可以精确到0.6?
在我看来(双)(6 / 10f)也应该是0.60000002384185791。 有人可以帮忙解释一下吗?谢谢!

3 个答案:

答案 0 :(得分:5)

首先,重要的是要记住,0.6无法准确地表示为float,但 可以准确地表示为double(浮点运算的不准确性已有详细记载,如果不清楚为什么0.6无法准确表示为浮点数,请尝试this link

你看到上述行为的原因取决于编译器 - 如果你看一下反射器中编译的程序集,那么这里发生的事情会更清楚一些:

UPDATE 我已经更改了代码,因此它不使用Console.WriteLine,因为我意识到编译器正在为您选择一个重载,这使情况混淆了)< / p>

// As written in source
var j = (double)(float)0.6;
var k = (double)0.6f;
var l = (double)(6/10f);
var m = (double)(float)(6/10f);

// Code as seen by Reflector
double j = 0.60000002384185791;
double k = 0.60000002384185791;
double l = 0.6;
double m = 0.6;

为什么编译器选择以这种特殊的方式编译是超出我的(fyi,这都是关闭优化的)

其他一些有趣的案例:

// Code
var a = 0.6;
var b = (double)0.6;
var c = 0.6f;
var d = (float)0.6;

var e = 6 / 10;
var f = 6 / (10f);
var g = (float)(6 / 10);
var h = 6 / 10f;
var i = (double)6 / 10;
// Prints out 0.60000002384185791

double n = (float)0.6;
double o = f;

// As seen by Reflector
double a = 0.6;
double b = 0.6;
float c = 0.6f;
float d = 0.6f;

int e = 0;
float f = 0.6f;
float g = 0f;
float h = 0.6f;
double i = 0.6;

double n = 0.60000002384185791;
double o = f;

编译器似乎只是在几个特殊情况下执行上述技巧,为什么只有在转换为double时才能完成此操作呢?

其余的时间似乎做了一些诡计,使浮点运算似乎工作,实际上它通常不会。

答案 1 :(得分:2)

似乎是对结果进行四舍五入。您是否以精确的必要数字显示结果?您可以使用Jon Skeet的this c# class来获得打印结果的精确数字表示。

请注意,ToString()并不总是打印所有数字,Visual Studio调试器也不会打印。

答案 2 :(得分:1)

如果我是一个博彩人,我会说区别在于强制发生的地方。在后两个例子(6 / 10f的例子)中,有两个文字都是整数(整数6和浮点数10.00000000 ......)。这种划分似乎是在强制之后发生的,至少在你正在使用的编译器中。在前两个示例中,您有一个小数浮点数(0.6),它不能充分表示为浮点尾数内的二进制值。将该值强制为双倍不能修复已经造成的伤害。

在产生完全一致结果的环境中,除法在强制加倍之前发生(6将被强制转换为浮点以使除法与10相匹配,除法在浮动空间中进行,然后是结果被强制为双倍。)