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] |
- From: "Nelson H. F. Beebe"
- To: gcc-help at gcc dot gnu dot org
- Cc: beebe at math dot utah dot edu
- Date: Wed, 9 Nov 2005 14:46:51 -0700 (MST)
- Subject: Re: Remainder ( % ) operator and GCC
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 -> -2The 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) -> 1Here is the standardese:
... 6.5.5 Multiplicative operators
Syntax1 multiplicative-expression: cast-expression multiplicative-expression * cast-expression multiplicative-expression / cast-expression multiplicative-expression % cast-expression
Constraints2 Each of the operands shall have arithmetic type. The operands of the % operator shall have integer type.
Semantics3 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
Synopsis1 #include <inttypes.h> imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom);
Description2 The imaxdiv function computes numer / denom and numer % denom in a single operation.
Returns3 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
Synopsis1 #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);
Description2 The div, ldiv, and lldiv, functions compute numer / denom and numer % denom in a single operation.
Returns3 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
Synopsis1 #include <math.h> double fmod(double x, double y); float fmodf(float x, float y); long double fmodl(long double x, long double y);
Description2 The fmod functions compute the floating-point remainder of x/y.
Returns3 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
Synopsis1 #include <math.h> double remainder(double x, double y); float remainderf(float x, float y); long double remainderl(long double x, long double y);
Description2 The remainder functions compute the remainder x REM y required by IEC 60559. 201)
Returns3 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
Synopsis1 #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);
Description2 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.
Returns3 The remquo functions return x REM y. ...
- Nelson H. F. Beebe Tel: +1 801 581 5254 -
- University of Utah FAX: +1 801 581 4148 -
- Department of Mathematics, 110 LCB Internet e-mail: beebe@math.utah.edu -
- 155 S 1400 E RM 233 beebe@acm.org beebe@computer.org -
- Salt Lake City, UT 84112-0090, USA URL: http://www.math.utah.edu/~beebe -
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |