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

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

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

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

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

示例

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吗?之前讲过哦。

相关文章
|
6月前
|
前端开发 JavaScript 程序员
程序员教你用代码制作圣诞树,正好圣诞节拿去送给女神给她个惊喜
使用HTML、CSS和JavaScript实现了一个圣诞树效果,包括一个闪烁的圣诞树和一个动态的光斑。代码包含一个<div>元素作为遮罩,一个<canvas>元素绘制星星动画,以及一个SVG元素绘制圣诞树。页面还包含一个提示用户先点赞再观看的提示。此效果适用于任何浏览器,推荐使用谷歌浏览器。提供了一段HTML代码,可以直接复制粘贴到文件中并以.html格式打开查看效果。
96 0
|
机器学习/深度学习 人工智能 Java
|
JavaScript 小程序 Java
当年那个手搓CPU的老哥回来了!
当年那个手搓CPU的老哥回来了!
|
程序员
L1-045 宇宙无敌大招呼 (5 分)
L1-045 宇宙无敌大招呼 (5 分)
139 0
|
C语言 C++ 算法
再学一道算法题:无聊的小明来数1 --按位与
小明这几天非常无聊,于是乎他又给自己找了一个乐子,他随手写一个十进制的数字,然后转换成二进制,数一数二进制中有几个1,请编写程序完成这个过程,注意看看输入、输出格式。
再学一道算法题:无聊的小明来数1 --按位与
|
前端开发 JavaScript 程序员
圣诞临近,小包送给大家一个雪人,一群麋鹿,一堆糖果,一句祝福,圣诞快乐!
圣诞临近,小包送给大家一个雪人,一群麋鹿,一堆糖果,一句祝福,圣诞快乐!
213 0
圣诞临近,小包送给大家一个雪人,一群麋鹿,一堆糖果,一句祝福,圣诞快乐!
|
存储 安全 Java
万恶的NPE差点让我半个月工资没了
万恶的NPE差点让我半个月工资没了
185 0
万恶的NPE差点让我半个月工资没了
|
算法
《C游记》 番外篇(壹)二分查找显神威 猜数游戏趣味生
《C游记》 番外篇(壹)二分查找显神威 猜数游戏趣味生
136 0
《C游记》 番外篇(壹)二分查找显神威 猜数游戏趣味生
|
Kubernetes API 调度
趁着同事玩游戏偷偷认识k8s一家子补补课
Kubernetes集群这个大家庭在容器化时代能够新军崛起,要感谢其众多可靠稳定,工作认真负责的优质成员。这些兄弟姐妹们为集群提供`故障转移`和`高可用性`,保证k8s 可以跨多主机运行,集群跨多个节点运行。
210 0
趁着同事玩游戏偷偷认识k8s一家子补补课
下一篇
无影云桌面