假设我有N个整数,其中N可以变大,但每个int保证在0和某个上限M之间,其中M很容易适合有符号的32位字段。
如果我想计算这些N个整数的平均值,我不能总是在同一个有符号的32位空间中对它们进行求和并将它们全部除以 - 如果N太大,分子就有溢出的风险。这个问题的一个解决方案是仅使用64位字段进行计算,以保持较大的N,但此解决方案不能扩展 - 如果M是一个大的64位整数,则会出现同样的问题。
有没有人知道可以计算同一位空间中正整数列表的平均值的算法(最好是O(N))?没有做一些便宜的事情,比如使用两个整数来模拟一个更大的整数。
答案 0 :(得分:5)
假设你最初知道M
,你可以保留两个变量,一个是到目前为止的答案除以M,另一个是余数。
例如,在C ++中:
int ans = 0, remainder = 0;
for (int i=0;i<N;i++) {
remainder += input[i]; // update remainder so far
ans += remainder/N; // move what we can from remainder into ans
remainder%=N; // calculate what's left of remainder
}
在循环结束时,答案在ans
中找到,余数在remainder
中(如果您需要除截断之外的舍入方法)。
此示例适用于最大输入数M + N适合32位int。
请注意,这应该适用于正整数和负整数,因为在C ++中,/
运算符是除法运算符,而%
实际上是余数运算符(实际上不是模运算符)。 / p>
答案 1 :(得分:1)
您可以计算出移动平均线。如果您有A
个N
元素的平均值,并且添加了另一个元素E
,则新的平均值为(A*N+E)/(N+1)
。通过除以加法的分配性质,这相当于(A*N)/(N+1) + E/(N+1)
。但是如果A*N
溢出,您可以使用乘法和除法的关联属性,您可以将第一项转换为A*(N/N+1)
。
所以算法是:
n = 0
avg = 0
for each i in list
avg = avg*(n/(n+1)) + i/(n+1)
n = n+1