I just want to AC you~~~
複習C++ Prime 4th的時候,看見書上對/和%操作符有以下描述:
For both division (/) and modulus(%), when both operands are positive, the result is positive (or zero). If both operands are negative, the result of division is positive (or zero) and the result of modulus is negative (or zero). If only one operand is negative, then the value of the result is machine-dependent for both operators. The sign is also machine-dependent for modulus; the sign is negative (or zero) for division :
21 % 6; // ok: result is 3 21 % 7; // ok: result is 0 -21 % -8; // ok: result is -5 21 % -5; // machine-dependent: result is 1 or -4 21 / 6; // ok: result is 3 21 / 7; // ok: result is 3 -21 / -8; // ok: result is 2 21 / -5; // machine-dependent: result -4 or -5
這段隱晦難懂的文字結合程式碼轉換成表格後依然讓人難以理解:
a | b | a / b | a % b |
>0 | >0 | >=0,取值可唯一確定 | >=0,取值可唯一確定 |
<0 | <0 | >=0,取值可唯一確定 | <=0,取值可唯一確定 |
>0 | <0 | <=0,取值由實現決定 | 符號和取值均由實現決定 |
<0 | >0 | <=0,取值由實現決定 | 符號和取值均由實現決定 |
於是我下載了C++ Prime 4th出版時C++最新版本(C++03)的ISO 標準文件,在章節5.6 Multiplicative operators下找到了如下敘述:
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined; otherwise (a/b)*b + a%b is equal to a. If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
也就是說對於整數除法和取餘,C++03只確保以下兩點:
( a / b ) * b + a % b = a ( b != 0 )。
a % b >= 0 ( a >= 0 && b > 0 )。
在經典和標準的描述中,都指出了餘數的符號,卻沒有提及更容易讓人理解的取整方法。
為此,我根據數學意義上的公式“商×除數+餘數=被除數”做出了不同取整方法下,a和b的符號與a%b的符號的對應圖:
根據這些圖表,從取整方法的角度,可以得出以下結論:
標準:在運算元均為正數時向下取整(此時也是向零取整),其餘情況由實現決定。
經典:在運算元符號相同時向下取整(此時也是向零取整),異號情況由實現決定。
經典與標準對運算元均為負數時描述的不一致讓我迷惑,莫非是作者的一時疏忽?然而當我在C++ Prime 5th中的相應章節找到以下敘述時頓感納悶:
In a division, a nonzero quotient is positive if the operands have the same sign and negative otherwise. Earlier versions of the language permitted a negative quotient to be rounded up or down; the new standard requires the quotient to be rounded toward zero (i.e., truncated).
“早期的語言標準允許負數商向上取整或向下取整”這一句豈不是暗示在運算元符號相同時取整方法是有明確規定的?
也許是Stanley B. Lippman連錯了兩次?
另外,C++11中已經規定,整數除法一律採用向零取整:
For integral operands the / operator yields the algebraic quotient with any fractional part discarded ( This is often called truncation towards zero. );
這一點在上述的C++ Prime 5th的敘述中也有提到。