1

类似的问题:Boost.Multiprecision cpp_int - 转换成字节数组?

但这一次与浮点值有关。

  1. export_bits - 似乎没有接受浮点值的重载
  2. cpp_dec_float_50 的肢体不对外公开

问题: 因此,应该如何解决将这种数据类型与字节数组相互转换的问题?

4

2 回答 2

1

如果您不介意 10 字节的开销并且不想使用任何未记录的接口,请使用序列化支持。

否则,“破解”后端实现。

使用序列化

例如

编译器资源管理器

#include <boost/archive/binary_oarchive.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <fmt/ranges.h>
#include <sstream>
#include <vector>
#include <span>

using F = boost::multiprecision::cpp_dec_float_50;
namespace ba = boost::archive;

int main() {
    F f{"2837498273489289734982739482398426938568923658926938478923748"};

    std::vector<unsigned char> raw;
    {
        std::ostringstream oss;
        {
            ba::binary_oarchive oa(
                oss, ba::no_header | ba::no_codecvt | ba::no_tracking);

            oa << f;
        }
        auto buf = std::move(oss).str();
        raw.assign(buf.begin(), buf.end());
    }

    fmt::print(" sizeof: {} raw {} bytes {::#0x}\n", sizeof(F), raw.size(),
               std::span(raw.data(), raw.size()));
}

印刷

 sizeof: 56 raw 63 bytes [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd6, 0x6e, 0x0, 0x0, 0xd1, 0x88, 0xdb, 0x5, 0xba, 0x19, 0xba, 0x1, 0x7, 0x3, 0xa2, 0x1, 0x3a,
 0xe0, 0xdd, 0x5, 0xcd, 0x1b, 0x64, 0x3, 0x88, 0x24, 0x52, 0x5, 0xe4, 0x47, 0xb4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x
0, 0xa, 0x0, 0x0, 0x0]

破解后端

原来相关的东西是私人的。但是serialize是通用的,所以你可以用它来泄露私人信息:

   template <class Archive>
   void serialize(Archive& ar, const unsigned int /*version*/)
   {
      for (unsigned i = 0; i < data.size(); ++i)
         ar& boost::make_nvp("digit", data[i]);
      ar& boost::make_nvp("exponent", exp);
      ar& boost::make_nvp("sign", neg);
      ar& boost::make_nvp("class-type", fpclass);
      ar& boost::make_nvp("precision", prec_elem);
   }

例如:实时编译器资源管理器

//#include <boost/core/demangle.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <fmt/ranges.h>
#include <vector>

using F = boost::multiprecision::cpp_dec_float_50;

struct Hack {
    std::vector<unsigned char> result {};

    template <typename T> Hack& operator&(boost::serialization::nvp<T> const& w) {
        return operator&(w.value());
    }

    template <typename, typename = void> struct Serializable : std::false_type{};
    template <typename T> struct Serializable<T,
                        std::void_t<decltype(std::declval<T>().serialize(
                            std::declval<Hack&>(), 0u))>> : std::true_type {
    };

    template <typename T> Hack& operator&(T const& v)
    {
        if constexpr (Serializable<T>{}) {
            const_cast<T&>(v).serialize(*this, 0u);
        } else {
            constexpr size_t n = sizeof(v);
            //fmt::print("{} ({} bytes)\n", boost::core::demangle(typeid(v).name()), n);
            static_assert(std::is_trivial_v<T>);
            static_assert(std::is_standard_layout_v<T>);
            auto at = result.size();
            result.resize(result.size() + n);
            std::memcpy(result.data() + at, &v, n);
        }
        return *this;
    }
};

int main() {
    F f{"2837498273489289734982739482398426938568923658926938478923748"};

    Hack hack;
    f.serialize(hack, 0u);

    fmt::print(" sizeof: {} raw {} bytes {::#0x}\n", sizeof(F),
            hack.result.size(), hack.result);
}

印刷

 sizeof: 56 raw 53 bytes [0xd6, 0x6e, 0x0, 0x0, 0xd1, 0x88, 0xdb, 0x5, 0xba, 0x19, 0xba, 0x1, 0x7, 0x3, 0xa2, 0x1, 0x3a, 0xe0, 0xdd, 0x5, 0xcd, 0x1b, 0x64, 0x3, 0x88, 0x24, 0x52, 0x5, 0xe4, 0x47, 0xb4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0]

摘要/警告

我将把相应的反序列化代码作为练习留给读者。

最后,hack 方法与 clean 方法非常相似,只是模拟了序列化存档。

请注意,Hack 方法不支持版本控制。

此外,这两种方法可能都没有给定可移植性。检查字节序/处理器架构是否改变了您的要求。

于 2022-02-05T18:40:30.430 回答
0

该答案基于@Sehe 提供的内容。

它为 Boost 的 mp::cpp_dec_float_50 的序列化和反序列化提供了便利。

由于 Boost 的序列化接口似乎不支持 no_header 标志- 通过序列化接口交互时插入了大约 10 个长字节的前缀废话,并且由于我不知道这些字节应该代表什么 - 所有非重要字节被省略,它们的数量存储在序列化产品的最低有效字节中。因此,如果 Boost 有一天决定正确处理标志,以下内容应该在 Boost 版本之间兼容。

然后在反序列化时“恢复”这些存根字节。

享受。

using BigFloat = mp::cpp_dec_float_50;
/// <summary>
/// Produces a vector of bytes from mp::cpp_dec_float_50 (BigFloat).
/// Leading header is omitted for storage efficiency.
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
std::vector<uint8_t>  CTools::BigFloatToBytes(BigFloat const& f)
{

    std::vector<unsigned char> raw;
    {
        std::ostringstream oss;
        {
            boost::archive::binary_oarchive oa(
                oss, boost::archive::no_header | boost::archive::no_codecvt | boost::archive::no_tracking);

            oa << f;
        }

        auto buf = std::move(oss).str();
        raw.assign(buf.begin(), buf.end());

        uint8_t leading0sCount = 0; //it will be stored within the last byte

        for (int i = 0; i < raw.size(); i++)
        {
            if (raw[i] == 0)
            {
                leading0sCount++;
            }
            else
                break;
        }

        raw.assign(raw.begin() + leading0sCount, raw.end());
        raw.push_back(leading0sCount);
    }

    return raw;
}

/// <summary>
/// Instantiates BigFloat (mp::cpp_dec_float_50) from a vector of bytes.
/// </summary>
/// <param name="v"></param>
/// <returns></returns>
BigFloat CTools::BytesToBigFloat(std::vector<uint8_t> v)
{
    //Local Variables and Namespaces - BEGIN
    namespace io = boost::iostreams;
    namespace ba = boost::archive;
    //Local Variables and Namespaces - END

    //Validation - BEGIN
    if (v.size() == 0)
        return 0;
    //Validation - END

    //Operational Logic - BEGIN

    //recover leading 0s/prefix
    uint8_t leading0sCount = v[v.size() - 1];
    v.pop_back();
    std::vector<uint8_t> prefix = std::vector<uint8_t>(leading0sCount);
    v.insert(v.begin(), prefix.begin(), prefix.end());

    io::stream_buffer<io::back_insert_device<std::vector<uint8_t>>> bb(v);

    BigFloat i;
    {
        std::vector<char> chars { v.begin(), v.end() };
        io::stream_buffer<io::array_source> bb(chars.data(), chars.size());
        boost::archive::binary_iarchive ia(bb, ba::no_header | ba::no_tracking | ba::no_codecvt);
        ia >> i;
    }
    //Operational Logic - END

    return i;
}
于 2022-02-06T10:17:00.483 回答