如何将升压多精度整数转换为大端字节?

问题描述 投票:0回答:1

我创建了u256类型定义为

using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;

我最初使用此代码:

        stringstream stream;
        u256 data = _data; // both variables are of the same type

        for (int i = 0; i < 5; ++i) {
            if (i < info.additional) {
                if (i == 4) {
                    // printf("+  ");
                    stream << "+  ";
                }
                else {
                    uint8_t dataByte = int(data & 0xFF);
                    data >>= 8;
                    stream << std::setfill('0') << std::setw(sizeof(char) * 2)
                        << std::hex << int(dataByte) << "  ";
                }
            }
            else {
                stream << "    ";
            }
        }

因此,数字被转换为字符串,每个字节之间(只有前一个字节)之间有一个空格。

但是后来我遇到了字节序问题:字节以相反的顺序打印。

所以我在上面的循环之前添加了此代码:

        for(unsigned int i=0;i<31;++i) //loop for putting in the big endian order from little endian
        {
            data |= int(_data & 0xFF);
            _data >>= 8;
            data <<= 8;
        }
        _data=data;

现在,为什么我的256位整数大多打印为00 00 00 00 00系列?如果我注释掉数字,则会再次以错误的顺序完全打印数字新循环。

c++ boost c++14 endianness boost-multiprecision
1个回答
0
投票

BTW,这不是字节序问题;您没有对对象表示进行字节访问。您将其作为256位整数进行操作,只需使用data & 0xFF一次请求低8位即可。

如果您确实了解目标C实现的字节顺序以及boost对象的数据布局,则可以使用unsigned char*以降序的地址有效地对其进行循环。

您之所以介绍字节顺序,是因为它与字节反转相关,这是您要尝试的操作。 但这确实效率很低,只需以另一种方式遍历bigint的字节。


我不愿意推荐一个特定的解决方案,因为我不知道什么将有效地进行编译。但是您可能想要类似的东西

for (outer loop) {
    uint64_t chunk = data >> (64*3);  // grab the highest 64-bit chunk
    data <<= 64;   // and shift everything up
    // alternative: maybe keep a shift-count in a variable instead of modifying `data`

    // Then pick apart the chunk into its component bytes, in MSB first order
    for (int = 0 ; i<8 ; i++) {
        unsigned tmp = (chunk >> 56) & 0xFF;
        // do something with it
        chunk <<= 8;                   // bring the next byte to the top
    }
}

在内部循环中,与使用两次移位相比,更有效的方法是使用rotate将高字节移至底部(对于& 0xFF而言),同时将低字节向上移。Best practices for circular shift (rotate) operations in C++

在外部循环中,如果boost::multiprecision::number具有任何用于对内置块进行有效索引的API,则IDK;如果是这样,使用它可能会更有效。

我使用了嵌套循环,因为我假设data <<= 8的编译效率不是很高,(data >> (256-8)) & 0xFF也不会。但这就是从顶部而不是底部抓取字节的方式。


如果您对一次将8、16或32字节数据转换为十六进制的[[efficiency感兴趣,请参阅How to convert a number to hex?了解某些x86 SIMD方式。 asm应该很容易移植到C ++内部函数。 (您可以使用SIMD混洗来处理从小尾数整数加载后将字节按MSB优先的打印顺序放置。)

您还可以使用SIMD随机播放来分隔成对的十六进制数字,然后像您显然想要的那样存储到内存中。


错误添加代码:

所以我在上面的循环之前添加了此代码:

for(unsigned int i=0,data,_data;i<33;++i)

unsigned i, data, _data声明类型为unsigned int的新变量,该变量遮盖了以前的data_data声明。该循环对循环范围以外的data_data无效。 (并且包含UB,因为您无需初始化即可读取_datadata。)

如果这些变量实际上仍然是外部范围的u256变量,除了效率外,我没有看到其他明显的问题,但是也许我也缺少明显的问题。我看起来并不难,因为使用64x 256位移位和32x OR似乎是一个可怕的想法。它的[[可能

可以完全优化掉它,也可以优化成具有它们的ISA上的bswap字节反向指令,但是我对此表示怀疑。特别是不能通过boost::multiprecision::number包装函数的额外复杂化。
© www.soinside.com 2019 - 2024. All rights reserved.