13

踩坑了!0作为除数,不一定会抛出异常! - why技术

 2 years ago
source link: https://www.cnblogs.com/thisiswhy/p/16635585.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

踩坑了!0作为除数,不一定会抛出异常!

你好呀,我是歪歪。

踩坑了啊,又踩坑了啊!

这次踩到一个特别无语的常识坑。知道真相的那一刻,人就是整个麻掉。

20220828161111.png

先上个代码:

private static double calculate(double a, int b) {
    return a / b;
}

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

正常用起来也没啥毛病:

20220828115737.png

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

20220828115838.png

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

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

20220828134251.png

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

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

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

20220828161607.png

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

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

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

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

20220828122836.png

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

20220828123126.png

找到了下面这个链接:

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

20220828133811.png

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

java.lang.ArithmeticException: / by zero

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

20220828134010.png
20220828134052.png

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

但是,为什么呢?

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

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

https://stackoverflow.com/

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

20220828141257.png

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

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

20220828143804.png

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

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

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

20220828144050.png

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

20220828162436.png

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

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

20220828145212.png

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

所以,别问:

20220828162616.png

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

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

20220828155131.png

好家伙,来头还不小。

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

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

Standard,标准,你明白吧?

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

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

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

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

20220828155401.png

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

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。

那么问题又来了?

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

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

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

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

20220828160041.png

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

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

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

所以到底为什么呢?

就到这吧。

就不礼貌了。

20220829123415.png

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


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK