算术运算符( - )
Java 语言提供了 7 个对整数和浮点值执行算术运算的运算符。
- 有两个
+
运算符:- 二元加法运算符将一个数字添加到另一个数字。 (还有一个二进制
+
运算符,它执行字符串连接。这在另一个例子中描述。) - 除了触发数字促销之外,一元加运算符没有任何作用(见下文)
- 二元加法运算符将一个数字添加到另一个数字。 (还有一个二进制
- 有两个
-
运算符:- 二元减法运算符从另一个数字中减去一个数字。
- 一元减运算符相当于从零减去其操作数。
- 二进制乘法运算符(*)将一个数字与另一个数字相乘。
- 二元除法运算符(/)将一个数字除以另一个数字。
- 二进制余数 1 运算符(%)计算一个数除以另一个数时的余数。
这通常被错误地称为模数算子。 剩余是 JLS 使用的术语。 模数和余数不是一回事。
操作数和结果类型以及数字提升
运算符需要数字操作数并生成数字结果。操作数类型可以是任何原始数字类型(即 byte
,short
,char
,int
,long
,float
或 double
)或 java.lang
中定义的任何数字包装类型; 即(Byte
,Character
,Short
,Integer
,Long
,Float
或 Double
。
结果类型根据操作数或操作数的类型确定,如下所示:
- 如果其中一个操作数是
double
或Double
,则结果类型为double
。 - 否则,如果其中一个操作数是
float
或Float
,则结果类型为float
。 - 否则,如果其中一个操作数是
long
或Long
,则结果类型为long
。 - 否则,结果类型为
int
。这包括byte
,short
和char
操作数以及`int。
操作的结果类型确定如何执行算术运算,以及如何处理操作数
- 如果结果类型为
double
,则操作数被提升为double
,并且使用 64 位(双精度二进制)IEE 754 浮点运算执行操作。 - 如果结果类型为
float
,则操作数被提升为float
,并且使用 32 位(单精度二进制)IEE 754 浮点运算执行操作。 - 如果结果类型为
long
,则将操作数提升为long
,并使用 64 位带符号二进制补码二进制整数运算执行操作。 - 如果结果类型为
int
,则将操作数提升为int
,并使用 32 位带符号二进制补码二进制整数运算执行操作。
促销分两个阶段进行:
- 如果操作数类型是包装类型,则操作数值将取消装箱到相应基元类型的值。
- 如有必要,将基元类型提升为所需类型:
- 向
int
或long
推广整数是无损失的。 - 将
float
推广到double
是无损失的。 - 将整数提升为浮点值可能会导致精度损失。使用 IEE 768舍入到最接近语义执行转换。
- 向
分裂的意义
/运算符将左侧操作数 n
( 被除数 )和右侧操作数 d
( 除数 ) 分开,并产生结果 q
( 商 )。
Java 整数除法向零舍入。该 JLS 第 15.17.2 规定如下 Java 的整数除法的行为:
为操作数
n
和d
生成的商是一个整数值q
,其大小尽可能大,同时满足|d ⋅ q| ≤ |n|
。此外,当|n| ≥ |d|
和n
和d
具有相同的符号时,q
为正,但当|n| ≥ |d|
和n
和d
具有相反的符号时q
为负。
有几个特例:
- 如果
n
是MIN_VALUE
,并且除数是 -1,则发生整数溢出,结果是MIN_VALUE
。在这种情况下不会抛出异常。 - 如果
d
为 0,则抛出`ArithmeticException。
Java 浮点除法有更多边缘情况需要考虑。然而,基本的想法是结果 q
是最接近满足 d . q = n
的值。
浮点除法永远不会导致异常。相反,除以零的运算会产生 INF 和 NaN 值; 见下文。
余数的含义
与 C 和 C++不同,Java 中的余数运算符适用于整数和浮点运算。
对于整数情况,a % b
的结果定义为 r
,使得 (a / b) * b + r
等于 a
,其中/
,*
和+
是适当的 Java 整数运算符。这适用于所有情况,除非 b
为零。那种情况下,剩余部分会产生一种情况。
从上面的定义可以得出,a % b
只有在 a
为负时才能为负数,只有当 a
为正时才为正。此外,a % b
的数量总是小于 b
的数量。
浮点余数运算是整数情况的推广。a % b
的结果是余量 r
由数学关系 r = a - (b ⋅ q)
定义,其中:
q
是一个整数,- 只有当
a / b
为正时,只有当a / b
为负时才是负数,并且 - 它的大小尽可能大,而不超过
a
和b
的真正数学商的大小。
浮点余数可以在边缘情况下产生 INF
和 NaN
值,例如当 b
为零时; 见下文。它不会抛出异常。
重要的提示:
作为计算通过
%
浮点余数操作的结果是不相同的,通过由 IEEE 754. IEEE 754 定义的剩余部分剩余部分操作产生可以使用本Math.IEEEremainder
文库的方法来计算。
整数溢出
Java 32 和 64 位整数值被签名并使用二进制补码二进制表示。例如,数字的范围所能表述为(32 位)int
-2 31 通过 2 31 - 1。
当你添加,减去或多个两个 N 位整数(N == 32 或 64)时,操作的结果可能太大而无法表示为 N 位整数。在这种情况下,操作会导致整数溢出,结果可以按如下方式计算:
- 执行数学运算以给出整数的中间二进制补码表示。该表示将大于 N 位。
- 中间表示的底部 32 或 64 位用作结果。
应该注意的是,整数溢出在任何情况下都不会导致异常。
浮点 INF 和 NAN 值
Java 使用 IEE 754 浮点表示 float
和 double
。这些表示具有一些特殊值,用于表示超出实数域的值:
- 无限或 INF 值表示数字太大。
+INF
值表示过大且积极的数字。-INF
值表示过大和负数的数字。 - 无限期/非数字或 NaN 表示由无意义操作产生的值。
INF 值由导致溢出的浮动操作产生,或者由除以零产生。
通过将零除以零或计算零余数零来产生 NaN 值。
令人惊讶的是,可以使用 INF 和 NaN 操作数执行算术而不会触发异常。例如:
- 添加+ INF 和有限值会给出+ INF。
- 添加+ INF 和+ INF 会给出+ INF。
- 添加+ INF 和 -INF 会产生 NaN。
- 除以 INF 给出+0.0 或 -0.0。
- 具有一个或多个 NaN 操作数的所有操作都给出 NaN。
有关详细信息,请参阅 JLS 15 的相关小节。请注意,这主要是学术性的。对于典型的计算,INF
或 NaN
意味着出了问题; 例如,输入数据不完整或不正确,或者计算编程错误。