Nelson H. F. Beebe - Re: Remainder ( % ) operator and GCC (original) (raw)

This is the mail archive of the gcc-help@gcc.gnu.orgmailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Discussion today on this list about the use of the C remainder operator, %, met with suggestions to use fmod() and div().

This is not a gcc-specific question, and thus is off-topic for this list. Nevertheless, it is a frequent source of misunderstanding (i.e., coding bugs), so I answer it below in depth.

The meaning of the remainder operator for negative arguments was defined to be IMPLEMENTATION DEPENDENT in 1989 ISO C (and was so in historical K&R implementations), but that was fixed in the 1999 Standard.

The relevant text from the 1999 ISO C Standard appears at the end of this message. Please remember that it will still be several years before C99-conforming compilers are widely the norm: don't rely on the behavior of the % operator if you need to run on a wide range of platforms with many different compilers.

In summary, div() will just get you the same result as %.

fmod() has floating-point arguments, and needs careful use to ensure that bits are not lost in conversion from integer to floating-point. For example, you cannot do (float)int_foo without risk of bit loss on most current platforms, but you CAN safely do (double)int_foo on those systems.

The C99 definition of % operator (see below) implies the following behavior:

    17 % 3    ->  2
    17 % -3   ->  2
    -17 % 3   -> -2
    -17 % -3  -> -2

The results from fmod() are the same as those for %.

To get the right answer, take the remainder of division of positive integers, and attach the sign of the first number. If you implement your own function to do this portably, however, you must also take care to handle the case of the most negative integer: on two's complement systems (virtually all computers on which C runs), that number has no corresponding positive value. Thus, -2147483648 % 3 = -2 and -(-2147483648) % 3 = -2: notice the sign of the latter.

The remainder() function behaves differently:

    remainder(17, 3)   -> -1
    remainder(17, -3)  -> -1
    remainder(-17, 3)  ->  1
    remainder(-17, -3) ->  1

Here is the standardese:

... 6.5.5 Multiplicative operators

 Syntax

1 multiplicative-expression: cast-expression multiplicative-expression * cast-expression multiplicative-expression / cast-expression multiplicative-expression % cast-expression

 Constraints

2 Each of the operands shall have arithmetic type. The operands of the % operator shall have integer type.

 Semantics

3 The usual arithmetic conversions are performed on the operands.

4 The result of the binary * operator is the product of the operands.

5 The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined.

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

... 7.8.2.2 The imaxdiv function

 Synopsis

1 #include <inttypes.h> imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom);

 Description

2 The imaxdiv function computes numer / denom and numer % denom in a single operation.

 Returns

3 The imaxdiv function returns a structure of type imaxdiv_t comprising both the quotient and the remainder. The structure shall contain (in either order) the members quot (the quotient) and rem (the remainder), each of which has type intmax_t. If either part of the result cannot be represented, the behavior is undefined. ...

... 7.20.6.2 The div, ldiv, and lldiv functions

 Synopsis

1 #include <stdlib.h> div_t div(int numer, int denom); ldiv_t ldiv(long int numer, long int denom); lldiv_t lldiv(long long int numer, long long int denom);

 Description

2 The div, ldiv, and lldiv, functions compute numer / denom and numer % denom in a single operation.

 Returns

3 The div, ldiv, and lldiv functions return a structure of type div_t, ldiv_t, and lldiv_t, respectively, comprising both the quotient and the remainder. The structures shall contain (in either order) the members quot (the quotient) and rem (the remainder), each of which has the same type as the arguments numer and denom. If either part of the result cannot be represented, the behavior is undefined. ...

... 7.12.10.1 The fmod functions

 Synopsis

1 #include <math.h> double fmod(double x, double y); float fmodf(float x, float y); long double fmodl(long double x, long double y);

 Description

2 The fmod functions compute the floating-point remainder of x/y.

 Returns

3 The fmod functions return the value x - ny, for some integer n such that, if y is nonzero, the result has the same sign as x and magnitude less than the magnitude of y. If y is zero, whether a domain error occurs or the fmod functions return zero is implementation- defined.

...

... 7.12.10.2 The remainder functions

 Synopsis

1 #include <math.h> double remainder(double x, double y); float remainderf(float x, float y); long double remainderl(long double x, long double y);

 Description

2 The remainder functions compute the remainder x REM y required by IEC 60559. 201)

 Returns

3 The remainder functions return x REM y.

 201) ``When y 0, the remainder r = x REM y is defined
 regardless of the rounding mode by the mathematical relation r
 = x - ny, where n is the integer nearest the exact value of
 x/y; whenever | n - x/y | = 1/2, then n is even.  Thus, the
 remainder is always exact.  If r = 0, its sign shall be that
 of x.'' This definition is applicable for all implementations.

...

... 7.12.10.3 The remquo functions

 Synopsis

1 #include <math.h> double remquo(double x, double y, int *quo); float remquof(float x, float y, int *quo); long double remquol(long double x, long double y, int *quo);

 Description

2 The remquo functions compute the same remainder as the remainder functions. In the object pointed to by quo they store a value whose sign is the sign of x/y and whose magnitude is congruent modulo 2n to the magnitude of the integral quotient of x/y, where n is an implementation-defined integer greater than or equal to 3.

 Returns

3 The remquo functions return x REM y. ...




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]