Can I rely on % (modulo) operator in C for negative numbers?
Asked Answered
B

3

1

Using GCC:

printf("%i \n", -1 % (int)4);
printf("%u \n", -1 % (unsigned int)4);

Output:

-1
3

Can I rely on this behaviour across platforms? Should I explicitly define MOD and REM macros to be sure this isn't altered?

Bohman answered 21/3, 2015 at 4:45 Comment(0)
C
4

From C99 onwards the result of % is required to be rounded toward 0 as quoted by Chris Dodd.

Prior to C99 standard, % operator's behavior on negative number is implementation defined.

When integers are divided and the division is inexact, if both operands are positive the result of the / operator is the largest integer less than the algebraic quotient and the result of the % operator is positive. If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.

Does either ANSI C or ISO C specify what -5 % 10 should be?

So the result is Yes if you're targeting C99 or newer, otherwise you can't rely on that.

If you need consistent result with portability to even older C standards, you can use div or ldiv, no need to define your own MOD and REM

C99 rationale regarding div, ldiv, and lldiv functions:

Because C89 had implementation-defined semantics for division of signed integers when negative operands were involved, div and ldiv, and lldiv in C99, were invented to provide well-specified semantics for signed integer division and remainder operations.

Charge answered 21/3, 2015 at 5:28 Comment(0)
I
1

The C99 standard says:

6.5.5 Multiplicative operators

:

When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded87). If the quotient a/b is representable, the expression
(a/b)*b + a%b shall equal a.

:

87) This is often called ‘‘truncation toward zero’’

This implies that divide always rounds towards 0, so you can rely on it.

Note that this is different from the C++03 standard.

Your second line does an unsigned divide, converting the value -1 to unsigned int before the divide. This will always be one less than a power of 2, so that is also well defined.

Ironworks answered 21/3, 2015 at 5:11 Comment(10)
It's not different from the C++11 standard. Which C++ standard are you referring to? (Or, to put it another way, it's also different from a previous C standard)Gayomart
@rici: I was referring to the C++03 standard that was more or less concurrent with the C99 standard. Much has changed with C11/C++11Ironworks
@user3467349: Strangely enough, that is guarenteed to evaluate to true -- the presence of the (unsigned int) cast will convert ALL the other constants to unsigned ints, and the -1s will become large positive integers (one less than a power of 2)Ironworks
There's a kind of relativity time-shift effect between different standards, so the fact that C++03 and C99 were somewhat contemporaneous doesn't actually imply that they were aligned, for all that there were some good intentions. (Some of the changes were still beyond the event horizon.) All the same, C++03 did not exclude C99 behaviour for %, and most implementations were aligned even though the standard allowed more flexibility.Gayomart
So if I understand correctly i.e. -1 % (unsigned int)4 will always be rendered as 4294967295 and then calculated % 4 and this is true across all C compilers?Bohman
@user3467349: (1) Since C99, which may not be all C compilers. (2) It might not be 2^32-1; int is not always 32 bits. (in the case of %4U, that makes no difference.)Gayomart
@user3467349: assuming unsigned int is 32 bits, yes.Ironworks
Actually only since C++11 many C99 features including % operator behavior are introduced into C. C++03 still has the remainder result implementation defined (en.wikipedia.org/wiki/Modulo_operation and en.cppreference.com/w/cpp/numeric/math/div)Charge
You need -std=c99 because some compilers don't enable C99 by default. And this won't work on older compilersCharge
I missed this yesterday, but the behaviour for %4 is only useful because it is a power of 2, for example -19 % (unsigned int)23 will hardly give a useful result.Bohman
D
-3

The modulo operator (%) has been part of the C and C++ standards for years. I am not sure you can overload it in C++. So YES you can rely on it.

Drum answered 21/3, 2015 at 4:58 Comment(5)
According to this answer the behaviour is implementation defined in C++, or is this outdated? https://mcmap.net/q/102203/-how-to-code-a-modulo-operator-in-c-c-obj-c-that-handles-negative-numbers-duplicateBohman
The question is: will that code produce the same output on every conforming C compiler? Because there are things in C that are (permissibly) compiler-dependent..Tullus
Well I have been writing straight C code for a long time. I have used the *nix, MS, Borland, and Intel C compilers and have never had a failure but YMMV.Drum
The OP didn't ask if you can overload % the operator or not. And you can't overload any operators in C. He asked for the behavior for negative numbersCharge
In most cases you can rely on it, but you must keep in mind that there are some cases like with negative number modulo divisions where no guarantees are provided and operation is fully dependant on the compiler and on how old its version is. It is better to test everything first and preferably use something that is at least C99-compliant. If your compiler claims to be C17 (ISO/IEC 9899:2018) compliant then you can be more relaxed, but still not completely - it is C programming after all.Diestock

© 2022 - 2024 — McMap. All rights reserved.