【问题标题】:Convert two's complement hex number to boost::multiprecision::int256_t将二进制补码十六进制数转换为 boost::multiprecision::int256_t
【发布时间】:2021-12-03 09:18:42
【问题描述】:

我正在尝试让 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 将十六进制数解释为负二进制补码?

【问题讨论】:

    标签: c++ boost hex boost-multiprecision


    【解决方案1】:

    十六进制转换构造函数根本不解析符号。同样,如果十六进制数为负数,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());
    

    【讨论】:

      猜你喜欢
      • 2014-03-01
      • 1970-01-01
      • 2014-04-16
      • 2013-09-28
      • 2011-09-03
      • 2012-06-26
      • 2016-05-24
      • 1970-01-01
      • 2016-08-28
      相关资源
      最近更新 更多