Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 寻找平均值的更好算法_C_Algorithm - Fatal编程技术网

C 寻找平均值的更好算法

C 寻找平均值的更好算法,c,algorithm,C,Algorithm,我正在练习一本编程书,一本关于C的书。该练习建议,要找到一组数字的平均值,算法: avg += (x - avg) / i; 优于: sum += x; avg = sum / i; “x”是用于存储输入数字的变量。它还建议除了防止溢出外,第一种算法确实比第二种算法有其他一些好处,有人能帮我吗?谢谢 更好的方法是,它计算一个运行平均值,也就是说,你不需要提前知道所有的数字。你可以边走边计算,或者在数字可用时计算 sum += x; avg = sum / i; 在上面的代码中,假设我们的数

我正在练习一本编程书,一本关于C的书。该练习建议,要找到一组数字的平均值,算法:

avg += (x - avg) / i;
优于:

sum += x;
avg = sum / i;

“x”是用于存储输入数字的变量。它还建议除了防止溢出外,第一种算法确实比第二种算法有其他一些好处,有人能帮我吗?谢谢

更好的方法是,它计算一个运行平均值,也就是说,你不需要提前知道所有的数字。你可以边走边计算,或者在数字可用时计算

sum += x;
avg = sum / i;
在上面的代码中,假设我们的数字为1000020000,…即包含大量数字的数字,则总和中的值可能会超过其最大值,而在第一个代码中,情况并非如此,因为总和在存储之前总是除以元素的个数

虽然由于编程语言中存在大量数据类型,这可能不是问题


专家说“根据您的应用程序和需求使用数据类型。”

后一种算法比前一种算法更快,因为您必须执行n个操作(实际上,后者需要执行2*n个操作)。但第一种方法确实可以防止溢出。例如,如果你有1000个数字:4000000×250, 1500000×500, 2000000 *500,所有整数的总和将是2’70.0.000,000,但是C++ INT数据类型的上限是2147483647。所以,我们正在处理一个溢出问题。但是如果你执行第一个算法,那么你就能够处理这个问题


因此,如果可能发生溢出,我建议您使用第一个算法,否则它只会添加额外的操作。如果您决定无论如何使用第一个,那么我建议您使用范围更大的类型。

我假设我们在这里讨论的是浮点算术(否则“更好”的平均值将非常糟糕)

在第二种方法中,中间结果(
sum
)将趋向于无边界增长,这意味着您最终将失去低端精度。在第一种方法中,中间结果应该与输入数据保持大致相似的大小(假设输入没有很大的动态范围)。这意味着它将更好地保持精度

然而,我可以想象,随着
I
变得越来越大,
(x-avg)/I
的值将变得越来越不准确(相对而言)。因此它也有它的缺点。

我更喜欢第二种方法(循环求和,最后除法),并且识别第二种方法的速度比第一种快得多

性能差异(如果有的话)无关紧要


而且,如果一个值的总和溢出了足够大的数据类型,您可能会遇到比计算平均值更多的问题。

好的,答案不在于溢出总和(因为这是不可能的),而是正如Oli在“失去低端精度”中所说的那样。如果要求和的数字的平均值远大于每个数字与平均值的距离,则第二种方法将丢失尾数位。因为第一种方法只是查看相对值,所以它不会遇到这个问题

因此,任何大于(比如)6000万(对于单精度浮点)但值的变化不超过10左右的数字列表都应该显示其行为


如果使用双精度浮点,则平均值应高得多。或者delta要低得多。

假设整数在一个数组中,这样计算怎么样

sum += x[i] / N; rem += x[i] % N;
avg = sum + rem/N;

如果
N
较大(0xFFFFF)且
x[i]
均较小,则
rem
加起来等于0xFFFF(最大整数),则可能发生溢出。

Heh。我桌上正好有那本书的第一版。这是在哪一章?反论点---第二种方法,忽略溢出,可能是因为只执行了一个除法:)@pmg只是一个很棒的注释。如果是溢出,我们为什么要选择I'st方法。无法从这里发布的答案中清除。@pmg可能我遗漏了什么,但是第一个方法如何执行两个划分呢?第一个方法有一个环绕
+=
表达式的循环;第二个表达式还有一个环绕
+=
表达式的循环。因此,在第一个迭代中,每个迭代都有一个除法,但第二个迭代只有一个除法。使用第一种方法的原因与数值稳定性和避免溢出有关。请参阅上的讨论,尤其是Wikipedia页面(以及相关的,可能更相关的页面)。OP上说“除了防止溢出之外”,您将能够在恒定时间内计算每个增量平均值,而不是O(N),谢谢"在本练习中,您将继续上一个练习中所做的工作。如果您从包含一些普通数字的文件中获取输入,运行平均值更好的程序,那么第一个算法和第二个算法似乎会产生相同的答案。找到一种情况并非如此。即,演示实验你能告诉我哪种情况会发生这种情况吗?-1:他们都能计算出运行平均值。+1你能解释一下“失去低端精度”吗"@算法:考虑浮点表示的结构;尾数和指数。尾数代表精度,即有效数字,并且有固定数目。随着你的数字越来越大,指数将开始增加,这意味着你的有效数字被乞求。在我看来,
(x-avg)/I
的问题只是部分由
I
变大引起的。如果许多数字是CLO,那么
(x-avg)
部分本身也是一个问题