0

I implemented the exponential by squaring in java. And copied from net, a C code for the same. But the problem is, these codes are giving different outputs.

The input i am giving is: 2 as base and 999999999 and 1000000000 as powers.

here is my java code:

long power(int b,int i){
    long num;
    if(i==1)
        return b;
    else if(i%2==0){
        num=(long)Math.pow(power(b,i/2),2);
        if(num>=1000000007)
            num%=1000000007;
        return num;
    }
    else{
        num=b*(long)Math.pow(power(b,(i-1)/2),2);
        if(num>=1000000007)
            num%=1000000007;
        return num;
    }
}

output: 646458262 178281319

here is the C code i got from net:

long long int fast_exp(int base, int exp)
{
    if(exp==1)
    return base;
    else
    {
        if(exp%2 == 0)
        {
            long long int base1 = pow(fast_exp(base, exp/2),2);
            if(base1 >= 1000000007)
            return base1%1000000007;
            else
            return base1;
        }
        else
        {
            long long int ans = (base*  pow(fast_exp(base,(exp-1)/2),2));
            if(ans >= 1000000007)
            return ans%1000000007;
            else
            return ans;
        }
    }
}

output: 646458006 477022294

nishantbhardwaj2002
  • 757
  • 2
  • 6
  • 18
  • A comment: The only difference between two branches of the `% 2` condition is that in one you multiply `num` with `b`, and in the other one you don't. `(i - 1)/2` is same as `i/2` in that case, because `i` is odd. So, the code would be more compact if you had just that line in your conditional blocks, kept the rest outside. You may also use a ternary operation like `num = (long) Math.pow(power(b, i/2), 2) * (i%2 ? b : 1);` or something. – Utkan Gezer Jul 30 '14 at 07:59
  • 2
    I would advice to convert the code at first with minimum changes, meaning use the same variable name, the same structure if possible and when you have the same results, you can modify it to your taste. – Eypros Jul 30 '14 at 08:13
  • 1
    Do your own integer multiplication instead of using the library pow. It's easy to prove that neither of your functions is correct. `2^999999999 * 2 = 2^1000000000`, so `(fast_exp(2,999999999) * 2) % 1000000007` should be equal to `fast_exp(2, 1000000000)`. – T.C. Jul 30 '14 at 08:56
  • using `Math.pow` can make the result totally different (especially for large value of `base` and `exp`). Notice that the function in C is pow and modulus combined, if you use Math.pow directly,all calculations using modulus will be skipped, which can lead to number overflow. – Pham Trung Jul 30 '14 at 08:59

3 Answers3

4

Don't use floating point numbers and functions that use them (including pow/std::pow in C/C++ or Math.pow in Java) for integer math. It doesn't do what you want.

A double usually have about 15 decimal digits of precision. (In C++, check with std::numeric_limits<double>::digits10; in C, it's the DBL_DIG macro.) The result of 1000000006 * 1000000006 (1000000006 being the largest value your fast_exp can return, since it returns the result modulo 1000000007) has 19 decimal digits, which means that it can't be accurately represented in a double. As a result, the return value of your pow calls is likely inaccurate at least in some cases.

Just use plain old integer multiplication:

long long int fast_exp(int base, int exp)
{
    if(exp==1)
    return base;
    else
    {
        if(exp%2 == 0)
        {
            long long int ret = fast_exp(base, exp/2);
            long long int base1 = ret * ret;
            return base1 % 1000000007;
        }
        else
        {
            long long int ret = fast_exp(base, (exp-1)/2);
            long long int ans = base * ret;
            ans %= 1000000007; 
            ans *= ret;
            return ans % 1000000007;
        }
    }
}

int main() {
    std::cout << fast_exp(2, 999999999) << std::endl;
    std::cout << fast_exp(2, 1000000000) << std::endl;
    return 0;
}

This produces:

570312504
140625001

Sanity check: 570312504 * 2 - 140625001 == 1000000007.

The equivalent Java version produces the same output, as expected.


A simple demo of the inaccuracies of floating point:

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
    cout << setprecision(20) << pow(1000000006, 2) << endl
         << 1000000006LL * 1000000006LL << endl;
}

prints:

1000000012000000000
1000000012000000036

So does the equivalent Java version.

T.C.
  • 133,968
  • 17
  • 288
  • 421
1

Welcome to the wonders of floating point arithmetic.

The implementation of Math.pow may vary. If you change the Java code to

 static long power(int b,int i){
    long num;
    if(i==1)
        return b;
    else if(i%2==0){
        long p = power(b,i/2);
        double dp = (double)p;
        num=(long)(dp*dp);
        if(num>=1000000007)
            num%=1000000007;
        return num;
    }
    else {
        long p = power(b,i/2);
        double dp = (double)p;
        num=(long)(b*dp*dp);
        num=(long)(b*Math.pow(power(b,(i-1)/2),2));
        if(num>=1000000007)
        num%=1000000007;
        return num;
    }
}

the results are

646458262 477022294

which shows that C++ appears to handle integer powers differently, in comparison to Math.pow( double base, double exp );

It's impossible to discuss such issues without reading the source code of Math.pow and the pow function in the C++ library.

laune
  • 31,114
  • 3
  • 29
  • 42
0

Why you are converting double to long here:

num=b*(long)Math.pow(power(b,(i-1)/2),2);

Original code does not do that:

long long int ans = (base*  pow(fast_exp(base,(exp-1)/2),2));

I guess that has something to do with the result.

Eypros
  • 5,370
  • 6
  • 42
  • 75
  • 1
    The conversion is done before the multiplication and in c code after. There is a difference. – Eypros Jul 30 '14 at 08:10