Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to code a modulo (%) operator in C/C++/Obj-C that handles negative numbers

One of my pet hates of C-derived languages (as a mathematician) is that

(-1) % 8 // comes out as -1, and not 7  fmodf(-1,8) // fails similarly 

What's the best solution?

C++ allows the possibility of templates and operator overloading, but both of these are murky waters for me. examples gratefully received.

like image 357
P i Avatar asked Oct 23 '10 09:10

P i


People also ask

Can you modulo a negative number in C?

Anyone can predict the output of a modulus operator when both operands are positive. But when it comes to the negative numbers, different languages give different outputs. In C language, modulus is calculated as, a % n = a – ( n * trunc( a/n ) ).

How do you do modulus with negative numbers?

The modulus of a negative number is found by ignoring the minus sign. The modulus of a number is denoted by writing vertical lines around the number. Note also that the modulus of a negative number can be found by multiplying it by −1 since, for example, −(−8) = 8.

What the modulus operator (%) does?

The modulus operator is added in the arithmetic operators in C, and it works between two available operands. It divides the given numerator by the denominator to find a result. In simpler words, it produces a remainder for the integer division.

What is the use of modulus (%) operator in C++?

C++ provides the modulus operator, %, that yields the remainder after integer division. The modulus operator can be used only with integer operands. The expression x % y yields the remainder after x is divided by y. Thus, 7 % 4 yields 3 and 17 % 5 yields 2.


2 Answers

First of all I'd like to note that you cannot even rely on the fact that (-1) % 8 == -1. the only thing you can rely on is that (x / y) * y + ( x % y) == x. However whether or not the remainder is negative is implementation-defined.

Reference: C++03 paragraph 5.6 clause 4:

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.

Here it follows a version that handles both negative operands so that the result of the subtraction of the remainder from the divisor can be subtracted from the dividend so it will be floor of the actual division. mod(-1,8) results in 7, while mod(13, -8) is -3.

int mod(int a, int b) {    if(b < 0) //you can check for b == 0 separately and do what you want      return -mod(-a, -b);       int ret = a % b;    if(ret < 0)      ret+=b;    return ret; } 
like image 75
Armen Tsirunyan Avatar answered Sep 28 '22 04:09

Armen Tsirunyan


Here is a C function that handles positive OR negative integer OR fractional values for BOTH OPERANDS

#include <math.h> float mod(float a, float N) {return a - N*floor(a/N);} //return in range [0, N) 

This is surely the most elegant solution from a mathematical standpoint. However, I'm not sure if it is robust in handling integers. Sometimes floating point errors creep in when converting int -> fp -> int.

I am using this code for non-int s, and a separate function for int.

NOTE: need to trap N = 0!

Tester code:

#include <math.h> #include <stdio.h>  float mod(float a, float N) {     float ret = a - N * floor (a / N);      printf("%f.1 mod %f.1 = %f.1 \n", a, N, ret);      return ret; }  int main (char* argc, char** argv) {     printf ("fmodf(-10.2, 2.0) = %f.1  == FAIL! \n\n", fmodf(-10.2, 2.0));      float x;     x = mod(10.2f, 2.0f);     x = mod(10.2f, -2.0f);     x = mod(-10.2f, 2.0f);     x = mod(-10.2f, -2.0f);      return 0; } 

(Note: You can compile and run it straight out of CodePad: http://codepad.org/UOgEqAMA)

Output:

fmodf(-10.2, 2.0) = -0.20 == FAIL!

10.2 mod 2.0 = 0.2
10.2 mod -2.0 = -1.8
-10.2 mod 2.0 = 1.8
-10.2 mod -2.0 = -0.2

like image 30
P i Avatar answered Sep 28 '22 05:09

P i