算术运算符( - )

Java 语言提供了 7 个对整数和浮点值执行算术运算的运算符。

  • 有两个+运算符:
    • 二元加法运算符将一个数字添加到另一个数字。 (还有一个二进制+运算符,它执行字符串连接。这在另一个例子中描述。)
    • 除了触发数字促销之外,一元加运算符没有任何作用(见下文)
  • 有两个 - 运算符:
    • 二元减法运算符从另一个数字中减去一个数字。
    • 一元减运算符相当于从零减去其操作数。
  • 二进制乘法运算符(*)将一个数字与另一个数字相乘。
  • 二元除法运算符(/)将一个数字除以另一个数字。
  • 二进制余数 1 运算符(%)计算一个数除以另一个数时的余数。

这通常被错误地称为模数算子。 剩余是 JLS 使用的术语。 模数余数不是一回事。

操作数和结果类型以及数字提升

运算符需要数字操作数并生成数字结果。操作数类型可以是任何原始数字类型(即 byteshortcharintlongfloatdouble)或 java.lang 中定义的任何数字包装类型; 即(ByteCharacterShortIntegerLongFloatDouble

结果类型根据操作数或操作数的类型确定,如下所示:

  • 如果其中一个操作数是 doubleDouble,则结果类型为 double
  • 否则,如果其中一个操作数是 floatFloat,则结果类型为 float
  • 否则,如果其中一个操作数是 longLong,则结果类型为 long
  • 否则,结果类型为 int。这包括 byteshortchar 操作数以及`int。

操作的结果类型确定如何执行算术运算,以及如何处理操作数

  • 如果结果类型为 double,则操作数被提升为 double,并且使用 64 位(双精度二进制)IEE 754 浮点运算执行操作。
  • 如果结果类型为 float,则操作数被提升为 float,并且使用 32 位(单精度二进制)IEE 754 浮点运算执行操作。
  • 如果结果类型为 long,则将操作数提升为 long,并使用 64 位带符号二进制补码二进制整数运算执行操作。
  • 如果结果类型为 int,则将操作数提升为 int,并使用 32 位带符号二进制补码二进制整数运算执行操作。

促销分两个阶段进行:

  • 如果操作数类型是包装类型,则操作数值将取消装箱到相应基元类型的值。
  • 如有必要,将基元类型提升为所需类型:
    • intlong 推广整数是无损失的。
    • float 推广到 double 是无损失的。
    • 将整数提升为浮点值可能会导致精度损失。使用 IEE 768舍入到最接近语义执行转换。

分裂的意义

/运算符将左侧操作数 n被除数 )和右侧操作数 d除数 ) 分开,并产生结果 q )。

Java 整数除法向零舍入。该 JLS 第 15.17.2 规定如下 Java 的整数除法的行为:

为操作数 nd 生成的商是一个整数值 q,其大小尽可能大,同时满足|d ⋅ q| ≤ |n|。此外,当|n| ≥ |d|nd 具有相同的符号时,q 为正,但当|n| ≥ |d|nd 具有相反的符号时 q 为负。

有几个特例:

  • 如果 nMIN_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 为负时才是负数,并且
  • 它的大小尽可能大,而不超过 ab 的真正数学商的大小。

浮点余数可以在边缘情况下产生 INFNaN 值,例如当 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 浮点表示 floatdouble。这些表示具有一些特殊值,用于表示超出实数域的值:

  • 无限或 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 的相关小节。请注意,这主要是学术性的。对于典型的计算,INFNaN 意味着出了问题; 例如,输入数据不完整或不正确,或者计算编程错误。