【问题标题】:Rounding a float to two decimal places将浮点数四舍五入到小数点后两位
【发布时间】:2016-09-08 21:47:01
【问题描述】:

我希望将浮点值(例如 val)四舍五入到最接近的 0.05 倍数。我的意图的解释是here。我已经有了val 的上限和下限,分别是valU 和valL。我可以通过以下方式做到这一点:

  1. 在[valL, valU] 范围内搜索最接近的0.05 倍数并相应地分配值。平局是通过采取较低的价值来解决的。或
  2. 使用 this 之类的东西(在链接中给出的解决方案中,将 20 替换为 100)。

我发现方法 2 有时会产生错误的结果。有人可以告诉我为什么方法 1 是正确的方法吗?

【问题讨论】:

  • 方法2最好,显示你的代码。
  • 请务必在此处发布相关材料。链接数据只是参考数据。

标签: c floating-point rounding


【解决方案1】:

...将float 值四舍五入,例如val 到最接近的0.05 倍数...

鉴于典型的binary floating point,可以拥有的最好的是

...将float 值四舍五入到最接近0.05 的倍数R 并保存为最接近的可表示float r。


方法#1 在极端情况下不清楚。 OP 所拥有的不是代码,而是从数学角度来看的代码大纲,而不是实际的 C 代码。我会选择 #2 的变体,非常效果很好。 @Barmar

几乎是方法 2:乘法、舍入、然后除法。

#include <math.h>
double factor = 20.0;
float val = foo();
double_or_float rounded_val = round(val * factor)/factor;

这种方法有两个微妙的地方使它更胜一筹。

  1. 与参考答案相比,乘法的精度和范围更大 - 这允许 精确 乘积和 非常 精确商。如果仅使用float 数学计算乘积/商,则某些极端情况最终会得到错误的答案,当然某些大值会溢出到无穷大。

  2. “平局以较低的价值结算。”是一个艰难而不同寻常的目标。听起来像是一个旨在扭曲选择的目标。 round(double) 无论当前的舍入方向如何,都可以很好地从零开始舍入一半的情况。要完成“降低”,请更改当前舍入方向并使用rint() 或nearbyint()。

    #include <fenv.h>
    int current_rounding_direction = fegetround();
    fesetround(FE_DOWNWARD);
    double rounded_val = rint(val * factor)/factor;
    fesetround(current_rounding_direction);
    

...方法 2 有时会产生错误的结果...

OP 需要发布代码和 exact 使用和计算的值,以便对各种方法的优势/劣势进行质量解释。试试printf("%a %a\n", val, rounded_val);。通常,由于对代码使用printf("%f\n", val);所使用的确切值的理解不准确而出现问题@


进一步:“我已经有了val 的上限和下限,分别是valU 和valL。我可以通过以下方式做到这一点:”

这可能是准确的,因为 valU 和 valL 的偏差只是原始问题的迭代 - 找到 rounded_val。查找valL 和valU 的代码都需要一个上限和下限,否则如何防止[valL ... valU] 范围本身具有不准确的端点?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 2013-08-14
    相关资源
    最近更新 更多