ruby 版本 2.4.1
> 526.56.floor(2) => 526.55 >
应该输出 526.56
试了下,确实如此
这是一道送分题。应该复习大一《计算机基础》关于浮点数的相关章节。
你猜 0.2 + 0.7 等于几。
0.2 + 0.7
526.56 转换成二进制是: 1000001110.1000111101011100001010001111010111000010...
1000001110
10001111010111000010
小数部分 10001111010111000010 无限循环
因为 32 位 float 存不了那么多,只能存到小数点后 14 位,所以最后只有这个二进制保存下来: 1000001110.10001111010111
小数部分就成了 0.10001111010111,也就是 0.55999755859375
因此 526.56.floor(2) 等价于 526.55999755859375.floor(2)
结果 526.55 没毛病
526.56 也就是 1000001110.1000111101011100001010001111010111000010... 用二进制的科学记数法表示为 (小数点左移 9 位): (2^9) * 1.0000011101000111101011100001010001111010111000010...
2^9
1.000001110
float 存储的时候第一位是一个符号位,接下来 8 个是指数位,也就是 9,因为有效数的整数部分只能为 1,就不存了,只剩下 23 个存有效数 1 后面的小数部分,原整数 526 的信息除 1 以外是 000001110, 占了 9 位,只剩下 23 - 9 = 14 位存小数部分:
000001110
0
10001000
10001111010111
指数不是 9 吗,这是却是 10001000?因为指数有正负,一共 8 bits, 0~255,正负各 256/2=128,所以 指数 9 表示为 9 + 127 = 136,也就是 10001000
最后结果: 526.56 的浮点数是:01000100 00000011 10100011 11010111
526.56
01000100
00000011
10100011
11010111
老实说这种东西挺无聊的,有点像 Fixnum 和 Bignum,无聊的 implementation detail 一大堆,带来一些坑,可能还作为面试题目。然后 Ruby 2.4.0 就把 Fixnum 和 Bignum 合为 Integer 了。什么时候把 Float 和 BigDecimal 合二为一啊
总之,用 Float 做严格浮点数计算是不可靠的。如果要做精确使用浮点数计算,那就用 BigDecimal
这点 Java 做的好,没有Math.floor(Float f)方法,而有Math.floor(double d), 参考https://stackoverflow.com/questions/6060940/why-isnt-there-a-math-floorfloat
Math.floor(Float f)
Math.floor(double d)