使用boost::multiprecision cpp_int左移时出现超时错误

Time limit exceeded error when doing left shift with boost::multiprecision cpp_int

本文关键字:超时 错误 左移 int boost multiprecision cpp 使用      更新时间:2023-10-16

我正在尝试以下操作:

#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
int main()
{
using namespace boost::multiprecision;
cpp_int v = 1;
unsigned int a = 4294967295;
std::cout << (v << a) << std::endl; 
return 0;
}

如何防止同样的错误?我们可以用cpp_int进行的位偏移的上限是多少。

这会分配大量(浪费的)内存。

既然你可以使用十进制浮点数来表示这个数字,而不会损失任何精度,我会这样做:

注意,1 << n等于2^n(pow(2,n)),因此可以写:

#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
namespace bmp = boost::multiprecision;
using number = bmp::number<bmp::cpp_dec_float<50, intmax_t> >;
int main() {
int64_t a = 0xffffffff;
std::cout << pow(number(2), a) << std::endl; 
}

哪个得到正确的

1.55164e+1292913986

您可以验证它是否正确:

for (intmax_t const a : { -8888ll, 0xFFFFll, 0xFFFFFFFFll, }) {
std::cout << pow(number(2), a) << std::endl; 
auto roundtrip_exponent = bmp::log2(pow(number(2), a));
auto reverse = round(roundtrip_exponent).convert_to<intmax_t>();
std::cout << "Reverse: " << std::hex << std::showbase << reverse << std::dec << "n";
std::cout << "Match: " << std::boolalpha << (a == reverse) << "n";
}

打印Coliru直播

2.78868e-2676
Reverse: 0xffffffffffffdd48
Match: true
1.00176e+19728
Reverse: 0xffff
Match: true
1.55164e+1292913986
Reverse: 0xffffffff
Match: true

在极端情况下,您将不可避免地在不精确运算(log2)上失去一些精度。

如果你很好奇,你可能想通过设置std::fixed:来尝试打印全精度

#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
namespace bmp = boost::multiprecision;
using number = bmp::number<bmp::cpp_dec_float<50, intmax_t> >;
int main() {
std::cout << std::fixed << pow(number(2), 0xFFFFFFFFll) << std::endl; 
}

将输出重定向到文件!它将用十进制数字写1.3GiB。这应该解释了为什么它不能很好地使用任意精度的整数表示。

所有输出压缩为:

0000000 3531 3135 3436 3230 3137 3339 3631 3334
0000020 3730 3130 3934 3439 3535 3737 3339 3831
0000040 3232 3937 3535 3631 3334 3936 3939 3038
0000060 3737 3938 3631 3338 3737 3030 3532 3339
0000100 3533 3538 3636 3230 3935 3039 3030 3030
0000120 3030 3030 3030 3030 3030 3030 3030 3030
*
11504046500 3030 2e30 3030 3030 3030 000a
11504046513

其中*表示只有0位数字的行。然后你就能明白为什么我称之为浪费