繁体   English   中英

C ++中的Json:将数字解析为字符串,以避免浮点数错误

[英]Json in C++: Parse a number as a string to avoid floating-point inaccuracy

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

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

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

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

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\"");
    };

现在它可以正常工作了。

我喜欢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

本地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,

如预期的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM