在字符串流中使用固定和设置精度时 C++ 的轮次误差

round error of C++ when using fixed and setprecision in stringstream

提问人:Lee 提问时间:11/13/2022 最后编辑:Lee 更新时间:11/14/2022 访问量:203

问:

我用 C++ 编写了一个程序,我认为它的结果应该是 12.3 和 12.2。但最终结果是 12.2 和 12.2。显然,它没有正确四舍五入。但是为什么? 非常感谢你:)

#include <iostream>
#include <iomanip>

using namespace std;

string dtos(double num) {
    stringstream ss;
    ss << fixed << setprecision(1) << num;
    return ss.str();
}

int main() {
    double num1 = 12.25;
    double num2 = 12.24;
    string str1 = dtos(num1);
    string str2 = dtos(num2);
    cout << str1 << ' ' << str2 << endl;
    return 0;
}

我还尝试了 num1 = 12.05 和 num2 = 12.04 的方法,并获得所需的结果为 12.1 和 12.0。

C++ 舍入 精度 固定 字符串流

评论

1赞 john 11/13/2022
@πάνταῥεῖ 如果这是真的(我不知道),那么为什么 OP 发现成功四舍五入到?刚刚尝试了 OP 的代码,我看到了相同的情况。有时会进行四舍五入。12.0512.1
0赞 joergbrech 11/13/2022
你尝试过 en.cppreference.com/w/cpp/numeric/fenv/feround 吗?
0赞 Gonen I 11/13/2022
相关新闻: stackoverflow.com/questions/10922366/...

答:

3赞 shy45 11/14/2022 #1

我检查了每个圆形函数的特征。因此,基本上这些函数从值返回最接近的整数,但如果该值位于两个整数之间的中间位置,则有以下行为类型可供计算。

  • 舍入类型
    • NI:最接近的整数,远不为零。(例如 2.5 -> 3)
    • NE:与值最接近的偶数。(例如 2.5 -> 2)
  • 中途型
    • 确切地说:考虑浮点误差。(例如,2.500002 不是中途)
    • 不完全是:忽略浮点错误。(例如,2.500002 被视为 2.5)

这就是为什么每个功能可以分为以下几种类型的原因。

  1. SetPrecision(设置精度)

    • 舍入类型:NE
    • 中途型:正好
  2. 林特

    • 舍入类型:NE
    • 中途类型:不完全是
    • 舍入类型:NI
    • 中途类型:不完全是
#include <iostream>
#include <cfenv>
#include <iomanip>
#include <math.h>
using namespace std;

int main() {
    fesetround(FE_TONEAREST);
    //fesetround(FE_DOWNWARD);
    //fesetround(FE_UPWARD);
    printf("round type=%d\n\n", fegetround());

    auto f = [&](auto v) {
        printf("%-14s %.30f\n", "orig val", v);
        cout << fixed << "setprecision" << setw(7) << setprecision(1) << v << endl;
        printf("%-14s %.30f\n", "rint", rint((v * 10)) / 10);
        printf("%-14s %.30f\n", "round", round((v * 10)) / 10);
        cout << "-----------------" << endl;
    };
    f(12.05);
    f(12.25);
    f(12.35);
    f(12.75);
}

输出为

round type=0

orig val       12.050000000000000710542735760100
setprecision   12.1
rint           12.000000000000000000000000000000
round          12.099999999999999644728632119950
-----------------
orig val       12.250000000000000000000000000000
setprecision   12.2
rint           12.199999999999999289457264239900
round          12.300000000000000710542735760100
-----------------
orig val       12.349999999999999644728632119950
setprecision   12.3
rint           12.400000000000000355271367880050
round          12.400000000000000355271367880050
-----------------
orig val       12.750000000000000000000000000000
setprecision   12.8
rint           12.800000000000000710542735760100
round          12.800000000000000710542735760100
-----------------

评论

0赞 Lee 11/14/2022
谢谢,我认为这就是答案。