I have a difficulty in implementing the tail recursive solution of the following problem:
There is another recursive relation for the double factorial, which also depends on the factorial, which is the above: (for n<20)
I have to implement a recursive relation of this equation- which I did as the above code that works:
long long factorial(int n) {
if (n < 0)
return 0;
if (n < 1)
return 1;
return n * factorial(n - 1);
}
long long doublefactorial(int n) {
if (n < 0)
return 0;
if (n < 2)
return 1;
return factorial(n) / doublefactorial(n - 1);
}
Now I have to implement the same problem using a tail recursion. can someone show me how to do this because I cant figure it out. (no need to implement the factorial function also in a tail recursive way)
test cases:
5!! = 15
10!! = 3840
18!! = 185,794,560
-10!! = 0
Here is a tail-recursive version of Factorial function:
long factorial(int n, int factor)
{
if (n == 0)
return factor;
return factorial(n-1, factor * n);
}
factorial(5, 1); // 120
Here's a tail-recursive double factorial with a simpler logic:
long doublefactorial(int n, int factor)
{
if (n < 0)
return 0;
if (n < 2)
return factor;
return doublefactorial(n-2, factor * n);
}
printf("%d ", doublefactorial(5,1)); // 15
printf("%d ", doublefactorial(10,1)); // 3840
printf("%d ", doublefactorial(18,1)); // 185794560
If you expand your math a little bit you'll get that the factorial function result is iterating between the numerator and the denominator of the final result.
so this code will do that in Python
def _factorial(n, m):
if n < 0:
return 0
elif n == 0:
return 1.0 * m
return _factorial(n - 1, n * m)
def factorial(n):
return _factorial(n, 1)
def _doublefactorial(n, m, is_even):
if n < 0:
return 0
elif n < 2:
return 1.0 * m
if is_even:
m *= factorial(n)
else:
m /= factorial(n)
return _doublefactorial(n - 1, m, (not is_even))
def doublefactorial(n):
return _doublefactorial(n, 1, True)
And in C:
unsigned int _factorial(const unsigned int n, const unsigned int m) {
if (n < 0) {
return 0;
} else if (n == 0) {
return m;
}
return _factorial(n - 1, n * m);
}
unsigned int factorial(const unsigned int n) {
return _factorial(n, 1);
}
double _doublefactorial(const unsigned int n, const double m, const char is_even) {
double value = m;
if (n < 0) {
return 0;
} else if (n < 2) {
return m;
}
if (is_even) {
value *= factorial(n);
} else {
value /= factorial(n);
}
return _doublefactorial(n - 1, value, !is_even);
}
double doublefactorial(const unsigned int n) {
return _doublefactorial(n, 1, 1);
}
Your definition of this double factorial function is incomplete: you need an initial value such as 0!! = 1. From the recurrence definition, it appears that p!! is the product of all numbers from 1 to p that have the same parity as p:
5!! = 1 * 3 * 5 = 15
6!! = 2 * 4 * 6 = 48
10!! = 2 * 4 * 6 * 8 * 10 = 3840
Computing the double factorial by computing the factorial and dividing by the result of the double factorial of the previous number will fail for numbers larger than 19 because of the limited range of integer types and the exponential growth of the factorial function. The double factorial grows quickly too, but its logarithm grows half as fast as that of the factorial function.
Here is an recursive function:
unsigned long long doublefactorial(int n) {
if (n < 0)
return 0;
if (n < 2)
return 1;
return n * doublefactorial(n - 2);
}
Here is a tail recursive implementation with a helper function:
unsigned long long doublefactorial_helper(int n, unsigned long long res) {
if (n < 2)
return res;
return doublefactorial(n - 2, res * n);
}
unsigned long long doublefactorial(int n) {
return doublefactorial_helper(n, n >= 0);
}
The trick to convert the first function to a tail recursive one is instead of waiting for the result and multiplying then by n, pass an updated intermediary result to the recursive function. The multiplications are performed in the opposite order but will produce the same result (even modulo ULLONG_MAX+1).
Related
long choose(int n, int k) {
if (k == 0 || k == n) {
return 1L;
} else {
long result = (choose(n-1, k) + choose(n-1, k-1));
return result;
}
}
This recursive function is very slow when using large numbers. How do I make it use memoization to make it faster?
You select a suitable data structure to store your results. In this case I capped the size of N and K and used an 2d array (note: choose() is a fast growing function so it may overflow in practice. ). If the result is cached return that, otherwise store the new calculation and return that.
#include <stdio.h>
#define MAX_N 100
#define MAX_K 100
long choose(int n, int k) {
if(n < 0 || n > MAX_N) {
printf("n should be between 0 and %d\n", MAX_N);
return -1;
}
if(k < 0 || k > MAX_K) {
printf("k should be between 0 and %d\n", MAX_K);
return -1;
}
if(n < k) {
printf("n should be greater or equal to k\n");
return -1;
}
if (k == 0 || k == n) {
return 1;
}
static long memorize[MAX_N+1][MAX_K+1];
return memorize[n][k] ?
memorize[n][k] :
(memorize[n][k] = choose(n-1, k) + choose(n-1, k-1));
}
int main(void) {
printf("%ld\n", choose(100, 6));
}
and example run:
1192052400
real 0m0.002s
user 0m0.002s
sys 0m0.000s
I was curious so here is a version that uses a dynamically allocate array. #autistic points out below mmap() and open_memstream() as alternatives, mmap() in particular can use file backed storage if you need more space than physical memory.
#include <stdio.h>
#include <stdlib.h>
long choose2(int n, int k, size_t k_len, long *memorize) {
if (k == 0 || k == n) {
return 1;
}
return memorize[n * k_len + k] ?
memorize[n * k_len + k] :
(memorize[n * k_len + k] = choose2(n-1, k, k_len, memorize) + choose2(n-1, k-1, k_len, memorize));
}
long choose(int n, int k) {
if(n < 0) {
printf("n must be greater than 0\n");
return -1;
}
if(k < 0) {
printf("k must be great than 0\n");
return -1;
}
if(n < k) {
printf("n should be greater or equal to k\n");
return -1;
}
long *memorize = calloc((n+1) * (k+1), sizeof(*memorize));
if(!memorize) {
printf("calloc failed\n");
return -1;
}
long result = choose2(n, k, k + 1, memorize);
free(memorize);
return result;
}
int main(void) {
printf("%ld\n", choose(100, 6));
}
It would be a little prettier if memorize was a vla long (*memorize)[k+1]; which would allow for a more natural memorize[n][k] syntax in choose2().
gcc, among others, support nested functions as an extension. It would be useful here so k_len and memorize would be accessible via the closure of the outer function instead of arguments.
// this is a recursive function for finding the sum of digits in C language
//I'm not getting any output in my IDE.
int dsum(int n)
{
int a, r;
r = n % 10;
a = r + dsum(n / 10);
return a;
}
int main()
{
int a;
a= dsum(12345);
printf("%d",a);
return 0;
}
A recursion function should always have a base case as a final return, in this case it's when n equals 0, which means all digits were summed (when msb digit is divided by 10 the result is 0).
Then you'll have the return which will call the function with the result of the current lsb digit (or right most digit) + the result of the function with the input of n/10
int dsum(int n)
{
if (n == 0) {
return 0;
}
return n % 10 + dsum(n / 10);
}
int main()
{
int a;
a = dsum(12345);
printf("%d",a);
return 0;
}
BTW, I also suggest looking into tail recursion:
https://en.wikipedia.org/wiki/Tail_call
In this scenario, it might look like that:
int dsum_tail_recursion(int n, int sum)
{
if (n == 0) {
return sum;
}
return dsum_tail_recursion(n/10, n%10 + sum)
}
int main()
{
int a;
a = dsum_tail_recursion(12345, 0); // 0 is the sum start value
printf("%d",a);
return 0;
}
I am trying to make a recursive function in C that calculates the sum of digits in 2ⁿ, where n < 10⁷. I made something that works, but it's very slow (for n = 10⁵ it takes 19 seconds). The function must return the sum in maximum 1 second. My algorithm calculates 2ⁿ using arrays to store its digits and it's not using a recursive function.
Is there any way to compute this sum of digits without calculating 2ⁿ? Or a faster way to calculate 2ⁿ and its digits sum?
P.S.: The recursive function must get only the n parameter, i.e. int f(int n);
Late edit: I wrote a recursive solution; it is faster, but it doesn't work for n > 10⁵.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int sumOfDigits(int* num, int n) {
if (n == 0) {
int sum = 0;
for (int i = 1; i <= num[0]; ++i) {
while (num[i] > 0) {
sum += num[i] % 10;
num[i] /= 10;
}
}
return sum;
}
int carry = 0;
for (int i = 1; i <= num[0]; ++i) {
num[i] = num[i] * 2 + carry;
carry = num[i] / 1000000000;
num[i] %= 1000000000;
if (carry != 0 && i == num[0]) {
++num[0];
}
}
return sumOfDigits(num, n - 1);
}
int main (void) {
int n = 100000;
int size = (n*log10(2) + 1) / 9 + 2;
int* num = calloc(size, sizeof(int));
num[0] = 1;
num[1] = 1;
printf("\n%d", sumOfDigits(num, n));
free(num);
return 0;
}
It seems that the posted code is using an "implicit" arbitrary precision type (with "digits" in the range [0, 999999999]) to recursively calculate all the multiplication by 2, which means, for e.g. n = 100, to perform 100 times those expansive calculation.
It should be more efficient (O(log(n)) instead of O(n)) to perform each time a multiplication of the number by itself or by 2, based on whether the exponent is even or odd. E.g. 27 = 2 * (23 * 23).
Another approach would be to explicitly implement a Bing Int type, but with a binary underlying type (say a uint32_t). It would be trivial to calculate 2n, it'd be just an array of zeroes with a final power of two (again, just one non-zero bit).
Now, to get the sum of the (base 10) digits you need to transform that number in base, say 100000000 (like the OP did), and to do that, you have to implement a long subtraction between two Big Ints and a long division by 100000000, which will give you the remainder too. Use that remainder to calculate the partial sum of the digits and iterate.
The following is a minimal implementation, testable here.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#define D_BASE 1000000
#define MSB_MASK 1 << 31
typedef struct
{
uint32_t size;
uint32_t capacity;
uint32_t *digits;
} BigInt;
void divide_bigint(BigInt *n, uint32_t x, uint32_t *remainder);
BigInt *make_bigint_of_two_raised_to(uint32_t n)
{
BigInt *p = malloc(sizeof *p);
if (!p)
{
perror("Fatal error");
exit(1);
}
uint32_t pos = n / 32;
uint32_t remainder = n % 32;
uint32_t capacity = (remainder == 31) ? pos + 2 : pos + 1;
uint32_t *pp = calloc(capacity, sizeof *pp);
if (!pp)
{
perror("Error initializing a Big Int as a power of two");
free(p);
exit(1);
}
p->capacity = capacity;
p->size = capacity;
pp[pos] = 1u << remainder;
p->digits = pp;
return p;
}
void free_bigint(BigInt **p);
uint64_t sum_of_digits_of_two_raised_to_the_power(uint32_t n)
{
BigInt *power_of_two = make_bigint_of_two_raised_to(n);
uint32_t remainder;
uint64_t sum = 0;
while (!(power_of_two->size == 1 && power_of_two->digits[0] == 0))
{
divide_bigint(power_of_two, 1000000000, &remainder);
while (remainder)
{
sum += remainder % 10;
remainder /= 10;
}
}
free_bigint(&power_of_two);
return sum;
}
void test(uint32_t n)
{
uint64_t sum = sum_of_digits_of_two_raised_to_the_power(n);
printf("Sum of digits of 2^%d: %" PRIu64 "\n", n, sum);
}
int main(void)
{
test(5);
test(10);
test(1000);
test(10000);
test(100000);
test(1000000);
return 0;
}
void shrink_size(BigInt *n)
{
while ( n->size > 1 )
{
if ( n->digits[n->size - 1] == 0 && !(n->digits[n->size - 2] & MSB_MASK) )
--n->size;
else
break;
}
}
void divide_bigint(BigInt *n, uint32_t x, uint32_t *remainder)
{
uint64_t carry = 0;
uint32_t i = n->size;
while ( i-- > 0 )
{
carry <<= 32;
carry += n->digits[i];
if ( carry < x )
{
n->digits[i] = 0;
continue;
}
uint64_t multiplier = (carry / x);
carry -= multiplier * x;
n->digits[i] = (uint32_t)multiplier;
}
shrink_size(n);
*remainder = carry;
}
void free_bigint(BigInt **p)
{
if (p && *p)
{
free((*p)->digits);
free(*p);
*p = NULL;
}
}
2^8 = (2 * 2 * 2 * 2 * 2 * 2 * 2 * 2) = (2 * 2 * 2 * 2) * (2 * 2 * 2 * 2) = (2 * 2 * 2 * 2)^2 = ((2 * 2) * (2 * 2))^2 = ((2 * 2)^2)^2 = ((2^2)^2)^2
So, first you need to calculate log(2, n), to see how you can calculate effectively. If log(2, n) is an integer, then you can simply calculate the square of the square of the ... of the square with very few operations. If log(2, n) is not an integer, then calculate 2^((int)log(2, n)) and thus you will very effectively do a partial calculation and then do the same for the remainder until there is no longer remainder.
Unify your partial results into a number (possibly represented by an array) and calculate the sum of the digits. Calculating the sum of the digits is straight-forward. The actual calculation of the 2^n is what takes the most time.
If you do not reach the limits of a number format, then you can think about shift left, but with the domain you work with this is not really an option.
I have an assigment to create a function that recieves a number, and return the reversed number.
E.G :
Input : 12343
Output : 34321
No loops allowed, and the input is only the number .
This is what I've tried :
long GetReverse(unsigned long n)
{
if (n < 10)
return n % 10;
else
return 10 * GetReverse(n / 10) + n % 10;
}
Though This is retuning me the same input and not reversing the number ( I know what is the problem here, I just can't think of a way to do it)
Any thoughts?
EDIT: This is the solution I came up with :
int numOfMulti(unsigned long num) {
if (num < 10)
return 1;
return 10 * numOfMulti(num / 10);
}
long GetReverse(unsigned long n)
{
if (n < 10)
return n % 10;
else
return n % 10 * numOfMulti(n) + GetReverse(n / 10) ;
}
Wasn't able to find a solution without a secondary function or static variables.
It's easy. Please try my solution. NO LOOPS, ONE PARAMETER.
long GetReverse(unsigned long n)
{
static unsigned long m = 0;
static int recursive_level = 0;
recursive_level++;
if (n < 10) {
recursive_level--;
m = m * 10 + n;
int temp = m;
if (recursive_level == 0) {
m = 0;
}
return temp;
}
m = m * 10 + (n % 10);
GetReverse(n / 10);
recursive_level--;
int temp = m;
if (recursive_level == 0) {
m = 0;
}
return temp;
}
You will need to pass 2 elements to the GetReverse function, because the last digit will have to be shifted on the left:
long GetReverse(unsigned long n, unsigned long m)
{
if (n < 10)
return 10 * m + n;
else
return GetReverse(n / 10, 10 * m + n % 10);
}
You can then call GetReverse(12343, 0) and get as expected 34321
This is silly and should not be used in real life, but complies with the requirements:
unsigned long GetReverse(unsigned long n)
{
if (n < 10)
return n;
else
return n % 10 * lround(pow(10,floor(log10(n)))) + GetReverse(n / 10);
}
Here's a solution that only takes one parameter, although you can only use the least significant 32 bits for your input:
uint64_t rev(uint64_t n)
{
uint32_t _n = n;
uint32_t _m = n >> 32;
return _n < 10
? 10 * _m + _n
: rev(_n / 10 + (uint64_t)(10 * _m + _n % 10) * 65536 * 65536)
;
}
int main(){
uint32_t n = 12345;
n = rev(n);
}
Essentially the coefficient is stored in the higher order bits of n. In many ways this is a terrible contrivance since all I'm doing is using a single parameter where there should be two parameters, and I'm relying on a (well-defined) narrowing unsigned conversion at the call site! But it does show the elegance of using the fixed width unsigned types.
How about this?
#include <stdio.h>
#include <math.h>
long GetReverse(unsigned long n){
if (n < 10){
return n;
} else {
unsigned long r = GetReverse(n / 10);
int p = snprintf(NULL, 0, "%lu", r);
return lround(pow(10, p)) * (n % 10) + r;
}
}
int main(void){
unsigned long n = 112233445566778899;
printf("%lu", GetReverse(n));
return 0;
}
To place the last digit first you need to multiply it by 10 once for each digit in the number:
#include <math.h>
long GetReverse(unsigned long n)
{
if (n < 10)
return n; // Removed the % 10 as it is not needed when n is < 10
else {
long digit = n%10;
long factor = (long) pow(10, (int)log(n));
return digit * factor + GetReverse(n / 10);
}
}
log and pow is used instead of loops to calculate the number of digits in n. Note that this may fail unless the implementation of pow is good enough. I did a test using gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16) and that combination produced correct results for integer powers of 10 for results that fit in a long.
No loops, no variables, no additional parameters!
#include <stdio.h>
unsigned long reverse(unsigned long num)
{
if (num < 10) return num;
if (num < 100) return 10 * (num %10) + reverse(num/10);
if (num < 1000) return 100 * (num %10) + reverse(num/10);
if (num < 10000) return 1000 * (num %10) + reverse(num/10);
if (num < 100000) return 10000 * (num %10) + reverse(num/10);
if (num < 1000000) return 100000 * (num %10) + reverse(num/10);
if (num < 10000000) return 1000000 * (num %10) + reverse(num/10);
if (num < 100000000) return 10000000 * (num %10) + reverse(num/10);
return 100000000 * (num %10) + reverse(num/10);
}
int main(int argc, char **argv)
{
unsigned long num, rev;
if (argc < 2) return 1;
sscanf(argv[1], "%lu", &num);
rev = reverse(num);
printf("%lu -->> %lu\n", num, rev );
return 0;
}
Or, using a helper function (not a variable)
[note: this has quadratic complexity(on the number of digits)]
unsigned long tencount(unsigned long num)
{
if (num < 10) return 1;
return 10 * tencount( num/10);
}
unsigned long reverse2(unsigned long num)
{
if (num < 10) return num;
return tencount(num) * (num %10) + reverse2(num/10);
}
Assuming a 32bit long you could do it without loops or recursion;
long GetReverse(unsigned long n)
{
unsigned long x = ((n/1000000000) +
((n/100000000)%10)*10 +
((n/10000000)%10)*100 +
((n/1000000)%10)*1000 +
((n/100000)%10)*10000 +
((n/10000)%10)*100000 +
((n/1000)%10)*1000000 +
((n/100)%10)*10000000 +
((n/10)%10)*100000000 +
((n)%10)*1000000000);
return (x/(9*(x%10==0)+1)/
(9*(x%100==0)+1)/
(9*(x%1000==0)+1)/
(9*(x%10000==0)+1)/
(9*(x%100000==0)+1)/
(9*(x%1000000==0)+1)/
(9*(x%10000000==0)+1)/
(9*(x%100000000==0)+1)/
(9*(x%1000000000==0)+1));
}
This is a solution:
int reverse(int i) {
static int p = 0;
if (i==0) { int r = p; p = 0; return r; }
p = 10*p+i%10;
return reverse(i/10);
}
Idea is to use a second argument, but as it is used only to store the partial result a static variable can be used. To be able to reuse the function you just need to reset the static at the end of the recursion.
Becareful as such a function is not an involution means that reverse(reverse(x)) not equals to x, think about x=1000. If you want involution then you need to define it over a C-string that represent the value.
C reverse a number recursively
I have an assignment to create a function that receives a number and return the reversed number.
No loops allowed, and the input is only the number .
Add a helper recursive function. #Art
No static variable, no floating point math needed.
The below meets the goals:
1) Recursion used.
2) Function receives a number and return the reversed number
3) No loops allowed, and the input is only the number
#include <stdio.h>
#include <stdlib.h>
static unsigned reverse_helper(unsigned x, unsigned *pow10) {
if (x < 10) {
*pow10 = 10;
return x;
}
unsigned y = reverse_helper(x / 10, pow10);
y += *pow10 * (x%10);
*pow10 *= 10;
return y;
}
unsigned reverse(unsigned x) {
unsigned pow10 = 1;
unsigned y = reverse_helper(x, &pow10);
printf("%10u %10u\n", x, y);
return y;
}
int main(void) {
reverse(0);
reverse(9);
reverse(10);
reverse(99);
reverse(100);
reverse(1234);
reverse(123456789);
}
Output
0 0
1 1
9 9
10 1
99 99
100 1
1234 4321
123456789 987654321
A solution like OP's yet uses 2 recursive functions.
Recurse function with 1 parameter, no floating-point, no static variables.
// return the great power-of-10 less than n
unsigned long p10(unsigned long n) {
if (n < 10) {
return 1;
}
return p10(n/10) * 10;
}
unsigned long GetReverse(unsigned long n) {
if (n < 10) {
return n;
}
// OPs code
//return 10 * GetReverse(n / 10) + n % 10;
// v----------------v------------------- scale by 1
// | | v-----------v--- scale by a power of 10 <= n
return GetReverse(n / 10) + p10(n)*(n%10);
}
What about calling a function like char* getReverse(int n) So you could use mod and concatenation to obtain the reverse. Then in the caller method int getReverse(int n) you parse the string to int. You could use recursion and then the single line to make the parsing. No loops needed and one parameter.
Here's my completely reentrant version, with no extra variable. It works by using ldiv( num / 10 ) to get quotient and remainder, then returns the remainder multiplied by 10^(num digits in quotient) added to the reverse of the quotient (code is formatted to remove the scroll bar - normally I'd have blank lines and more braces):
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
/* unsigned long power function */
unsigned long lpow( unsigned long base, unsigned long exp )
{
unsigned long result = 1UL;
while ( exp )
{
if ( exp & 1 )
result *= base;
exp >>= 1;
base *= base;
}
return( result );
}
/* count the number of decimal digits */
unsigned long numdigits( unsigned long num )
{
return( floor( log10( num ) ) + 1 );
}
unsigned long reverse( unsigned long in )
{
ldiv_t tmp = ldiv( in, 10UL );
if ( tmp.quot == 0 )
return( tmp.rem );
return( reverse( tmp.quot ) + tmp.rem * lpow( 10, numdigits( tmp.quot ) ) );
}
unsigned long lpow() function from https://stackoverflow.com/a/101613/4756299
unsigned long numdigits() function from https://stackoverflow.com/a/1068870/4756299
Called like this:
int main( int argc, char **argv )
{
for ( int ii = 1; ii < argc; ii++ )
{
unsigned long num = strtoul( argv[ ii ], NULL, 10 );
printf( "Reverse of %lu is %lu\n", num, reverse( num ) );
}
return( 0 );
}
For starters it is unclear why the return type is declared like long while the parameter has the type unsigned long.
long GetReverse(unsigned long n);
^^^^ ^^^^^^^^^^^^^
To have a more large of integers it is better to declare the parameter and the return type like unsigned long long int.
The function can be defined by using a local static variable that will keep the calculated reversed value.
Here it is.
unsigned long long int GetReverse(unsigned long long int n)
{
const unsigned long long int Base = 10;
static unsigned long long int reversed;
unsigned long long int tmp;
reversed = Base * reversed + n % Base;
return (n /= Base ) == 0 ? tmp = reversed, reversed = n, n = tmp, n
: GetReverse(n);
}
In the demonstrative program below there is shown how the function works.
#include <stdio.h>
unsigned long long int GetReverse(unsigned long long int n)
{
const unsigned long long int Base = 10;
static unsigned long long int reversed;
unsigned long long int tmp;
reversed = Base * reversed + n % Base;
return (n /= Base ) == 0 ? tmp = reversed, reversed = n, n = tmp, n
: GetReverse(n);
}
int main(void)
{
const unsigned long long int Base = 10;
for ( unsigned long long int i = 1, n = 0; i < Base; i++ )
{
n = Base * n + i;
printf( "%llu\n", n );
printf( "%llu\n", GetReverse( n ) );
putchar( '\n' );
}
return 0;
}
The program output is
1
1
12
21
123
321
1234
4321
12345
54321
123456
654321
1234567
7654321
12345678
87654321
123456789
987654321
I got a modular exponentiation function in C which looks like this.
int modexp(int m, int e, int n)
{
printf("%i\n", m);
printf("%i\n", e);
printf("%i\n", n);
printf("\n");
if(e == 0)
{
return 1;
}
if(e%2 == 1)
{
return modexp(m, e-1, n) * m%n;
}
else
{
int modTemp = modexp(m, (int)(e/2), n);
modTemp = modTemp * modTemp;
return modTemp % n;
}
}
which I am calling in my main() function like this
int p = 3511;
printf("%i\n", modexp(2, p-1, p*p));
When printing the values for m, e and n I get the correct recursion values up to e = 0 in the end. This is when the function should return 1. It definitely returns at that position in the code, however instead of the expected integer 1, I get -6593454 and I have no idea why.
The full code can be found here:
https://gist.github.com/anonymous/7024ac77b2432a381968
any input is highly appreciated...
Multipying an n-bit value with an m-bit value produces a (n+m)-bit result. That's why modexp(m, e-1, n) * m and modTemp * modTemp overflow. You need a widening multiplication to get the full 64-bit result from 32-bit values
return ((int64_t)modexp(m, e-1, n) * m) % n;
...
int64_t modTemp = modexp(m, (int)(e/2), n);
modTemp = modTemp * modTemp;
return modTemp % n;
1 is indeed returned when e == 0, but this return value is a term in the calculations made on previous levels of recursion. If you modify your code like this:
#include <stdio.h>
int modexp(int m, int e, int n)
{
printf("%i\n", m);
printf("%i\n", e);
printf("%i\n", n);
printf("\n");
if(e == 0)
{
printf("returning 1\n");
return 1;
}
if(e%2 == 1)
{
int tmp=modexp(m, e-1, n) * m%n;
printf("returning %d\n",tmp);
return tmp;
}
else
{
int modTemp = modexp(m, (int)(e/2), n);
modTemp = modTemp * modTemp;
modTemp= modTemp % n;
printf("returning %d\n",modTemp);
return modTemp;;
}
}
int main(){
int p = 3511;
printf("%d\n", modexp(2, p-1, p*p));
return 0;
}
You will get this output at the end:
returning 1
returning 2
returning 4
returning 8
returning 64
returning 4096
returning 8192
returning 5473259
returning 10946518
returning 2217782
returning 5855618
returning 11711236
returning 8916378
returning 5505635
returning -1026672
returning 975519
returning 1951038
returning 195330
returning 390660
returning -6593454
-6593454
This shows that the 1 returned for e == 0 is used for further calculations.
At some point your code overflows int, that's why you get a negative number at the end. You should probably use a longer type.
I agree it's an overflow of the modTemp variable. However, for clarity, I'd suggest to only change the type of modTemp from Int to long, and change m/e/n with b/e/m like the following:
#include <stdio.h>
int modexp(int b, int e, int m); // b: base; e: exp; m: modulus
int main()
{
int p = 3511; // given number p
printf("%i\n", modexp(2, p-1, p*p)); // last line printed is the remainder of mod exp
}
int modexp(int b, int e, int m)
{
printf("%i\n", b);
printf("%i\n", e);
printf("%i\n", m);
printf("\n");
if(e == 0)
{
return 1;
}
if(e%2 == 1)
{
return modexp(b, e-1, m) * b%m;
}
else
{
long modTemp = modexp(b, (int)(e/2), m); // !!here modTemp is declared as long!!
modTemp = modTemp * modTemp;
return modTemp % m;
}
}
Your numbers are overflowing. They are most likely 32 or 64-bit signed integers here, which means the maximum size can be 231=2147483648 or 263 = 9223372036854775807. Just look at the size of the modexp(...) multiplied by m%n. That's quite a large number :)
The same goes for modTemp * modTemp