将二进制补码十六进制数转换为 boost::multiprecision::int256_t

Convert two's complement hex number to 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>();
}

这是一个验证所有边缘情况的测试程序:

Live On Coliru

#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

PS

作为旁注,显然数字限制是不可信任的,所以我在上面回避了它们。

assert(std::numeric_limits<UInt>::max() != std::numeric_limits<Int>::max());
assert(std::numeric_limits<UInt>::min() != std::numeric_limits<Int>::min());