为什么以下程序会打印出打印的内容?
class Program
{
static void Main(string[] args)
{
float f1 = 0.09f*100f;
float f2 = 0.09f*99.999999f;
Console.WriteLine(f1 > f2);
}
}
输出
false
答案 0 :(得分:34)
浮点只有很多精度数字。如果你看到f1 == f2,那是因为任何差异都需要比32位浮点数更高的精度。
我建议阅读What Every Computer Scientist Should Read About Floating Point
答案 1 :(得分:5)
主要的是,这不仅仅是.Net:它是内存中underlying system most every language will use to represent a float的限制。精度只是到目前为止。
当你考虑到它甚至不是十号时,你也可以用相对简单的数字获得一些乐趣。例如,0.1是以二进制表示的重复小数。
答案 2 :(得分:4)
在这种特殊情况下,这是因为.09和.999999不能用二进制的精确精度表示(类似地,1/3不能用精确的十进制精度表示)。例如,0.111111111111111111101111 base 2为0.999998986721038818359375 base 10.将1添加到上一个二进制值,0.11111111111111111111 base 2为0.99999904632568359375 base 10.没有二进制值正好为0.999999。浮点精度也受分配用于存储指数的空间和尾数的小数部分的限制。此外,与整数类型一样,浮点可以溢出其范围,但其范围大于整数范围。
在Xcode调试器中运行这一段C ++代码,
float myFloat = 0.1;
显示myFloat的值为0.100000001。它被0.000000001关闭。不是很多,但如果计算有几个算术运算,那么不精确就会复杂化。
imho对浮点的一个非常好的解释是在计算机组织简介的第14章中使用x86-64汇编语言& GNU / Linux 由加州州立大学索诺玛分校的Bob Plantz(已退休)http://bob.cs.sonoma.edu/getting_book.html。以下是基于该章。浮点就像科学记数法,其中一个值存储为大于或等于1.0且小于2.0的混合数(尾数),乘以另一个数字到某个幂(指数)。浮点使用基数2而不是基数10,但在Plantz给出的简单模型中,为了清晰起见,他使用基数10。想象一个系统,其中两个存储位置用于尾数,一个位置用于指数的符号*(0代表+和1代表 - ),一个位置用于指数。现在加0.93和0.91。答案是1.8,而不是1.84。
9311代表0.93,或者说是-1的9.3倍。
9111代表0.91,或-1乘以9.1的9.1倍。
确切的答案是1.84,或者是0到1.84乘以10,如果我们有5个位置则是18400,但是,只有4个位置,答案是1800,或者是零到1.8或1.8的1.8倍。当然,浮点数据类型可以使用四个以上的存储位置,但位置数量仍然有限。
不仅精度受空间限制,而且“二进制中小数值的精确表示仅限于2的反幂之和。”(Plantz,op.cit。)。
0.11100110(二进制)= 0.89843750(十进制)
0.11100111(二进制)= 0.90234375(十进制)
二进制中没有精确的0.9十进制表示。即使把分数带到更多的地方也行不通,因为你在右边永远重复1100.
初学程序员经常看到浮点运算更多 精确比整数。确实,即使添加两个非常大 整数会导致溢出。乘法使其更有可能 结果将非常大,因此溢出。使用时 使用两个整数,C / C ++中的/运算符会导致小数部分 迷路了。但是,...浮点表示有自己的 一组不准确。 (Plantz,op.cit。)
*在浮点数中,表示数字的符号和指数的符号。