首页 > 解决方案 > 为什么这个浮点数的总和是四舍五入的?

问题描述

我编写了一个简单的 C++ 宏,用于 CERN ROOT 数据分析框架。它接收一个包含天、小时、分钟、秒和亚秒列的数据文件(本质上是电子表格)。我的目标是将该数据转换为时间戳文件,以秒为单位。一切正常,直到添加亚秒。出于某种原因,它似乎对结果进行了四舍五入。例如,一个时间戳是:

804267 + 0.5606663227081298828125 = 804267.5625

另一个是:

155034 + 0.0958281949540391919293 = 155034

ROOT::RDataFrame d("N", "mydata1.root");
TFile *rfout = new TFile("./mydata2.root", "recreate");
TNtuple *N = new TNtuple("N","N","TIMESTAMP");

vector<float> timestamp;
int i;

d.Foreach([&](float day){timestamp.push_back(day*86400.00);},{"day"});
d.Foreach([&](float hr){timestamp.at(i) = timestamp.at(i)+(hr*3600);i++;},{"hr"});
i=0;
d.Foreach([&](float min){timestamp.at(i) = timestamp.at(i)+(min*60);i++;},{"min"});
i=0;
d.Foreach([&](float sec){timestamp.at(i) = timestamp.at(i)+sec;i++;},{"sec"});

i=0;
float j;
d.Foreach([&](float sub){
    while(sub > 1){
        sub = sub/10;
    }
    j = sub + timestamp.at(i);
    N->Fill(j);
    std::cout << std::setprecision(100) << j << " " << sub <<std::endl;
    i++;
},{"subsecond"});

rfout->Write();
rfout->Close();
abort();

}`

标签: c++c++11c++17root-framework

解决方案


出于某种原因,它似乎对结果进行了四舍五入。

原因命名为IEEE_754。如果您想最大程度地减少求和浮点数的损失,请按从小到大的顺序求和。

所以,在你的情况下:

...
vector<float> timestamp(d.Size(), 0.0f); // Note: I guess, ROOT::RDataFrame has the member function Size()
d.Foreach([i=0,&timestamp]mutable(float sub){timestamp[i]+=sub; i++;},{"subsecond"});
d.Foreach([i=0,&timestamp]mutable(float sec){timestamp[i]+=sec; i++;},{"sec"});
d.Foreach([i=0,&timestamp]mutable(float min){timestamp[i]+=min*60; i++;},{"min"});
d.Foreach([i=0,&timestamp]mutable(float hr){timestamp[i]+=hr*3600; i++;},{"hr"});
...
for(const auto &j : timestamp) {
    N->Fill(j);
    std::cout << std::setprecision(100) << j << " " << sub <<std::endl;
}


推荐阅读