【问题标题】:Is arithmetic commutative and associative?算术交换和结合?
【发布时间】:2013-10-21 22:56:40
【问题描述】:

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

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

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

实数的乘法也是可交换的和结合的。但是对于 .NET 中的整数和浮点数来说,这是真的吗?欢迎反例。

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

【问题讨论】:

  • DV 看起来有点极端,但你到底想解决什么问题呢?
  • 坚持“我不知道我在说什么,但无论如何我都会就这个主题发表我的看法”,我想说它适用于整数,但不是必须为花车。至少这是我对浮点运算的直觉。
  • 在任何语言中,都遵循基本的数学规则。对于整数来说,交换性、关联性以及加法的置换性确实应该在数值舍入精度的限制内尊重浮点数。
  • 另外,您对并行化(我假设是指多线程)的评论可能表明存在完全不同的问题。也许您有竞争条件或需要更好锁定的非原子操作。

标签: c# .net math


【解决方案1】:

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

【讨论】:

  • 另外,ints 可以进行溢出检查。
  • @millimoose:如果溢出导致异常,那么,是的,那会破坏事情。如果他们只是“翻转”,那么申请顺序应该无关紧要。
  • 在 C# both are possible 中,翻转是默认的 IIRC。 (当然与 OP 并不特别相关,但仍然如此。)
【解决方案2】:

假设没有发生未经检查的溢出,.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

【讨论】:

  • 未经检查的溢出实际上不会破坏交换性或关联性(对于整数,浮点数是另一回事)。但是,检查溢出确实如此。
【解决方案3】:

在并行化约简中:

floats.AsParallel().Sum();

...您每次都可以期待不同的结果。这是因为每次对工作进行不同的分区,导致相加时出现不同的舍入误差。

要尽量减少这个问题,请确保使用双精度而不是浮点数进行归约。如果您想要按位相同的结果,则不应使用 TPL 或 PLINQ,而应使用自己的并行计算。

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

【讨论】:

    【解决方案4】:

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

    0x7fffffff + 0x80000000 + 0xffffffff 为例。结果是0xfffffffe(又名-2),不管你怎么加括号。但是(0x7fffffff + 0x80000000) + 0xffffffff 不会溢出,而0x7fffffff + (0x80000000 + 0xffffffff) 会溢出两次。 (在无符号算术中,它们都会溢出一次)

    一般情况下也是如此。 a + (b + c) = (a + b) + c 在 C#(如果是 unchecked)和 Java 中的整数。在 C 和 C++ 中,这仅对无符号整数有保证,因为有符号溢出是未定义的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-05
      相关资源
      最近更新 更多