算术可交换和关联吗?

时间:2013-10-14 11:28:17

标签: c# .net math

在数学中,(实数)的加法是可交换的和关联的,即。对于所有数字x,y和z

  

x + y = y + x(交换性)

  

x +(y + z)=(x + y)+ z(相关性)

实数的乘法也是可交换和关联的。但这对于.NET中的int和浮点数是否正确?反例欢迎。

编辑:背景是我们最近并行化算法,现在它的结果在重复之间不再一致。我推测这可能是由于原子计算以非确定性顺序返回(并被合并)。在这种情况下,可以通过更智能(但更慢)的合并算法(在合并之前对结果进行排序)来修复不一致性。我想知道它可以对.NET算法做出什么假设。

4 个答案:

答案 0 :(得分:9)

假设没有发生未经检查的溢出,.NET的整数加法和乘法(intlong等)是可交换的和关联的,就像数学中的实数一样。由于精度的限制,浮点运算(floatdouble)是可交换的,但并不总是精确关联的。来自Wikipedia (with an example in the article)

  

虽然浮点加法和乘法都是可交换的(a + b = b + a和a×b = b×a),但它们不一定是关联的。也就是说,(a + b)+ c不一定等于a +(b + c)。

以下是一个例子:

a: 0.825402526103613
b: 0.909231618470155
c: 0.654626872695343
(a*b)*c: 0.491285733573819
a*(b*c): 0.49128573357382

有些示例在结果变为string时结果显示相同,但​​不同((a*b)*c != a*(b*c)true(a*b)*c - a*(b*c)返回较小的值,不是0)。

a: 0.613781429181705
b: 0.648859122604532
c: 0.795545351596337
(a*b)*c: 0.316832045751117
a*(b*c): 0.316832045751117
difference: 5.55111512312578E-17

答案 1 :(得分:2)

int是,不(不幸的选择)float(由于精度有限)。

答案 2 :(得分:1)

在未经检查的上下文(默认值)中,溢出的存在与关联性和可交换性无关。

例如,取0x7fffffff + 0x80000000 + 0xffffffff。无论你如何将它括起来,结果都是0xfffffffe(又称-2)。但(0x7fffffff + 0x80000000) + 0xffffffff不会溢出而0x7fffffff + (0x80000000 + 0xffffffff)溢出两次。 (在无符号算术中,它们都会溢出一次)

总的来说也是如此。 C#中的整数a + (b + c) = (a + b) + c(如果unchecked)和Java。在C和C ++中,只保证无符号整数,因为未定义有符号溢出。

答案 3 :(得分:0)

并行缩减:

floats.AsParallel().Sum();

......每次都可以得到不同的结果。这是因为每次都会对工作进行不同的分区,这会在添加数字时导致不同的舍入错误。

要最大限度地减少此问题,请确保使用double来完成缩减,而不是使用浮点数。如果您想要按位相同的结果,则不应使用TPL或PLINQ,并滚动自己的并行计算。

请注意,在C#中,fp的准确性不能像C ++那样严格保证。阅读Eric对this SO question.

的回答