using System; class Test { static void Main() { double f = Sum (0.1d, 0.2d); double g = 0.3d; Console.WriteLine (f); Console.WriteLine (f==g); } static double Sum (double f1, double f2) { return f1+f2; } }
我们编译并且运行这段代码,可以看到输出了如下的内容:
比较这两个小数的结果并不是true,这和我们的预期并不一样。
浮点数的真模样我们知道,像上文中的那个二进制小数1110.1101事实上也是按照人类习惯表达出来的,但是计算机可是不能识别这种带小数点的东西的哦。所以计算机会使用之前介绍的数字格式来表示这样一个数字,那么一个二进制浮点数在计算机中到底是如何表现的呢?其实在上文介绍数字格式的部分已经介绍过了,但是没有实际看一眼终究是不能有一个直观的认识,那在本文的最后,我们就来看一个二进制浮点数的在计算机中真实的样子。
0100000001000111101101101101001001001000010101110011000100100011
这是一个64位的二进制数。如果把它作为一个双精度浮点数,那么它的各部分都分别表示了什么呢?
按照上文介绍浮点数的部分,我们可以将它分成如下几部分:
符号:0
指数部分:10000000100(二进制,可以转换为十进制的1028)
尾数部分:0111101101101101001001001000010101110011000100100011
因此,将它转换为一个用二进制表示的小数,则是:
(-1)^0 * 1.0111101101101101001001001000010101110011000100100011 x 2^(1028-1023)
= 1.0111101101101101001001001000010101110011000100100011 x 2^5
= 101111.01101101101001001001000010101110011000100100011
如果各位读者观察足够仔细的话,是否发现了有趣的一点呢?那就是在这个在计算机中用来表示双精度浮点数的64位数中,尾数部分的几位数字是:0111101101101101001001001000010101110011000100100011
但是经过从计算机中的形式转化成人类使用二进制表示小数的形式之后,数字却变成了1.0111101101101101001001001000010101110011000100100011x 2^5,小数点之前为什么会多出了一个1呢?
这是因为在尾数部分,为了将表现形式多样的浮点数统一为同一种表示方式而规定要将小数点前的值固定为1。由于小数点前的数永远是1,因此为了节省一个数据位,这个1在计算机中并不需要被保存。
那么应该如何保证一个二进制小数的小数点前的值是1呢?这就需要对二进制小数进行逻辑移位了,通过左移或右移若干次后,将整数部分变为1。例如上文中的这个二进制小数:1110.1101,我们就来试试如何把它变成计算机可以识别的浮点数的尾数吧。
1110.1101(原始数据)——>0001.1101101(通过右移将整数部分变为1)——>0001.11011010000000000000....(拓展位数,使之符合数字格式的规定)——>11011010000000000000....(去掉整数部分,仅保留小数部分)
好了,到此关于C#或者计算机中的小数计算就写得差不多了。欢迎各位交流。