Java 计算大数的加权平均数

Java 计算大数的加权平均数,java,average,weighted-average,Java,Average,Weighted Average,我想得到几个数字的加权平均数。基本上,我有: Price - 134.42 Quantity - 15236545 价格和数量可以少到一对、两对,也可以多到五十对、六十对。我需要算出价格的加权平均数。基本上,加权平均应该给像这样的配对很少的权重 Price - 100000000.00 Quantity - 3 对上面的那一对,还有更多 我目前的公式是: ((price)(quantity) + (price)(quantity) + ...)/totalQuantity 到目

我想得到几个数字的加权平均数。基本上,我有:

Price    - 134.42
Quantity - 15236545
价格和数量可以少到一对、两对,也可以多到五十对、六十对。我需要算出价格的加权平均数。基本上,加权平均应该给像这样的配对很少的权重

Price    - 100000000.00
Quantity - 3
对上面的那一对,还有更多

我目前的公式是:

((price)(quantity) + (price)(quantity) + ...)/totalQuantity
到目前为止,我已经做到了:

        double optimalPrice = 0;
        int totalQuantity = 0;
        double rolling = 0;
        System.out.println(rolling);

        Iterator it = orders.entrySet().iterator();
        while(it.hasNext()) {
            System.out.println("inside");
            Map.Entry order = (Map.Entry)it.next();
            double price = (Double)order.getKey();
            int quantity = (Integer)order.getValue();
            System.out.println(price + " " + quantity);

            rolling += price * quantity;
            totalQuantity += quantity;
            System.out.println(rolling);
        }
        System.out.println(rolling);
        return rolling/totalQuantity;
问题是我很快就最大化了“滚动”变量


如何实际获得加权平均值?

一种解决方案是对
滚动
总量
使用
java.math.biginger
,并且只在最后对它们进行分割。这具有更好的数值稳定性,因为末尾只有一个浮点数除法,其他都是整数运算

biginger
基本上是无界的,因此您不应该遇到任何溢出


编辑:对不起,只是在重读之后我才注意到你的价格是双倍的。也许值得绕开这个问题,将它乘以100,然后转换成
biginger
——因为我在你的例子中看到它正好是小数点右边的2位数字——然后在最后除以100,尽管这有点麻烦。

一个double可以容纳一个相当大的数字(根据文档,大约是1.7 x 10^308),但您可能不应该将其用于需要精确精度的值(例如货币值)


改为查看课堂。更详细地讨论它。

要获得最大的灵活性,请使用
滚动
,以及
总量
。除法后(注意,它应该是滚动/总量),您可以返回一个大十进制,也可以在精度损失的情况下使用。

在任何给定点,您都记录了总值
ax+by+cz+…=pq和总重量
a+b+c+…=p
。知道了这两个参数,就得到了平均值
pq/p=q
。问题是
pq
p
都是溢出的大总和,即使您只想要中等大小的
q

例如,下一步添加权重
r
和值
s
。您希望通过仅使用
q
的值来查找新的和
(pq+rs)/(p+r)
,这只有在
p
pq
位于相同分数的分子和分母中时才会发生。这是不可能的,我会证明的

您需要在这个迭代中添加的值自然是

(pq + rs) / (p + r) - q
这不能简化为
p*q
p
消失的点。你也可以找到

(pq + rs) / q(p + r)
乘以q得到下一个平均值的因子;但是,
pq
p
仍然存在。所以没有聪明的解决办法


其他人提到了任意精度变量,这是一个很好的解决方案。
p
pq
的大小随条目数线性增长,整数/浮点数的内存使用和计算速度随值的大小呈对数增长。因此,性能是O(log(n))与灾难不同,如果
p
以某种方式是许多数字的倍数。

首先,我不知道如何“最大化”滚动
变量。正如@Ash所指出的,它最多可以表示大约
1.7x10^308
的值。我能想到的唯一可能性就是你的输入中有一些不好的值。(也许真正的问题是你正在失去精确度…)


第二,你用
地图
来表示订单是很奇怪的,而且可能是不正确的。按照您目前使用的方式,您无法表示包含两个或多个相同价格项目的订单。

您的最终结果只是精度的加权平均值,因此您可能不需要遵循计算账户余额等时使用的规则。如果我对上述内容正确,那么您就不需要使用
BigDecimal
double
就足够了

溢出问题可以通过存储“运行平均值”并用每个新条目更新来解决。即让

a_n=(sum_{i=1}^n x_i*w_i)/(sum_{i=1}^n w_i)

对于n=1,…,n.从a_n=x_n开始,然后添加

d_n:=a_{n+1}-a_n

去吧。d_n的公式是

d_n=(x_{n+1}-w_{n+1}*a_n)/w_{n+1}

其中W_n:=sum_{i=1}^n W_n。您需要跟踪W_n,但这个问题可以通过将其存储为
double
来解决(这没关系,因为我们只对平均值感兴趣)。您还可以规范化权重,如果您知道所有权重都是1000的倍数,只需将它们除以1000即可

要获得更高的精度,可以使用

抢占式解释:这里可以使用浮点运算
double
的相对精度为2E-16。OP的平均值为正数,因此不会出现取消错误。任意精度算法的支持者没有告诉你的是,撇开舍入规则不谈,当它确实比IEEE754浮点算法提供了更多精度时,这将带来巨大的内存和性能成本。浮点运算是由非常聪明的人(Kahan教授和其他人)设计的,如果有一种方法可以比浮点运算更便宜地提高运算精度,他们就会这么做


免责声明:如果您的权重完全疯狂(一个是1,另一个是10000000),那么我不能100%确定您是否会获得令人满意的准确度,但您可以在知道答案后在某个示例上进行测试。

执行两个循环:首先在第一个循环中计算总量。然后在第二个循环中累积价格*(数量/总数量)。

Ye