Reputation: 767
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
Upvotes: 0
Views: 470
Reputation: 137395
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;
}
1000000012000000000
1000000012000000036
So does the equivalent Java version.
Upvotes: 4
Reputation: 31300
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.
Upvotes: 1
Reputation: 5723
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.
Upvotes: 0