c++ - 在浮点精度成为问题之前可以将多少个 float 加在一起

标签 c++ floating-point precision

我目前正在用 MS 而不是滴答记录一些帧时间。我知道这可能是个问题,因为我们将所有帧时间(以 MS 为单位)加在一起,然后除以帧数。由于浮点精度,这可能会导致不良结果。

将所有滴答计数加在一起然后在最后转换为 MS 会更有意义。

但是,我想知道少量样本的实际差异是什么?我希望有 900-1800 个样本。这会成为一个问题吗?

我做了这个小例子并在 GCC 4.9.2 上运行它:

// Example program
#include <iostream>
#include <string>

int main()
{
    float total = 0.0f;
    double total2 = 0.0f;

    for(int i = 0; i < 1000000; ++i)
    {
        float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
        total += r;
        total2 += r;
    }

    std::cout << "Total: " << total << std::endl;
    std::cout << "Total2: " << total2 << std::endl;
}

结果:

Total: 500004 Total2: 500007

据我所知,使用 100 万个值我们不会损失很多精度。虽然我不确定我写的是合理的测试还是实际测试我想测试的东西。

所以我的问题是,在精度成为问题之前,我可以将多少个 float 加在一起?我希望我的值在 1 到 60 毫秒之间。我希望最终精度在 1 毫秒以内。我有 900-1800 个值。

示例值:15.1345f 代表 15 毫秒。

最佳答案

反例

使用以下关于问题陈述的假设(时间有效地给出为 60 毫秒的 .06 等值),如果我们将 .06 转换为 float 并将其相加 1800 次,则计算结果为 107.99884796142578125。这与数学结果 108.000 相差超过 0.001。因此,计算结果有时会与数学结果相差超过1毫秒,因此在这种情况下无法实现问题中期望的目标。 (进一步细化问题陈述和替代计算方法可能能够实现目标。)

原始分析

假设我们在 [1, 60] 中有 1800 个整数值,使用 float y = x/1000.f; 转换为 float,其中实现了所有操作使用具有正确舍入的 IEEE-754 基本 32 位二进制 float 。

1 到 60 到 float 的转换是准确的。除以 1000 的误差最多为 ½ ULP(.06),即 ½ • 2−5 • 2−23 = 2−29。 1800 个这样的错误最多为 1800 • 2−29

随着生成的 float 值相加,每次相加最多可能有 ½ ULP 的误差,其中 ULP 是当前结果的 ULP。对于松散的分析,我们可以将其与最终结果的 ULP 绑定(bind),最终结果最多约为 1800 • .06 = 108,其 ULP 为 26 • 2−23 = 2−17。所以1799次加法每一次的误差至多为2−17,所以加法的总误差至多为1799•2−18

因此,除法和加法期间的总误差最多为 1800 • 2−29 + 1799 • 2−18,约为 .006866。

这是一个问题。我希望对加法中的错误进行更好的分析会使错误范围减半,因为它是从 0 到总数的算术级数,但这仍然会留下高于 .003 的潜在错误,这意味着总和可能是关闭几毫秒。

请注意,如果将时间作为整数相加,则最大潜在总和为 1800•60 = 108,000,这远低于 float 中无法表示的第一个整数 (16,777,217)。在 float 中添加这些整数将不会出错。

这个 .003 的边界足够小,以至于对问题的一些额外约束和一些额外的分析可能,只是可能,将它推到 .0005 以下,在这种情况下,计算结果将始终足够接近正确的数学结果将计算结果四舍五入到最接近的毫秒将产生正确的答案。

例如,如果知道虽然时间范围为 1 到 60 毫秒,但总时间总是小于 7.8 秒,这就足够了。

关于c++ - 在浮点精度成为问题之前可以将多少个 float 加在一起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51601492/

相关文章:

mysql - 如何配置 Rails 以在表单字段中以正确的精度输出小数?

c++ - Protocol Buffer : how nested (custom) optional fields are to be handled in C++?

c++ - 实现霍夫曼树

C++ GNU 指定的结构初始化在 Eclipse 中无法识别

c++ - 如何在verilog模块上运行SPECfp基准测试?

java - Android:如何持久存储 float 组

c++ - boost 序列化和 double

c++ exp 函数在 i7-3770 和 i7-4790 上 x64 下的不同结果

javascript - 为什么 JavaScript 中带小数的最大位数只有 16

c++ - 文件 I/O C++ ifstream 语法