通过平方我的指数实现有什么问题吗?

时间:2014-07-30 07:48:43

标签: java c++ c algorithm math

我通过在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

3 个答案:

答案 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;
}

prints

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));

我猜这与结果有关。