jsoncpp库输出浮点型值精度错误

可以看到图中71.21的值经过jsoncpp转换后变成了71.20999999999999

这是因为 21/100 没有精确的浮点表示,默认情况下,我们使用17位数字,因为这是将double的任何值明确表示为字符串所需的数字。此17==DBL_DECIMAL_DIG==std::numeric_limits<double>::max_digist10。以这种精度打印可以保证任何双值都可以在打印和解析时存活下来,而不会失真。这与15==DBL_DIG==std::numeric_limits<double>::digitals10不同,后者是可以在不失真的情况下从字符串解析到double并返回的最大位数。因此,17的默认值是一种折衷。我们选择了足够多的数字来完美地表示每一个可能的双精度值。不过,这不是我想要的。所以只需要15位数字的精度,因为15位数字可以在不失真的情况下解析和重新打印,但这会牺牲对double数据类型的完整尾数的访问。

如果您需要自定义输出并使用自定义配置的编写器,有一种方法可以设置精度。

cpp 复制代码
文件:jsoncpp/src/lib_json/json_writer.cpp

Line 1240

 (*settings)["precision"] = 17; 

将17修改为15即可正常输出71.21

以下代码可以看出计算机对不同位数精度的不同输出:

cpp 复制代码
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>

constexpr double inf = std::numeric_limits<double>::infinity();

void dumpTable(double x) {
    int maxPrecision = 25;
    double xPlusEpsilon = std::nextafter(x, inf);
    for (int p = 0; p < maxPrecision; ++p) {
        std::cout << "p=" << std::setw(3) << p;
        for (auto f : {x, xPlusEpsilon}) {
            std::cout
                << ", "
                << std::setprecision(p)
                << std::defaultfloat
                << std::setw(maxPrecision + 5)
                << f;
        }
        std::cout << std::endl;
    }
}

int main() {
    dumpTable(71.21);
    return 0;
}

可以从下面看出16位时,输出71.21则会出错,当然不止72.21,一些其它浮点类型也可能会出错。

cpp 复制代码
p=  0,                          7e+01,                          7e+01
p=  1,                          7e+01,                          7e+01
p=  2,                             71,                             71
p=  3,                           71.2,                           71.2
p=  4,                          71.21,                          71.21
p=  5,                          71.21,                          71.21
p=  6,                          71.21,                          71.21
p=  7,                          71.21,                          71.21
p=  8,                          71.21,                          71.21
p=  9,                          71.21,                          71.21
p= 10,                          71.21,                          71.21
p= 11,                          71.21,                          71.21
p= 12,                          71.21,                          71.21
p= 13,                          71.21,                          71.21
p= 14,                          71.21,                          71.21
p= 15,                          71.21,                          71.21
p= 16,              71.20999999999999,              71.21000000000001
p= 17,             71.209999999999994,             71.210000000000008
p= 18,            71.2099999999999937,             71.210000000000008
p= 19,           71.20999999999999375,           71.21000000000000796
p= 20,          71.209999999999993747,          71.210000000000007958
p= 21,         71.2099999999999937472,         71.2100000000000079581
p= 22,        71.20999999999999374722,        71.21000000000000795808
p= 23,       71.209999999999993747224,       71.210000000000007958079
p= 24,      71.2099999999999937472239,      71.2100000000000079580786
相关推荐
Brilliantwxx6 分钟前
【C语言】 初入嵌入式C语言复习(基础+进阶面试题)
c语言·开发语言
熊野君28 分钟前
附录与 Codex 实操手册
开发语言·人工智能·产品经理
wuminyu31 分钟前
深入剖析 Panama Off-heap 的性能损耗与开销
java·linux·c语言·jvm·c++
维克兜率天33 分钟前
【维克】动量指标家族:RSI、ROC、CCI、Momentum全面解析
python·算法
rhythm-ring1 小时前
宏定义续行符 \ 的使用与踩坑
c语言·c++
AI情绪识别开源1 小时前
检信 AI 智能推广平台(代号:JX-Promote)
人工智能·算法·erlang
XZ-0700011 小时前
week2-1-可视化
开发语言·python
Java后端的Ai之路2 小时前
14、Python - 责任链模式
服务器·开发语言·人工智能·python·责任链模式
吴声子夜歌2 小时前
Java——基本类型
java·开发语言
老当益壮梁奶奶2 小时前
Linux软件编程学习笔记(八):进程间通信详解(1)
linux·c语言·笔记·学习·算法