【问题标题】:Adding several small float values overflows into infinity添加几个小的浮点值会溢出到无穷大
【发布时间】:2015-01-17 14:39:11
【问题描述】:

我遇到了一个循环问题,该循环应该将许多非常小的浮点值加在一起以最终产生加权平均值,如下所示:

    for(int k = 0; k < slopes.size(); k++){
        if(slopes.get(k).isClimbing() == false){
            float tempWeight = (slopes.get(k).getzDiff() / highestFallZ);
            weight += tempWeight;
            highestFallX += (slopes.get(k).getEndX() * tempWeight);
        }

        highestFallX = highestFallX / weight;
    }

本质上它所做的是从对象的一个​​属性产生一个权重(其结果总是在 0 和 1 之间),然后通过该权重修改同一对象的另一个属性并将结果添加到运行计数中,最后除以权重之和。所有值和变量都是浮点类型。

现在我遇到的问题是,在短短几步内,运行计数(highestFallX)呈指数增长到 -infinity。我进行了一些诊断,他们表明添加的每个单独的值都在 -1 和 -1*10^-5 之间的范围内(在与加权相乘之后)并且其中不超过 60 个加在一起,所以上溢和下溢都不是问题。为了比较,这里是循环前几个步骤中最后添加的值 (LastFallX) 和计数 (HighestFallX) 的列表:

LastFallX: -1.2650555E-4
HighestFallX: -1.2650555E-4
LastFallX: -6.3799386E-4
HighestFallX: -0.25996128
LastFallX: -4.602447E-4
HighestFallX: -87.01444
LastFallX: -0.0020183846
HighestFallX: -16370.462
LastFallX: -4.158747E-5
HighestFallX: -826683.3

从那以后它一直呈指数增长,并在大约 10 个循环内达到 -infinity。在这个循环中,highestFallX 变量没有被其他任何东西引用或修改。

【问题讨论】:

    标签: java infinity


    【解决方案1】:

    表示平均值的一种方式是:

    totalValue += nextValue * nextWeight;
    totalWeight += nextWeight;
    average = totalValue / totalWeight;
    

    正如你所见,这在totalValue 中很容易溢出。

    您也可以这样做:

    totalWeight += nextWeight;
    average += ((nextValue * nextWeight) - average) / totalWeight;
    

    在你的情况下,我认为这可能看起来像:

    for(int k = 0; k < slopes.size(); k++){
        if(slopes.get(k).isClimbing() == false){
            float tempWeight = (slopes.get(k).getzDiff() / highestFallZ);
            weight += tempWeight;
            float weightedValue = (slopes.get(k).getEndX() * tempWeight);
            float delta = weightedValue - highestFallX;
            highestFallX += delta / weight;
        }
    }
    

    但我仍在努力确定您的加权平均值应该如何工作,所以我有点不确定最后一点。

    【讨论】:

    • 在尝试了您的方法后,我意识到我在每次循环运行期间都按组合重量进行除法,而不是在正确汇总计数后仅进行一次。都是因为放错了位置 } 干杯!
    【解决方案2】:

    它必须有多精确?您可以简单地将所有内容删除到小数点后三位,以确保它不会遇到大量数字的问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-03
      • 2014-04-06
      • 2023-03-16
      • 1970-01-01
      • 2015-10-16
      • 1970-01-01
      相关资源
      最近更新 更多