前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >真是个诡计多端的“0”。

真是个诡计多端的“0”。

作者头像
why技术
发布2024-07-04 13:53:22
1130
发布2024-07-04 13:53:22
举报
文章被收录于专栏:why技术

你好呀,我是歪歪。

事情是这样的,昨天我在 B 站冲浪学(摸)习(鱼)的时候,看到毕导发的这个视频:

https://www.bilibili.com/video/BV1SS411w7CF/

我点进去学习了一下,虽然视频长度只有三分钟,但是看得我脑仁疼。

视频的内容是探讨 1 除以 0 到底等于多少?

这还用问吗?

肯定是等于 ArithmeticException 啊。

但是毕导却给了我一个叫做“黎曼球”的东西:

他告诉我,在黎曼球规则里,1 除以 0 等于无穷,这个无穷非正、非负、非实数、非虚数,它长度无限,方向任意。

哦,原来是这样。

我打开弹幕又看了一遍,发现弹幕里面大多数人和我一样没懂,那我就放心了:

在评论区,我还看到了这样的评论:

我立马掏出手机,打开计算器,输入 1÷0,结果...

好吧,这个运行结果,可能还分机型。

在评论区,还提到了另外一个视频:

于是我点过去看了一下:

https://www.bilibili.com/festival/jzj2023?bvid=BV1ph4y1g75E

好家伙,来头还不小,这个视频是 2023 知识区年终盛典金知奖的作品之一。

视频长 14 分钟,看得我目瞪口呆,虽然我看不懂,但是我是真的觉得很厉害。

看完之后,就像是这个热评说的一样:很喜欢这种知识从脑子里流淌而过,而不留下一丝痕迹的感觉。

但是,我其实不能算完全的“不留下一丝痕迹”,看完之后我的脑海里面至少冒出了四个字:数学之美。

推荐你可以去看看。

回到 Java

关于除 0 这个话题,我们回到 Java 里面,我曾经踩过这样的一个坑,也研究了一小下下,给大家分享一下。

先上个代码:

代码语言:javascript
复制
private static double calculate(double a, int b) {
    return a / b;
}

你先别问为什么计算不用 BigDecimal,反正程序里面就是有一个类似于这样的方法。

正常用起来也没啥毛病:

注意,我说的是“正常使用看起来没毛病”,不正常使用是怎么样的呢?

看到输出结果是 “Infinity” 的时候,我甚至揉了一下眼睛,以为自己是过于热爱工作,导致用眼过度,看花了。

有一说一,我真没见过这玩意。但是这个单词我认识啊:

在看毕导的视频之前,在我有限的认知里面, 0 是不可以作为除数的,如果作为除数会抛出异常才对。

但是这个简单的案例打破了我的认知,它不仅没有抛出异常,还给我了一个“无穷大的数”。

在一脸懵逼中,我知道,素材这不就来了嘛。

搜索一番

如果是在使用框架的过程中遇到问题,一般来说我是先自己调试一下,挣扎一波,看看是不是自己的打开方式不对。

但是这个问题太简单了,以至于我甚至找不到调试的角度。

怎么办?

只有直接拿出程序员的祖传技能了:面向浏览器编程。

于是我输入搜索关键字 “Java Infinity”,排在第一的是某博客网站:

我个人是不太喜欢这个网站,所以我按照个人习惯重新搜索了一次:

找到了下面这个链接:

https://www.cnblogs.com/zhisuoyu/p/5314541.html

从这篇文章中我知道了,原来在我的认知里面,0 作为除数会抛出下面这个异常,还有一个前提是“整型运算”:

java.lang.ArithmeticException: / by zero

在 Double 和 Float 里面都定义了“正无穷”和“负无穷”这两个常量:

现在我知道在浮点运算的时候,0 是可以作为除数的。

那么 Java 里面什么这样设计呢,为什么不一视同仁呢?

博客里面没有写,但是我知道要找到这个问题的答案,这个地方可以去看看:

https://stackoverflow.com/

于是我用 “Java Double Float Infinity” 关键字去查询了一下:

很容易就找到了这个链接:

https://stackoverflow.com/questions/12954193/why-does-division-by-zero-with-floating-point-or-double-precision-numbers-not

这个提问者提出的问题翻译过来,和我前面遇到的问题一模一样:

为什么用 Float 或者 Double 除以零不会抛出 java.lang.ArithmeticExceptionL:/by zero 异常?

这个问题下的高赞回答是这样的:

问题的终极答案就藏在这个高赞回答中,我给你解析一番。

揭秘

这个高赞回答,其实就只有一句话:

In short, that's the way it's specified in the IEEE-754 standard, which is what Java's Floating-Point Operations are based on.

其他的部分都是引用。

在这一句话中,他提到了两个关键的东西:

  • IEEE-754 standard
  • Java's Floating-Point Operations

意思就是 Java 的浮点运算是基于 IEEE-754 标准来的。

他给的其中一个超链接是 Java 语言规范:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.3

Java 语言规范表示:你要问我为什么,我只能告诉你我遵守的是 IEEE 754 这个国际规范。

所以,别问:

那么这个 IEEE 754 是个什么东西呢?

我也不知道,所以查一下:

好家伙,来头还不小。

IEEE,全称 Institute of Electrical and Electronics Engineers,电气和电子工程师协会。

IEEE 754 的全称是 IEEE Standard for Floating-Point Arithmetic。表示电气和电子工程师协会制定的浮点运算技术标准。

Standard,标准,你明白吧?

得有一些 Standard,有些事情才好办,不然各自为战,各自兼容,难受的一比。

所以,该标准是为了解决在不同的浮点实现中的各种问题,这些问题使它们难以可靠地使用和移植。

一旦有了标准,大家都遵守,就好办了。

在标准中就规定了对于异常应该如何处理:

来,框起来的部分,跟我大声的朗读一遍:

Division by zero: an operation on finite operands gives an exact infinite result, e.g., 1/0 or log(0). By default, returns ±infinity.

针对“除以 0”异常,IEEE 754 规定:对有限操作数的运算会得到一个精确的无限结果,例如,1/0 或 log(0)。默认情况下,返回 ±infinity。

另外,说个题外话,按照毕导的视频来说,这里的这个 “±infinity” 其实是不严谨的,应该就是无穷,视频前面说了,这个无穷非正、非负、非实数、非虚数,它长度无限,方向任意。

那么问题又来了?

为什么标准中要这样的规定呢?

在前面提到的高赞回答中,给到了这样的一个链接:

https://web.archive.org/web/20180112211305/http://grouper.ieee.org/groups/754/faq.html#exceptions

这个问题的答案就藏在这个链接里面:

请问:为什么除以零(或溢出,或下溢)不会停止程序或引发错误?

下面给了一大段回复,我尝试着理解了几次,但是我发现有点超纲了,确实不知道具体啥意思。

我个人浅显的认为它要表达的意思是:这玩意使用范围很广,为了程序的稳定性,我不想抛出异常来终止程序,而使用者应该知道我这个“除 0 之后是一个无穷大的数”这样的设定。

所以到底为什么呢?

好了,

别问了,

就到这吧。

再问,

就不礼貌了。

看完之后,你只需要记住一句话:在 Java 里面,除数作为 0,不一定会抛出 ArithmeticException,千万不要形成这样的固化思维,从而影响自己排除问题的方向。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 why技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 回到 Java
  • 搜索一番
  • 揭秘
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档