使用无符号长整型进行幂运算的精度问题

5

我正在尝试进行pow(x, y)计算,其中x和y是无符号长整型,结果存储在无符号长整型中。这个结果会小于2^63,所以我应该能够做到。 但由于它返回一个浮点数,对于大数字我得到的结果不准确。有没有办法在不使用外部库(如bignum)的情况下获得精确的结果? 我知道我可以简单地将x*x乘以Y次,但这正是我想避免的,因为我想让我的程序更快。


1
你的代码在哪里?你可能需要将浮点数四舍五入到最近的整数。 - owacoder
2
pow执行的是exp(y*log(x)),速度较快但存在精度问题。 - Déjà vu
2
这可能对您有些兴趣:https://zh.wikipedia.org/wiki/平方求幂算法 - user4520
1
我没有将其标记为重复,因为您一开始不知道如何处理,但您可以查看以下内容: https://dev59.com/hnVD5IYBdhLWcg3wE3No - Emilien
通过此结果将小于2^63,您是否意味着xy的值足够小,或者意味着模算术?如果您将x等于01进行测试,则最多应具有61次乘法,可以使用蛮力循环,甚至不值得优化。 - chqrlie
显示剩余3条评论
3个回答

6

pow函数返回一个双精度浮点数,存在精度问题,如果将其转换为long类型,那么你很可能会遇到精度问题。据我所知,如果不使用库,仅靠pow函数本身是不可能得到准确结果的。

你也可以看一下平方法幂运算,并查看barak manos的答案,在那里你可以尝试实现自己的pow函数。

unsigned long long pow(unsigned long long x,unsigned int y)
{
    unsigned long long res = 1;
    while (y > 0)
    {
        if (y & 1)
            res *= x;
        y >>= 1;
        x *= x;
    }
    return res;
}

这种方法对于非常大的数字有效吗?比如10000^10000(x^y)?因为我想始终将值保持在2^63-1以下。所以我正在尝试尽可能接近2^63-1,然后在那一部分进行计算,取得结果,并将其带入下一个计算,直到我的y变得足够小,可以立即进行计算。 - LifeisHard
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Jongware
@Jongware:10000^10000比2^63大,但仍然可以轻松地放在网页上,尽管不是在注释中:一个后面跟着40000个0的1 - chqrlie
@chqrlie:根据谷歌计算器,10000^10等于1e+40。这是10³¹ Gb,对于一个网页来说有点太大了,而且讨论的数字比这还要大一倍的谷歌。 - Jongware
3
创建一个函数 unsigned long long pow(unsigned long long x,unsigned int y) ... 是引起一些讨厌的错误的好方法。C语言没有为具有相同名称的函数提供签名。这掩盖了符合标准的 double pow( double, double ); 函数。 - Andrew Henle
显示剩余2条评论

2

pow 的定义本身就是不精确的。它使用 exp(y*log(x)) 来模拟 x ^ y。如果您想要完全的准确性,您需要使用外部库或者自己制作一个版本的 pow


-1

我不确定你的代码。但是我猜你的代码应该像这样

unsigned long x,y;
x=...//
y=...//

unsigned long res=pow(x,y);

这不对。因为 pow() 总是返回 double 类型。

double pow(double x, double y) 

这就是为什么你得到了双精度浮点数。

要获得正确的数字,您可以像这样操作:

    unsigned long x,y;
    x=...//
    y=...//

    unsigned long res=(unsigned long)pow(x,y);

1
这并没有解决 OP 的问题:“由于它返回一个浮点数,对于大数字我得到不准确的结果”。 - Jongware
@Jongware 你确定 res 的值是浮点数吗? - Newaz Hossain
你的解释有些混淆:只要通过 #include <math.h> 正确声明了 pow,第一种选项就没有问题,转换为 unsigned long 是隐式的,编译器将生成正确的代码。相反,如果没有声明 pow,添加显式转换也不会改变任何东西:编译器将假定该函数具有 int pow(int,int); 原型,并且生成的代码将完全错误。 - chqrlie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接