unsigned long long int 参数的日志

log of unsigned long long int argument

我需要在 C++ 代码中进行以下计算:

(((n*log(n)) / log(4)) + 1)

其中 n 的类型为 'unsigned long long int'(并且是 2 的幂,因此结果应为整数)。

对于非常大的数字,我得到一些错误,例如 n = 9007199254740992 结果应该是 238690780250636289,但是当我 运行 代码时,我得到 238690780250636288.

这可能是 'log' 函数没有使用 'unsigned long long int' 参数实现的结果吗?如果是这样,有没有办法在不实现新日志功能的情况下规避它?

unsigned long long int upToBit(unsigned long long int n) {
    unsigned long long int check = (((n*log(n)) / log(4)) + 1);
    return check;
}

Could this be the result of 'log' function not having an implementation with 'unsigned long long int' argument?

是也不是。

您使用 std::log 其中 returns 加倍。由于扩展范围,double 不能表示 238690780250636289。如果您只是将该数字转换为 long long,您将得到完全相同的错误:

int main()
{
    volatile double dd = 238690780250636289.0;
    printf("%lld\n", (long long)dd);
}

输出:

238690780250636288

要了解为什么会发生这种情况,有 a good paper about floating point numbers。 如果编译器上的 sizeof(long double) > 8,你可能会幸运地使用 long double 版本的 log。您还可以测试 "correctness" 您的计算:

bool resultOk = upToBit(9007199254740992) == 238690780250636289.0;

一般来说,double 有 52 位尾数,由于有额外的隐藏位,double 可以表示的最大可靠整数是 2 的 53 次方或 9007199254740992。如果您得到的 double 具有更高的整数值,那么有时简单的整数数学 "stops working":

#include <stdio.h>

int main()
{
    long long l = 9007199254740992;
    double d = (double)l;
    d += 1;
    printf("9007199254740992 + 1 = %lld\n", (long long)d);
}

输出:

9007199254740992 + 1 = 9007199254740992

为了获得更高的精度,您可以使用一些专门为此设计的多精度算术库。例如,GCC 使用 GMP / MPFR 进行内部计算。