【问题标题】:Json in C++: Parse a number as a string to avoid floating-point inaccuracyC++ 中的 Json:将数字解析为字符串以避免浮点不准确
【发布时间】:2018-06-28 16:43:43
【问题描述】:

我正在处理加密货币 RPC 并接收 json 数据,如下所示:

{
  ...
  "amount": 1.34000000,
  "confirmations": 230016,
  "spendable": true,
  "solvable": true
  ...
}

使用Jsoncpp 库或json11 获取解析为double 的数字。发生这种情况时,由于双精度问题,结果为:1.3400000000000001。一般来说,这对金融交易来说是灾难性的并且是不可接受的。

我已经有一个定点库,它可以接受一个有效的字符串并在内部将其视为一个整数。有没有办法让 Jsoncpp(或任何其他 json 库)将选定的数字 json 值作为字符串,以便我可以以固定精度正确对待它们?

【问题讨论】:

  • 我不确定,但您可能可以运行预解析并将 "amount": 1.34000000 更改为 "amount": "1.34000000"
  • @NathanOliver 当然。这将是我最终会做的一个 hack。
  • 如果您将值存储为双精度值,那么即使您将值解析为字符串,这种情况也总会发生。一旦你把它变成一个双精度浮点数就有一个有限的分辨率。这就是金融应用程序不使用实数的原因(它们使用整数或 BCD(二进制编码的小数))。您可以乘以 100000000 并存储为整数。
  • @MartinYork 你似乎误解了发生了什么。请允许我解释一下。在将数字乘以 10000000 后存储数字......基本上称为“定点精度”,这是我在问题中提到的(例如,比特币是如何运作的,其中最小的可交易整数单元被称为聪)。我不想存储在双,永远。问题是我想直接从字符串到定点精度,而不必经过双精度,所有 json 库似乎都在未经我同意的情况下这样做。

标签: c++ json double fixed-point jsoncpp


【解决方案1】:

json库中似乎没有解决方案,所以我不得不自己修改数字并用引号将其包裹起来。我将此函数应用于响应以做到这一点。

[](std::string& jsonStr) {
        // matches "amount" field in json
        static std::regex reg(R"((\s*\"amount\"\s*:)\s*(\d*\.{0,1}\d{0,8})\s*)");
        jsonStr = std::regex_replace(jsonStr, reg, "$1\"$2\"");
    };

现在它可以正常工作了。

【讨论】:

    【解决方案2】:

    我喜欢ThorsSerializer。免责声明是我写的。

    它支持您正在寻找的内容。
    您可以告诉解析器对类使用标准输入/输出运算符(然后您可以自己定义)。

    例子:

    #include "ThorSerialize/JsonThor.h"
    #include "ThorSerialize/SerUtil.h"
    #include <sstream>
    #include <iostream>
    #include <string>
    #include <map>
    
    struct FixedPoint
    {
        int     integerPart;
        int     floatPart;
        friend std::istream& operator>>(std::istream& stream, FixedPoint& data)
        {
            // This code assumes <number>.<number>
            // Change to suite your needs.
            char c;
            stream >> data.integerPart >> c >> data.floatPart;
            if (c != '.')
            {
                stream.setstate(std::ios::failbit);
            }
    
            return stream;
        }
    };
    // This declaration tells the serializer to use operator>> for reading
    // and operator<< for writing this value.
    // Note: The value must still conform to standard Json type
    //       true/false/null/integer/real/quoted string
    ThorsAnvil_MakeTraitCustom(FixedPoint);
    
    struct BitCoin
    {
        FixedPoint  amount;
        int         confirmations;
        bool        spendable;
        bool        solvable;
    };
    // This declaration tells the serializer to use the standard
    // built in operators for a struct and serialize the listed members.
    // There are built in operations for all built in types and std::Types
    ThorsAnvil_MakeTrait(BitCoin, amount, confirmations, spendable, solvable);
    

    示例用法:

    int main()
    {
        using ThorsAnvil::Serialize::jsonImport;
        using ThorsAnvil::Serialize::jsonExport;
    
        std::stringstream file(R"(
            {
                "amount": 1.34000000,
                "confirmations": 230016,
                "spendable": true,
                "solvable": true
            }
        )");
    
        BitCoin     coin;
        file >> jsonImport(coin);
    
        std::cout << coin.amount.integerPart << " . " << coin.amount.floatPart << "\n";
    }
    

    构建:

    > g++ -std=c++1z 51087868.cpp -lThorSerialize17
    

    【讨论】:

      【解决方案3】:

      原生的jsoncpp解决方案是RTFM!!! (例如,这里:https://open-source-parsers.github.io/jsoncpp-docs/doxygen/class_json_1_1_stream_writer_builder.html

      Json::StreamWriterBuilder builder;
      builder["commentStyle"] = "None";
      builder["indentation"] = "   ";
      builder["precision"] = 15;
      

      这将设置您的写入器浮点精度,以避免打印双精度表示中的小截断错误。例如,不是 json 字段,而是

      “金额”:1.3400000000000001,

      你现在会得到

      “金额”:1.340000000000000,

      根据需要。

      【讨论】:

        猜你喜欢
        • 2011-10-13
        • 2021-06-30
        • 2015-03-15
        • 1970-01-01
        • 2020-02-05
        • 1970-01-01
        • 2014-05-26
        • 1970-01-01
        • 2016-04-24
        相关资源
        最近更新 更多