c++ - 将二进制补码十六进制数转换为 boost::multiprecision::int256_t
问题描述
我试图让 boost::multiprecision 解析一个负数(二进制补码)十六进制数:
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
int main(int argc, char* argv[]) {
std::string hex_str = "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb2e";
boost::multiprecision::int256_t signed_int(hex_str);
std::cout << signed_int << std::endl;
}
我希望这会输出-1234。不幸的是,它输出 115792089237316195423570985008687907853269984665640564039457584007913129638702
解析无符号十六进制数可以正常工作。
如何让 int256_t 将十六进制数解释为负二进制补码?
解决方案
十六进制转换构造函数根本不解析符号。同样,如果它们是负数,std::cout 将拒绝打印十六进制数,并且确实.str(..., std::ios::hex)
会抛出runtime_error
异常(“不支持以 8 或 16 为基数打印负数”)。
所以你必须让它手动工作,比如
UInt uval(str);
Int val;
if (/*signbit =*/uval >> 255) {
// manual two's complement
val = ~uval + 1;
val.backend().sign(true);
} else {
val = uval.convert_to<boost::multiprecision::int256_t>();
}
这是一个验证所有边缘情况的测试程序:
#include <boost/multiprecision/cpp_int.hpp>
#include <iomanip>
#include <iostream>
using namespace std::string_literals;
using UInt = boost::multiprecision::uint256_t;
using Int = boost::multiprecision::int256_t;
int main()
{
static const auto min = -Int(UInt(1) << 255);
static const auto max = Int(UInt(1) << 255 - 1);
static const auto dec = std::ios::dec;
static const auto hex = std::ios::hex | std::ios::showbase;
struct {
std::string_view caption;
Int expected;
std::string str;
} testcases[] = {
// clang-format off
{"zero", 0, Int{0}.str(0, dec),},
{"zero", 0, Int{0}.str(0, hex),},
//
{"one", 1, Int{1}.str(0, dec),},
{"one", 1, Int{1}.str(0, hex),},
//
{"negone", -1, Int{-1}.str(0, dec),},
{"negone", -1, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"s,},
//
{"min", min, (min).str(0, dec),},
{"min", min, "0x8000000000000000000000000000000000000000000000000000000000000000"s,},
//
{"min+1", min+1, (min + 1).str(0, dec),},
{"min+1", min+1, "0x8000000000000000000000000000000000000000000000000000000000000001"s,},
//
{"max-1", max-1, (max - 1).str(0, dec),},
{"max-1", max-1, (max - 1).str(0, hex),},
//
{"max", max, (max).str(0, dec),},
{"max", max, (max).str(0, hex),},
// question case
{"question", -1234, "-1234"s,},
{"question", -1234, "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb2e"s,},
// clang-format on
};
for (auto [caption, expected, str] : testcases) {
std::cout << " ---- " << caption << ":\t\t" << str << "\n";
UInt uval(str);
Int val;
if (/*signbit =*/uval >> 255) {
// manual two's complement
val = ~uval + 1;
val.backend().sign(true);
} else {
val = uval.convert_to<boost::multiprecision::int256_t>();
}
std::cout << "Expected? " << std::boolalpha
<< (expected == val ? "SUCCESS" : "FAILED") << "\t";
std::cout << std::dec << val;
if (val.sign() >= 0) // negative no hex
std::cout << " (" << std::hex << std::showbase << val << ")";
std::cout << "\n";
}
}
印刷
---- zero: 0
Expected? SUCCESS 0 (0x0)
---- zero: 0x0
Expected? SUCCESS 0 (0x0)
---- one: 1
Expected? SUCCESS 1 (0x1)
---- one: 0x1
Expected? SUCCESS 1 (0x1)
---- negone: -1
Expected? SUCCESS -1
---- negone: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Expected? SUCCESS -1
---- min: -57896044618658097711785492504343953926634992332820282019728792003956564819968
Expected? SUCCESS -57896044618658097711785492504343953926634992332820282019728792003956564819968
---- min: 0x8000000000000000000000000000000000000000000000000000000000000000
Expected? SUCCESS -57896044618658097711785492504343953926634992332820282019728792003956564819968
---- min+1: -57896044618658097711785492504343953926634992332820282019728792003956564819967
Expected? SUCCESS -57896044618658097711785492504343953926634992332820282019728792003956564819967
---- min+1: 0x8000000000000000000000000000000000000000000000000000000000000001
Expected? SUCCESS -57896044618658097711785492504343953926634992332820282019728792003956564819967
---- max-1: 28948022309329048855892746252171976963317496166410141009864396001978282409983
Expected? SUCCESS 28948022309329048855892746252171976963317496166410141009864396001978282409983 (0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
---- max-1: 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Expected? SUCCESS 28948022309329048855892746252171976963317496166410141009864396001978282409983 (0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
---- max: 28948022309329048855892746252171976963317496166410141009864396001978282409984
Expected? SUCCESS 28948022309329048855892746252171976963317496166410141009864396001978282409984 (0x4000000000000000000000000000000000000000000000000000000000000000)
---- max: 0x4000000000000000000000000000000000000000000000000000000000000000
Expected? SUCCESS 28948022309329048855892746252171976963317496166410141009864396001978282409984 (0x4000000000000000000000000000000000000000000000000000000000000000)
---- question: -1234
Expected? SUCCESS -1234
---- question: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb2e
Expected? SUCCESS -1234
附言
作为旁注,显然数字限制是不可信的,所以我在上面回避了它们。
assert(std::numeric_limits<UInt>::max() != std::numeric_limits<Int>::max());
assert(std::numeric_limits<UInt>::min() != std::numeric_limits<Int>::min());
推荐阅读
- php - 如何在没有模块的情况下在 Prestashop 中添加 Google Tag Manager 代码
- python - PyQt5 - 如何更改列表小部件中的特定项目背景颜色
- weblogic12c - 在 Weblogic Server 上提供静态文件
- angular - ngFor 循环内的函数无限调用
- reactjs - 如何使用获取的变量作为材料 UI 日期选择器的初始状态?
- angular - 错误:“仪表板组件”类型上不存在属性“数据”
- arrays - 用于简单数组特定值替换和转换的 MongoDB 聚合
- javascript - Firebase Firestore 集合无法检索 - 反应原生
- node.js - NPM 在通过 apt 安装时需要 x11
- flutter - Flutter:BLoC 通过监听数据流来发出状态