I am curious about these languages (Java, C ...) which ignore mathematical definition of modulus operation.
What is the point of returning negative values in a module operation (that, by definition, should allways return a positive number)?
I doubt that the remainder operator was deliberately designed to have those semantics, which I agree aren't very useful. (Would you ever write a calendar program that shows the weekdays Sunday, Anti-Saturday, Anti-Friday, ..., Anti-Monday for dates before the epoch?)
Rather, negative remainders are a side effect of the way integer division is defined.
A rem B := A - (A div B) * B
If A div B
is defined as trunc(A/B)
, you get C's %
operator. If A div B
is defined as floor(A/B)
, you get Python's %
operator. Other definitions are possible.
So, the real question is:
Why do C++, Java, C#, etc. use truncating integer division?
Because that's the way that C does it.
Why does C use truncating division?
Originally, C didn't specify how /
should handle negative numbers. It left it up to the hardware.
In practice, every significant C implementation used truncating division, so in 1999 these semantics were formally made a part of the C standard.
Why does hardware use truncating division?
Because it's easier (=cheaper) to implement in terms of unsigned division. You just calculate abs(A) div abs(B)
and flip the sign if (A < 0) xor (B < 0)
.
Floored division has the additional step of subtracting 1 from the quotient if the remainder is nonzero.
In Java at least, it's not a modulus operator - it's a remainder operator.
I believe the reason for it being chosen that way is to make this relation work (from the JLS):
The remainder operation for operands that are integers after binary numeric promotion (§5.6.2) produces a result value such that (a/b)*b+(a%b) is equal to a. This identity holds even in the special case that the dividend is the negative integer of largest possible magnitude for its type and the divisor is -1 (the remainder is 0). It follows from this rule that the result of the remainder operation can be negative only if the dividend is negative, and can be positive only if the dividend is positive; moreover, the magnitude of the result is always less than the magnitude of the divisor.
That equality relation seems like a reasonable thing to use as part of the definition. If you take division truncating towards zero to be a given, that leaves you with a negative remainder.
From Wikipedia (my emphasis):
Given two positive numbers, a (the dividend) and n (the divisor), a modulo n (abbreviated as a mod n) can be thought of as the remainder, on division of a by n. For instance, the expression "5 mod 4" would evaluate to 1 because 5 divided by 4 leaves a remainder of 1, while "9 mod 3" would evaluate to 0 because the division of 9 by 3 leaves a remainder of 0; there is nothing to subtract from 9 after multiplying 3 times 3. (Notice that doing the division with a calculator won't show you the result referred to here by this operation, the quotient will be expressed as a decimal.) When either a or n is negative, this naive definition breaks down and programming languages differ in how these values are defined. Although typically performed with a and n both being integers, many computing systems allow other types of numeric operands. The range of numbers for an integer modulo of n is 0 to n - 1. (n mod 1 is always 0; n mod 0 is undefined, possibly resulting in a "Division by zero" error in computer programming languages) See modular arithmetic for an older and related convention applied in number theory.
Most of them are not defined to return a modulus. What they're defined to return is a remainder, for which positive and negative values are equally reasonable.
In C or C++ it's pretty reasonable to say it should produce whatever the underlying hardware produces. That excuse/reason doesn't work nearly as well for Java though.
Also note that in C89/90 and C++98/03, the remainder could be either positive or negative, as long as the results from remainder and division worked together ((a/b)*b+a%b == a
). In C99 and C++11, the rules been tightened up so the division must truncate toward zero, and if there is a remainder it must be negative.
A pragmatic reason to return a negative value for modulus would be that the hardware instruction implementing modulus does so.
So standards leave that ill defined, so that compilers can do whatever is simpler to them.
In neither of the C or Java standards is %
referred to as a modulus operator - rather, it returns the remainder.
It is defined to return negative numbers for negative dividends so that the relation (a/b)*b + a%b == a
holds, as long as a / b
is representable. Since the division operator is defined to truncate towards zero, this constrains the sign of the remainder.
来源:https://stackoverflow.com/questions/8318791/is-there-a-reason-some-languages-allow-a-negative-modulus