我通过在java中进行平方来实现指数。并从网上复制,一个C代码相同。但问题是,这些代码提供了不同的输出。
我给出的输入是:2作为基数,999999999和1000000000作为权力。
这是我的java代码:
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;
}
}
输出: 646458262 178281319
这是我从网上获得的C代码:
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;
}
}
}
输出: 646458006 477022294
答案 0 :(得分:4)
不要使用浮点数和使用它们的函数(包括C / C ++中的pow
/ std::pow
或Java中的Math.pow
)来进行整数数学运算。它没有做你想做的事。
double
通常具有大约15个十进制数字的精度。 (在C ++中,请与std::numeric_limits<double>::digits10
一起检查;在C中,它是DBL_DIG
宏。)1000000006 * 1000000006
的结果(1000000006
是您{fast_exp
的最大值1}}可以返回,因为它返回结果模1000000007
)有19个十进制数字,这意味着它不能在double
中准确表示。因此,至少在某些情况下,pow
来电的返回值可能不准确。
只需使用普通的旧整数乘法:
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;
}
这produces:
570312504
140625001
完整性检查:570312504 * 2 - 140625001
== 1000000007
。
等效Java version产生与预期相同的输出。
浮点不准确的简单演示:
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
cout << setprecision(20) << pow(1000000006, 2) << endl
<< 1000000006LL * 1000000006LL << endl;
}
1000000012000000000
1000000012000000036
等效Java version也是如此。
答案 1 :(得分:1)
欢迎来到浮点运算的奇迹。
Math.pow的实现可能会有所不同。如果将Java代码更改为
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;
}
}
结果
646458262 477022294
表明与Math.pow(double base, double exp)相比,C ++似乎以不同方式处理整数幂;
如果不阅读Math.pow的源代码和C ++库中的pow函数,就无法讨论这些问题。
答案 2 :(得分:0)
为什么您要将double
转换为long
:
num=b*(long)Math.pow(power(b,(i-1)/2),2);
原始代码不会这样做:
long long int ans = (base* pow(fast_exp(base,(exp-1)/2),2));
我猜这与结果有关。