Finding modulus with very large exponentiation and divisor in C - c

I need a function in C that calculates a^n mod q, where the divisor q is determined to be very big (15,383,399,235,709,406,497) and the exponent n may also be as large as that.
Based on the property of modulo multiplication, that (a * b) mod n = ((a mod n) * (b mod n)) mod n, my attempt is as follows:
#include <stdio.h>
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
unsigned long long int cnt;
for (cnt=expo; cnt>0; cnt--)
{
out = (out * base) % mod;
}
return out;
}
int main()
{
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
return 0;
}
As seen in the main function above, I tested my function modExp with base 3, exponent (189 + 50 * 223), and divisor 15383399235709406497. It gave the output 3915400295876975163 with some warnings that
In function ‘findxA’:
findxA.c:17:32: warning: integer constant is so large that it is unsigned [enabled by default]
unsigned long long int h = 12036625823877237123;
^
findxA.c:17:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
unsigned long long int h = 12036625823877237123;
^
findxA.c:18:32: warning: integer constant is so large that it is unsigned [enabled by default]
unsigned long long int q = 15383399235709406497;
^
findxA.c:18:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
unsigned long long int q = 15383399235709406497;
^
findxA.c: In function ‘main’:
findxA.c:34:48: warning: integer constant is so large that it is unsigned [enabled by default]
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
^
findxA.c:34:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
^
To verify this answer, I compared the result (given by the C function) with the output given by evaluating the expression 3^(189 + 50 * 223) `mod` 15383399235709406497, written in Haskell. This Haskell expression evaluated to a different decimal, 12349118475990906085. I think it is my C function that is wrong, since I believe Haskell does a better job at handling such large decimals.
How can I improve my C function, modExp?
Edit: I have tried the option of the first answer of this question. However, as I am trying to deal with the decimal of unsigned long long int, I have switched every input and return types from int to unsigned long long int. This resulted in a Segmentation fault.
Edit2: I have used the function described on the above link in a wrong way. It does not give Segmentation fault; but it still does not output the correct decimal.

To reduce the chance of overflow, you can rely on (x*y)%z == ((x%z) * (y%z)) % z.
For example (untested):
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int baseMod = base%mod;
unsigned long long int out = 1;
unsigned long long int cnt;
for (cnt=expo; cnt>0; cnt--)
{
out = ( (out%mod) * baseMod) % mod;
}
return out;
}
Also note that exponentiation can be done more efficiently as "product of squares". For example, x ** 5 == 1*(x**4) * 0*(x**2) * 1*(x**1) because 5 == 1*4 + 0*2 + 1*1 (or 5 == 101b).
For example (untested):
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
unsigned long long int temp = base%mod;
while(exp0 > 0) {
if( (exp0 & 1) != 0) {
out = (out * temp) % mod;
}
temp = (temp*temp) % mod;
exp0 >>= 1;
}
return out;
}
For large exponents this should make a huge difference in performance (e.g. if the exponent is 123456 then the loop would have 17 iterations instead of 123456 iterations).
Also; if this is for some kind of cryptography (not unlikely); then you should state that clearly because you will probably want "constant time" (to reduce the chance of timing side-channels - e.g. inferring information about the exponent from how much time modExp() takes to execute).
Finally; even with the changes, numbers up to 15,383,399,235,709,406,497 are probably too large for unsigned long long (you'd need to ensure mod * mod <= ULLONG_MAX); which means that you'll probably need to use/implement "big integer" operations (e.g. maybe a typedef struct { uint32_t digit[4]; } MY_NUMBER_TYPE thing to handle 128-bit integers, with functions for multiplication and modulo).

This will never work this way!
This result of the multiplication here alone
out = (out * base) % mod;
needs potentially more than the 64 bit of the underlying data type. And if an integer overflow occurs (ie, the most significant bits get cut off), the mod operation turns out wrong!
Use larger data types, or use a different approach :-)
If you like, btw, please use this test code to see that there is actually an integer overflow occuring TWICE with your inputs:
#include <stdio.h>
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
while(expo>0)
{
if(expo % 2 == 1)
out = (out * base) % mod;
expo = expo >> 1;
if (base * base < base) printf("WARNING! INTEGER OVERFLOW!!!!\n");
base = (base * base) % mod;
}
return out;
}
int main()
{
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
return 0;
}

Related

A C left shift anomaly in unsigned long long ints

When this code:
// Print out the powers of 2 from 1 to 63.
#include <stdio.h>
int main() {
unsigned long long n = 64;
for (unsigned long long i = 1; i < n; i++) {
unsigned long long po2 = (1 << i);
printf("%llu) %llu/%0llX\n", i, po2, po2);
}
printf("Size of unsigned long long int: %ld.\n", sizeof(unsigned long long int));
}
is run, left shift values up to 30 are correct:
1) 2/2
2) 4/4
3) 8/8
...
28) 268435456/10000000
29) 536870912/20000000
30) 1073741824/40000000
However, once i == 31 (a 32 bit left shift), the results are not correct:
31) 18446744071562067968/FFFFFFFF80000000
32) 1/1
33) 2/2
34) 4/4
35) 8/8
36) 16/10
37) 32/20
...
61) 536870912/20000000
62) 1073741824/40000000
63) 18446744071562067968/FFFFFFFF80000000
Size of unsigned long long int: 8.
This is run on a 64 bit machine, and the C Standard states:
The integer promotions are performed on each of the operands. The type
of the result is that of the promoted left operand. If the value of
the right operand is negative or is greater than or equal to the width
of the promoted left operand, the behavior is undefined.
Note that the variables, i and n, in the above code are both 64 bit integers, yet they are treated as if they were 32 bit integers!
Look at the << operation in the following line:
unsigned long long po2 = (1 << i);
What is its left operand? Well, that is the int literal, 1, and an int type will not undergo promotion, in that context1. So, the type of the result will be int, as specified in the extract from the Standard that you cited, and that int result will be converted to the required unsigned long long type … but after the overflow (undefined behaviour) has already happened.
To fix the issue, make that literal an unsigned long long, using the uLL suffix:
unsigned long long po2 = (1uLL << i);
1 Some clarity on the "context" from this cppreference page (bold emphasis mine):
Shift Operators
…
First, integer promotions are performed, individually, on each operand (Note: this is unlike
other binary arithmetic operators, which all perform usual arithmetic
conversions). The type of the result is the type of lhs after
promotion.
Adrian Mole is correct. The revised code:
// Print out the powers of 2 from 1 to 63.
#include <stdio.h>
int main() {
unsigned long long n = 64,
one = 1;
for (unsigned long long i = 1; i < n; i++) {
unsigned long long po2 = (one << i);
printf("%llu) %llu/%0llX\n", i, po2, po2);
}
printf("Size of unsigned long long int: %ld.\n", sizeof(unsigned long long int));
}
works.

Modulus operator returning quotient instead of remainder

I am currenly attempting to implement a basic pairing function in c. The pairing function will take in 2 unsigned integers and output a single unsigned long value. In order to unpair the result and retrieve the original values, the modulus operator must be used. But for some reason the modulues operator is returning the quotient and not the remainder like it is supposed to.
Here is the code:
unsigned long pair(unsigned int x, unsigned int y)
{
return (unsigned long)UINT_MAX * y + x;
}
unsigned int depair_x(unsigned long z)
{
return (unsigned int)(z % UINT_MAX);
}
unsigned int depair_y(unsigned long z)
{
return (unsigned int)(z / UINT_MAX);
}
A good example is that when I input the values 1058242433 and 1063370847 I get the result 4567143011379691298. However the result of the modulus operator is roughly 1063370847, which is incorrect (feel free to check it). However that result is the quotient. What is happening here?
Looks like "off-by-1".
In order to achieve "to unpair the result and retrieve the original values" a scale of UINT_MAX + 1UL is needed, not UINT_MAX.
// return (unsigned long)UINT_MAX * y + x;
return (UINT_MAX + 1UL)* y + x;
//return (unsigned int)(z % UINT_MAX);
return (unsigned int)(z % (UINT_MAX + 1ul));
// Likewise for `/`
If unsigned long has same range as unsigned, look to using unsigned long long instead of unsigned long.

Multiplication and Division unsigned integers

In my program , I have to perform arithmetic operations on unsigned integers.
The variable a has a range from 0 to 4294967295.
The variable b has a range from 0 to 32.
When I check the boundary condition by taking the maximun values for a and b,I am getting 0 as the answer since overflow occurs when I try to multiply a and MAX_NS.Ideally I should get 7 as the answer.How could I write the program such that overflow is taken care of and I get 7 as the answer and hopefully it works for other valid value range for a and b.Thanks.
#include "stdio.h"
#define MAX_NS 1000000000
int main()
{
unsigned int a = 4294967295;
unsigned int b = 32 ;
unsigned int c = ((b * MAX_NS)/a);
printf("%d",c);
}
**Edit:**Please note that I can't use unsigned long long.I can use only unsigned int for the variables.
Here is solution as Weather Vane suggested
#include "stdio.h"
#define MAX_NS 1000000000
int main()
{
unsigned long long a = 4294967295;
unsigned long long b = 32;
unsigned long long c = ((b * MAX_NS) / a);
printf("%llu", c);
}
The key is that the product b * MAX_NS must be computed using wide enough math.
Make certain at least one of the * operands is unsigned long long.
With large enough b and small enough a, the quotient will need a wider type to avoid overflow;
#include "stdio.h"
// #define MAX_NS 1000000000
#define MAX_NS 1000000000LLU
int main(void) {
unsigned int a = 4294967295; // type may remain unsigned
unsigned int b = 32 ; // type may remain unsigned
unsigned long long c = ((b * MAX_NS)/a);
printf("%llu",c);
}
Alternatively, coax the multiplication gently by multiplying by 1ull. In general avoid casting as in (unsigned long long) b * MAX_NS. Rampant practice of casting surprisingly sometimes narrows the math which could happen here at a later date with uintmax_t b.
#define MAX_NS 1000000000
int main(void) {
unsigned int a = 4294967295; // type may remain unsigned
unsigned int b = 32 ; // type may remain unsigned
unsigned long long c = ((1ull * b * MAX_NS)/a);
printf("%llu",c);
}

pow() function weird behavior when used in brackets and with long long integer

I found something weird.
This function puts a digit in a number at the given spot and returns the modified number.
Now we want to do put_digit(123456789123456784, 0, 9);
That will put 9 at the end of the number, replacing the last number (4).
This is the code that WORKS:
long long int put_digit(long long int number, char place, char digit)
{
long long int result = number;
long long int power = number;
power = pow(10, (place));
result -= get_digit(number, place)*power;
result += digit*pow(10, (place));
return result;
}
The code returns 123456789123456789
This is the code that DOES NOT WORK:
long long int put_digit(long long int number, char place, char digit)
{
long long int result = number;
result -= get_digit(number, place)*pow(10, (place));
result += digit*pow(10, (place));
return result;
}
This code returns 123456789123456800 as the result.
The functions get_digit() returns the digit from the number in the given place.
This is it's code:
char get_digit(long long int number, char place)
{
long long int target = number;
char digit = 0;
target /= pow(10, place);
digit = target % 10;
return digit;
}
• This does not happen with lower numbers.
• get_digit() always returns the correct value (4 in this case).
• get_digit() is a char because this is not a counter function, and thus it is better to focus on using less memory rather than using a faster variable like int.
• I've tried using brackets to avoid troublesome operator precedence, but to no avail.
• A weird behavior is also observed when doing put_digit(123456789123456000, 2, 7), which for some reason returns 123456789123456704. This is solved by replacing the pow function in the second result calculation with the variable "power".
I just don't understand why this is happening.
Am I getting some kind of an overflow? Is it my system's fault or my own? Am I using pow() in a bad way?
The declaration of pow() is: double pow( double base, double exponent );
In the first case:
long long int power = number;
power = pow(10, (place));
the value returned by pow() is converted to long long int when it is assigned power. The rest of the computation is processed using integer numbers and the result is the one you expect.
On the second case:
result -= get_digit(number, place)*pow(10, (place));
the value returned by get_digit(number, place) is converted to double because it needs to be multiplied with a floating point number (returned by pow()). Also, the value of result is converted to double before subtracting the result of the multiplication. In the end, the computed value is converted from double to long long int to be stored in result.
But starting on some magnitude, the floating point numbers lose the precision of their least significant digit(s).
Try this simple piece of code to see for yourself:
long long int i = 123456789123456785;
for (; i <= 123456789123456795; i ++) {
printf("long long int: %lld; double: %f\n", i, (double)i);
}
It outputs:
long long int: 123456789123456785; double: 123456789123456784.000000
long long int: 123456789123456786; double: 123456789123456784.000000
long long int: 123456789123456787; double: 123456789123456784.000000
long long int: 123456789123456788; double: 123456789123456784.000000
long long int: 123456789123456789; double: 123456789123456784.000000
long long int: 123456789123456790; double: 123456789123456784.000000
long long int: 123456789123456791; double: 123456789123456784.000000
long long int: 123456789123456792; double: 123456789123456800.000000
long long int: 123456789123456793; double: 123456789123456800.000000
long long int: 123456789123456794; double: 123456789123456800.000000
long long int: 123456789123456795; double: 123456789123456800.000000
This behaviour is not a bug but a limitation of the floating point numbers.
The solution for your code is to convert the value returned by pow(10, place) to long long int as soon as it returns:
result -= get_digit(number, place)*(long long int)pow(10, place);

int divided by unsigned int causing rollover

I try to divide int by unsigned int and I get unexpected result:
int b;
unsigned int c;
int res;
float res_f;
b = -25;
c = 5;
res = b / c; // res = 858993454
res_f = b / c; // res_f = -5.000000
The same works just fine for '+', '-' and '*', but fails for '/'. What is it that I miss here?
P.S.
It was tested on different compilers and the result was the same.
Assuming this is C or similar (e.g. Objective C), change:
res = b / c;
to:
res = b / (int)c;
Explanation: b is being converted from int to unsigned int, according to C's type conversion rules for mixed expressions. In the process it overflows from -25 to 0xFFFFFFE7 == 4294967271. Then you get an unsigned int result of 4294967271 / 5U = 858993454U, which is then being implicitly converted back to an int (no overflow in this step, as the result is in the range of both signed and unsigned 32-bit ints).
By the way, the float result should be the same, within the precision limits of a float (I get 858993472.0). I'm surprised that you get -5.0 in this case.

Resources