妈,旧电脑连加法都算错了,我要换新的

简介: 妈,旧电脑连加法都算错了,我要换新的

妈妈,我的电脑连加法都算错了

垃圾电脑,连一个加法都算不对

小朱: 怎么给儿子换电脑了,我那旧电脑她不想嘛。
小仙女: 你也知道旧电脑,连个加法都算不对,你好意思。
小朱: 纳尼,什么加法算不对。

示例

public static void main(String[] args) {
    float f = 2000000000f;
    System.out.println((f + 50f) == f);
}

小仙女: 虽然我没学过,但是没吃过猪肉,没见过猪跑吗?肯定是false啊。但是得到的竟然是true
小朱: 😯,那你新电脑试过了吗?
小仙女: 那还用试吗,肯定没问题,我试下好了。
......
小仙女: 走,和我一起找他们理论去,垃圾电脑,毁我儿子。
小朱: ......

各位,你们的电脑是不是也出问题了。😄😄😄

解析

我们先来了解计算机怎么存储float的数据
float的存储正是将4字节32位划分为了3部分来分别存储正负号,指数部分,小数部分

  • 1.Sign(1位): 用来表示浮点数是正数还是负数,0表示正数,1表示负数。
  • 2.Exponent(8位): 指数部分。为了同时表示正负指数以及他们的大小顺序,这里实际存储的是指数+127。
  • 3.Mantissa(23位): 尾数部分。

我们先算2000000000f的二进制

float f =  2000000000f;
int i = Float.floatToIntBits(f);
System.out.println(Integer.toBinaryString(i));
//运行结果
//1001110111011100110101100101000

结果应该在补一个0,正好32位。
有同学有可能对着很模糊,为什么2000000000f这的二进制是这样的。下面我们来介绍一下,因为这个例子全是整数部分所以这么写

public static void main(String[] args) {
    Integer x = 2000000000;
    StringBuilder stringBuilder = new StringBuilder();
    while (x >= 1){
        //求余数
        Integer y = x % 2;
        x = x / 2;
        stringBuilder.append(y);
    }
    //反转字符串
    stringBuilder.reverse();
    System.out.println(stringBuilder);
}
//结果
//1110111001101011001010000000000

1110111001101011001010000000000可以写成1.11011100110101100101 * 2^30

第一步: Sign(1位)因为是正数所以第一位是0
第二步: Exponent(8位)因为指数是30+127=157转成二进制是10011101
第三步: Mantissa(23位)11011100110101100101,000这个地方不足23位补0,以逗号分割
综上所得第一步➕第二步➕第三步不足32位补0得到
0,10011101,11011100110101100101,000,这就得到上面的值了(上面的值第一位0隐藏了)。
到这里读者还是不明白为什么(f + 50f) == ftrue,其实2000000000f == 2000000050f。是不是不可思议。当你把2000000050f用二进制表示出来你就知道了。

float f =  2000000050f;
int i = Float.floatToIntBits(f);
System.out.println(Integer.toBinaryString(i));
//运行结果
//1001110111011100110101100101000

没有任何变化,为什么呢?我们来按我们的方法去写。

public static void main(String[] args) {
    Integer x = 2000000050;
    StringBuilder stringBuilder = new StringBuilder();
    while (x >= 1){
        //求余数
        Integer y = x % 2;
        x = x / 2;
        stringBuilder.append(y);
    }
    //反转字符串
    stringBuilder.reverse();
    System.out.println(stringBuilder);
}
//结果
//1110111001101011001010000110010

同上面
1110111001101011001010000110010可以写成1.11011100110101100101000011001 * 2^30

第一步: Sign(1位)因为是正数所以第一位是0
第二步: Exponent(8位)因为指数是30+127=157转成二进制是10011101
第三步: Mantissa(23位)11011100110101100101000,011001因为超了23位,所以多余的部分是四舍五入,这里是遇1进位所以得到的是11011100110101100101000
综上所得第一步➕第二步➕第三步超过32位四舍五入得到
0,10011101,11011100110101100101000,这就得到上面的值了(上面的值第一位0隐藏了)。
所以2000000000f == 2000000050f是true。这下是不是理解了。去考考你的同学和同事,让他们怀疑一下自己的编程人生(大牛除外😄)。

最后留一个问题0.1 + 0.2 == 0.3吗?之前讲过哦。

相关文章
|
4月前
1001 害死人不偿命的(3n+1)猜想
1001 害死人不偿命的(3n+1)猜想
25 0
|
4月前
|
前端开发 JavaScript 程序员
程序员教你用代码制作圣诞树,正好圣诞节拿去送给女神给她个惊喜
使用HTML、CSS和JavaScript实现了一个圣诞树效果,包括一个闪烁的圣诞树和一个动态的光斑。代码包含一个<div>元素作为遮罩,一个<canvas>元素绘制星星动画,以及一个SVG元素绘制圣诞树。页面还包含一个提示用户先点赞再观看的提示。此效果适用于任何浏览器,推荐使用谷歌浏览器。提供了一段HTML代码,可以直接复制粘贴到文件中并以.html格式打开查看效果。
35 0
|
12月前
|
测试技术
害死人不偿命的(3n+1)猜想
害死人不偿命的(3n+1)猜想
|
JavaScript 小程序 Java
当年那个手搓CPU的老哥回来了!
当年那个手搓CPU的老哥回来了!
|
缓存 Java Spring
每天一个小题目,你废了吗?
每天一个小题目,你废了吗?
|
测试技术
PAT 1001 害死人不偿命的(3n+1)猜想
对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把 (3n+1) 砍掉一半。
86 0
|
机器学习/深度学习 测试技术
PAT乙级1001 害死人不偿命的(3n+1)猜想 (15分)
PAT乙级1001 害死人不偿命的(3n+1)猜想 (15分)
78 0
L2-029 特立独行的幸福 (25 分)(数组模拟)
L2-029 特立独行的幸福 (25 分)(数组模拟)
116 0
|
测试技术
1001 害死人不偿命的(3n+1)猜想 (15 分)
1001 害死人不偿命的(3n+1)猜想 (15 分)
61 0