1
154
你可以 calculate the mean iteratively . 此算法简单、快速,您只需处理一次每个值,并且变量永远不会大于集合中的最大值,因此不会出现溢出。
圈内
|
2
12
我想问你的第一个问题是:
如果没有,那你就别无选择,只能求和,数,除,求平均数。如果
另一方面,如果你 做 事先知道值的数目,你可以看看你真正在做什么,然后改变 怎样 你做到了,但要保持整体结果。 存储在某些集合A中的n个值的平均值如下:
若要计算此结果的子集,可以将计算拆分为大小相等的集,以便对3值集执行此操作(假设值的数目可被3整除,否则需要不同的整除器)
注意你需要 同等大小的集合 ,否则,与之前的所有集合相比,最后一个集合中的数字没有足够的值,将对最终结果产生更大的影响。 按顺序考虑数字1-7,如果选择3的集合大小,将得到以下结果:
它给出:
如果y是所有集合的3,则得到:
它给出:
这是:
总计:
平均1-7,是4。显然这行不通。注意,如果你用数字1,2,3,4,5,6,7,0,0做上面的练习(注意后面的两个零),那么你会得到上面的结果。 换言之,如果无法将值的数目拆分为大小相等的集合,则最后一个集合将被计算为与前面所有集合具有相同数目的值,但对于所有缺少的值,将用零填充。 所以, 你需要同样大小的套装 . 如果原始输入集由质数个值组成,那就太倒霉了。
不过,我担心的是精确度的下降。我不太确定
|
3
12
imho,解决问题最有力的方法是
这种方法的一个优点是,如果有大量的元素要求和,并且有大量的处理器/机器要用来计算,那么它可以很好地扩展 |
4
11
除了使用已经建议的更好的方法之外,您还可以使用 BigDecimal 做你的计算。(记住它是不可变的) |
5
10
请澄清这些值的潜在范围。 假设一个double有一个范围~=+/-10^308,并且你正在求10^9的值的和,你的问题中建议的表观范围是10^299的顺序值。 这似乎有点,嗯,不太可能… 如果你的价值观真的 是 那么大,那么对于一个普通的双精度,你只有17个有效的小数位数,所以在你考虑取平均值之前,你将扔掉大约280个数字的信息。
我也会注意到(因为没有人知道)对于任何一组数字
对于任意常数
在这个特殊的问题中,设置
我可以谦虚地说问题陈述不完整吗…? |
6
6
将所有值除以设置的大小,然后求和 |
7
6
一个双精度可以被2的幂除而不损失精度。所以如果你唯一的问题是求和的绝对大小,你可以在求和之前预先缩放你的数字。但有了这样大的数据集,仍然有可能遇到这样的情况:将小数字添加到大数字中,而小数字最终将大部分(或完全)被忽略。 例如,当您将2.2e-20添加到9.0e20时,结果是9.0e20,因为一旦调整了刻度,以便将它们的数字相加,较小的数字就是0。双打只能容纳大约17位数字,你需要40位以上的数字才能把这两个数字加在一起而不会丢失。 所以,根据你的数据集和你能承受的精度数字,你可能需要做其他的事情。将数据分解成集合会有帮助,但保持精度的更好方法可能是确定一个粗略的平均值(您可能已经知道这个数字)。然后在求和之前,从粗平均值中减去每个值。这样你就把距离和平均值相加,所以你的总和永远不会太大。 然后取平均增量,把它加到粗和中,得到正确的平均值。跟踪min delta和max delta也会告诉您在求和过程中丢失了多少精度。如果你有很多时间并且需要一个非常精确的结果,你可以迭代。 |
8
6
您可以取不超过限制的等号子集的平均值。 |
9
5
选项1是使用任意精度库,这样就没有上限。 其他选项(失去精度)是分组求和,而不是一次全部求和,或者在求和之前进行除法。 |
10
3
所以我不会重复这么多,让我声明,我假设数字列表是正态分布的,在溢出之前,你可以对许多数字求和。这种技术仍然适用于非正常发行版,但有些东西不能满足我下面描述的期望。 —— 总结一个子系列,记录你吃了多少,直到你接近溢出,然后取平均值。这将给你一个平均0,并计数n0。重复一遍,直到你把清单排完。现在你应该有很多人工智能了,尼。 每一个ai和ni应该是相对接近的,除了列表的最后一个部分。你可以通过在列表末尾咬一口来缓解这种情况。 您可以通过选择子集中的任何ni(称为np)并将该子集中的所有ni除以该值来组合这些ai、ni的任何子集。要合并的子集的最大大小是n的大致恒定值。 ni/np应接近1。现在求和ni/np*ai并乘以np/(和ni),跟踪求和ni。这给你一个新的ni,ai组合,如果你需要重复这个过程。 如果需要重复(即ai、n i对的数量比典型ni大得多),请尝试通过将一个n级的所有平均值组合在一起,然后在下一个n级组合,以保持相对n大小不变,依此类推。 |
11
3
首先,让自己熟悉
然后,假设双精度表示为“值加指数”,其中指数是2的幂。最大双精度值的极限是指数的上限,而不是该值的极限!所以你可以把所有大的输入数除以足够大的二次幂。对于所有足够大的数量,这应该是安全的。您可以将结果与因子相乘,以检查是否因相乘而丢失精度。 这里我们用一个算法
不要担心额外的除法和乘法。FPU将对它们进行优化,因为它们是用2的幂来完成的(为了进行比较,想象一下在十进制数字的末尾添加和删除数字)。
PS: 此外,您可能需要使用 Kahan summation 以提高精度。kahan求和避免了非常大和非常小的数字求和时精度的损失。 |
12
2
我张贴 an answer 到 a question 从这个问题衍生出来,后来意识到我的答案更适合这个问题而不是那个问题。我在下面复制了它。但我注意到,我的回答类似于 Bozho's 和 Anon . 's . 由于另一个问题被标记为语言不可知,我选择了c作为我包含的代码示例。它的相对易用性和易于遵循的语法,以及它包含的一些促进这个例程的特性(bcl中的divrem函数和对迭代器函数的支持),以及我自己对它的熟悉,使它成为解决这个问题的一个很好的选择。因为这里的OP对Java解决方案感兴趣,但我不是Java流利,足以有效地编写它,如果有人可以将此代码的翻译添加到Java,可能会很好。 这里有些数学解很好。这里有一个简单的技术解决方案。 使用较大的数据类型。这分为两种可能性:
这应该能提供一个double所能表示的精度,并且对于任何数量的32位元素都有效,最多2个
三十二
- 1。如果需要更多元素,则
就效率而言,它应该和这里的任何其他技术一样快或更快,因为它只需要遍历一次列表,只执行一个除法操作(嗯,一组除法操作),并且它的大部分工作都使用整数。不过,我没有对它进行优化,而且我非常确定,如果有必要的话,它的速度还可以稍微快一点。放弃递归函数调用和列表索引将是一个好的开始。再次,给读者一个练习。该代码的目的是易于理解。
我现在已经测试了这段代码,并做了一些小的更正(在
我首先通过1000组随机长度(介于1和1000之间)和随机整数(介于0和2之间)来测试它 三十二 - 1)。对于这些集合,我可以通过对它们运行规范平均值来轻松快速地验证其准确性。
然后我用100
*
大序列,随机长度在10之间
五
和10
九
. 这些序列的上下界也是随机选择的,受约束的,这样序列就可以在32位整数的范围内。对于任何序列,结果都很容易验证为
* 好吧,那是个善意的谎言。在大约20或30次成功运行之后,我中止了大型系列测试。一系列长度10 九 在我的机器上运行只需要不到一分半钟的时间,所以半个小时左右的测试就足够满足我的口味了。 对于感兴趣的人,我的测试代码如下:
|
13
2
对一小部分完整数据集进行随机抽样通常会得到“足够好”的解决方案。显然,您必须根据系统需求自己做出这个决定。样本量可以非常小,并且仍然可以获得相当好的答案。这可以通过计算随机选择的样本数量的平均值来自适应地计算,平均值将在某个区间内收敛。 采样不仅解决了双重溢出问题,而且速度更快。不适用于所有问题,但对许多问题肯定有用。 |
14
1
考虑一下:
因此,对于任意大小的双倍集,你可以做到这一点(这是C语言,但我敢肯定它很容易翻译成Java):
实际上,这很好地简化为(马丁内斯已经提供了):
我写了一个快速的测试来尝试这个函数,与更传统的求值和除以计数的方法不同(
以下是一些试验的结果:
好吧,但是10^9的值呢?
当然,这个解决方案的可接受程度将取决于您的精度要求。但值得考虑。 |
15
0
|
16
0
为了保持逻辑简单,并保持性能不是最好的但可以接受,我建议您将bigdecimal与原语类型一起使用。 这个概念非常简单,您可以使用基元类型将值相加,每当值下溢或溢出时,您可以将计算值移动到bigdecimal,然后将其重置以进行下一次求和计算。还有一件事你应该知道,当你构造bigdecimal时,你应该总是使用string而不是double。
从这个概念来看,每次结果是下溢或溢出时,我们都会将该值保存到更大的变量中,这个解决方案可能会由于bigdecimal计算而稍微降低性能,但它保证了运行时的稳定性。 |
17
-1
(n) 一 +n 二 +…+n K /k=(n) 一 +n 二 /k+(n) 三 +n 四 )+(n) K-1 +n K )/如果k是偶数 (n) 一 +n 二 +…+n K /k= n 一 /k+(n) 二 +n 三 )+(n) 小精灵 +n K )/如果k是奇数 |
18
-2
为什么这么多复杂的长答案。这是目前为止最简单的求平均值的方法,不需要知道有多少元素或大小等。 长整数i=0; 双平均值=0; while(仍有元素) { 平均值=平均值*(i/i+1)+x[i]/(i+1); I++; } 平均收益率; |