如何指定 setprecision 的四舍五入方式

8

我可以通过指定setprecision来在流向std输出时四舍五入double值吗?

ofile << std::setprecision(12) << total_run_time/TIME << "\n";

输出: 0.756247615801

ofile << std::setprecision(6)<< total_run_time/TIME << "\n";

输出: 0.756248

但我需要输出为0.756247

谢谢

4个回答

17

还有来自<cfenv>std::fesetround,它可以设置舍入方向:

#include <iostream>
#include <iomanip>
#include <cmath>
#include <cfenv>

int main () {
    double runtime = 0.756247615801;

    // Set rounding direction and output with some precision:
    const auto prev_round = std::fegetround();
    std::fesetround(FE_DOWNWARD);    
    std::cout << "desired: " << std::setprecision(6) << runtime << "\n";

    // Restore previous rounding direction and output for testing:
    std::fesetround(prev_round);
    std::cout << "default: " << std::setprecision(6) << runtime << "\n";
}

(请注意,这些不是我推荐的评论,它们只是为了教学目的而存在)

输出:

desired: 0.756247
default: 0.756248

重要说明:然而,我没有在标准中找到任何有关浮点类型的operator<<重载需要遵守舍入方向的内容。


到目前为止,唯一100%正确的解决方案是假定实现质量良好,其中将转换为十进制的函数遵守舍入模式。 - Pascal Cuoq
@PascalCuoq:我添加了名为“重要提示”的部分。 - Sebastian Mach
@phreshel fesetround 返回值为“零,如果成功设置了请求的舍入方向。否则,返回非零值”:http://www.cplusplus.com/reference/cfenv/fesetround/#return 我想你可能想使用:fegetround 我修改了你的答案,请随意回滚,如果我的修改没有意义。 - Jonathan Mee
@JonathanMee:哎呀,你的修改完全有效,我完全没问题。谢谢! - Sebastian Mach

2

另一种方法是通过在输出之前从 double 中减去0.000005 来避免四舍五入,针对您的第二种情况:

total_run_time / TIME - 0.000005

在许多方面,我更喜欢这样做,因为它避免了整数溢出的潜在问题。

4
但是这样可能会引入舍入误差,因为 0.000005 无法被精确地表示。 - James Kanze

2
将您的除法结果乘以一百万,转换为整数,然后再除以一百万(作为double类型)。这样可以省略输出时使用std::setprecision的步骤。

3
+1,但在这种情况下显然不会影响您,但是请注意使用此方法时不要溢出整数。 - Bathsheba
1
通过使用modf(将double拆分为整数和小数部分)避免将其转换为int(可能导致溢出)。 - James Kanze
1
编辑:一些肮脏的试错二分法揭示了一个事件视界,大约在2147.483648000000130125左右。 - Sebastian Mach
2
无需转换为整数;floor或trunc函数将在不进行转换的情况下提供所需的结果。 - Eric Postpischil
1
乘以1000000会产生一个四舍五入的结果,可能会丢失所需的向下取整值。 - Eric Postpischil
显示剩余3条评论

1
std::cout.write(std::to_string(0.756247615801).c_str(), 8);

它看起来很杂乱,但它能够正常工作!

你可以改进它并使用std::string::substring(0,9) - Sebastian Mach
std::string::substr 创建了一个不必要的额外字符串对象,因此我只是使用 write 输出相关部分。 - user2637317
我只是认为它会有更好的自我记录,但你是对的。 - Sebastian Mach
这个解决方案存在双重舍入问题。在初始转换为十进制时使用的附加数字越少,双重舍入问题就越明显。存在一定数量的数字用于初始转换,这意味着对于所有“double”来说,双重舍入是无害的,但我不确定有多少个数字。这与在十进制中可以表示一个“double”的确切表示中最大连续非前导非尾随零的数量有关。 - Pascal Cuoq
假设正确舍入转换为十进制,并打印21个附加数字,此方法在所有情况下均有效。参考:https://dev59.com/nHnZa4cB1Zd3GeqPtK4g#20302431 - Pascal Cuoq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接