signed int modulo unsigned int produces nonsense results


I need to perform a real mathematical modulo in C. It makes sense for me to allow negative numbers for the moduled argument, since my modular calculations can produce negative intermediate results, which must be put back into the least residue system. But it makes no sense to allow negative module, therefore i wrote

unsigned int mod( int x, unsigned int m ) { int r = x % m; return r >= 0 ? r : r + m; }

However calling such function with negative number and positive module

printf("%u\n", mod(-3, 11));

produces output


And i don't understand why. Could you please explain?

EDIT: I know operator % is different from mathematical modulo and i know how it is defined for positive and negative numbers. I was asking what it will do for different signedness, not different sign.


clang with -Wconversion enabled clearly pinpoints your mistake:

prog.cc:3:15: warning: implicit conversion changes signedness: 'unsigned int' to 'int' [-Wsign-conversion] int r = x % m; ~ ~~^~~ prog.cc:3:13: warning: implicit conversion changes signedness: 'int' to 'unsigned int' [-Wsign-conversion] int r = x % m; ^ ~ prog.cc:4:21: warning: operand of ? changes signedness: 'int' to 'unsigned int' [-Wsign-conversion] return r >= 0 ? r : r + m; ~~~~~~ ^ prog.cc:4:25: warning: implicit conversion changes signedness: 'int' to 'unsigned int' [-Wsign-conversion] return r >= 0 ? r : r + m; ^ ~ prog.cc:9:12: warning: implicit conversion changes signedness: 'unsigned int' to 'int' [-Wsign-conversion] return mod(-3, 11); ~~~~~~ ^~~~~~~~~~~

live example on wandbox

<hr />

When converted to unsigned int, -3 becomes 4294967293.

4294967293 % 11 is equal to 1.


See C11 6.5.5 (Multiplicative operators) /3:


The usual arithmetic conversions are performed on the operands.


The usual arithmetic conversions is defined by The relevant part is:


Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.


So in x % m, the x is first converted to unsigned int.

To avoid this behaviour you could use x % (int)m,although this will malfunction if m > INT_MAX. If you want to support m > INT_MAX and also negative x, you'll have to use slightly more complicated logic.


Others answers well explain OP had troubles as conversion of negative value to unsigned before the % operation did not yield expected results.

Below are solutions: one resorts to wider math (which may not always be available). The second is careful constructed to avoid any undefined behavior, (UB), implementation defined (ID) behavior or overflow using only int, unsigned math. It does not rely on 2's complement.

unsigned int mod_ref(int x, unsigned int m) { long long r = ((long long) x) % m; return (unsigned) (r >= 0 ? r : r + m); } unsigned int mod_c(int x, unsigned int m) { if (x >= 0) { return ((unsigned) x) % m; } unsigned negx_m1 = (unsigned) (-(x + 1)); return m - 1 - negx_m1 % m; }

A test driver

#include <limits.h> #include <stdio.h> #include <stdlib.h> void testm(int x, unsigned int m) { if (m) { unsigned r0 = mod_ref(x, m); unsigned r1 = mod_c(x, m); if (r0 != r1) { printf("%11d %10u --> %10u %10u\n", x, m, r0, r1); } } } int main() { int ti[] = {INT_MIN, INT_MIN + 1, INT_MIN / 2, -2, -1, 0, 1, 2, INT_MAX / 2, INT_MAX - 1, INT_MAX}; unsigned tu[] = {0, 1, 2, UINT_MAX / 2, UINT_MAX - 1, UINT_MAX}; for (unsigned i = 0; i < sizeof ti / sizeof *ti; i++) { for (unsigned u = 0; u < sizeof tu / sizeof *tu; u++) { testm(ti[i], tu[u]); } } for (unsigned i = 0; i < 1000u * 1000; i++) { int x = rand() % 100000000; if (rand() & 1) x = -x - 1; unsigned m = (unsigned) rand(); if (rand() & 1) m += INT_MAX + 1u; testm(x, m); } puts("done"); return 0; }



  • signed int modulo unsigned int produces nonsense results
  • signed int modulo unsigned int produces nonsense results
  • Allow the user to change CSS design elements with a dropdown menu?
  • Keen.io Dataviz to draw graph but keep getting error “Uncaught Requested parser does not exist”
  • Edittext keeps focus when keyboard up AND scrolling the listview
  • Resolving protected resources with Flying Saucer (ITextRenderer)
  • Neo4j Cypher WITH is required between CREATE and MATCH
  • Sql Alchemy cannot run inside a transaction block
  • Where is located the Unlocking Xib files option 'Reset Locking Control' (for 'Localiz
  • audio controll - backward , forward buttons - Java script
  • Tooltip on Hover of select box options generated by ng-options in Angularjs
  • How create observable with parameters in Angular 6?
  • Exception : The provider did not return a ProviderManifestToken string-Entityframework
  • How to tell if an error captured by my global.asax was displayed on the screen of the user
  • Textarea toolbar?
  • Synchronize two vobs on two different hosts
  • How do I restore console.log() function that has been disabled by a website? [duplicate]
  • Fade In circles in Google Maps
  • Show QMainwindow in the middle of the screen
  • CRM Dynamics How to set short list - long list relationship
  • BTYD (Buy 'Till You Die). Walkthrough. pnbd.EstimateParameters()
  • Tomcat Replacing VM arguments
  • how to limit a click event applied to the from executing on a jquery datatable in the body
  • Parse fasta sequence to the dictionary
  • how to ignore files when finishing private ClearCase branch?
  • Moving Circle on Live Wallpaper
  • Use Perl to Add GIF Image Other Than 8-bit to PDF
  • Project Euler -Prob. #20 (Lua)
  • Firebase suddenly reports invalid signature
  • Insert statement not working using execute(array()) of PDO Extension
  • Inet6Address valid for invalid IPv6 Address
  • Compiling and linking NASM and 64-bit C code together into a bootloader [duplicate]
  • Separating definition/instantiation of template classes without 'extern'
  • Create an average of multiple excel chart without the data source
  • how do i compare two rows and store the similarities of the two rows in another column
  • Create/delete users from text file using Bash script