cunsigned-long-long-int

Finding the last 10 digits of 2^n


So i'm supposed to find out the last 10 digits of 2^n(0<=n<=100) where n is the input. I found a method to handle large numbers but the program fails when n>64. Any leads on how to go about with this would be appreciated.

#include<stdio.h>
#include<math.h>


/* Iterative Function to calculate (x^y)%p in O(log y) */
int power(long long int x, long long int y, long long int p)
{
long long int res = 1; // Initialize result

x = x % p; // Update x if it is more than or
// equal to p

while (y > 0) {

    // If y is odd, multiply x with result
    if (y & 1)
        res = (res * x) % p;

    // y must be even now
    y = y >> 1; // y = y/2
    x = (x * x) % p;
}
return res;
}

// C function to print last 10 digits of a^b
void printLastDigits(long long int a,long long int b)
{    

long long int temp = pow(10,10);

// Calling modular exponentiation
temp = power(a, b, temp);

if (temp)
    printf("%d",temp);
}

int main()
{
long long int n;
scanf("%d",&n);
printLastDigits(2,n);
return 0;
}

Solution

  • You don't need to worry about the 'high' bits, since multiplication by 2 left shifts them out of range of the lower part of the product you're interesting in. Just be sure you're using the unsigned long long type (of at least 64 bits) to hold integral types that are wide enough, e.g.,

    #include <inttypes.h>
    #include <stdio.h>
    
    void low_digits (unsigned int n)
    {
        unsigned long long base = 2, modulus = 10000000000ULL;
    
        for (unsigned int i = 1; i <= n; i++)
        {
            fprintf(stdout, "2^%u mod 10^10 = %llu\n", i, base);
            base = (base * 2) % modulus;
        }
    }
    

    You can test 2^1000 with a bignum calculator:

    10715086071862673209484250490600018105614048117055336074437503883703\ 51051124936122493198378815695858127594672917553146825187145285692314\ 04359845775746985748039345677748242309854210746050623711418779541821\ 53046474983581941267398767559165543946077062914571196477686542167660\ 429831652624386837205668069376

    while n = 1000 above yields: 5668069376


    Others have noted, that this is a naive method, and modular exponentiation is far more efficient for sufficiently large values of (n). Unfortunately, this is going to require products that exceed the range of an unsigned 64-bit value, so unless you're prepared to implement [hi64][lo64] multi-precision mul / mod operations, it's probably beyond the scope of your task.

    Fortunately, later versions of gcc and clang do provide an extended 128 bit integral type:

    #include <inttypes.h>
    #include <stdio.h>
    
    void low_digits (unsigned int n)
    {
        unsigned long long base = 2, modulus = 10000000000ULL;
        __extension__ unsigned __int128 u = 1, w = base;
    
        while (n != 0)
        {
            if ((n & 0x1) != 0)
                u = (u * w) % modulus; /* (mul-reduce) */
    
            if ((n >>= 1) != 0)
                w = (w * w) % modulus; /* (sqr-reduce) */
        }
    
        base = (unsigned long long) u;
        fprintf(stdout, "2^%u mod 10^10 = %llu\n", n, base);
    }