溢出安全求和


13

假设我给了固定宽度的整数(即它们适合宽度w的寄存器),a_1,a_2,\点a_n,使得它们的和a_1 + a_2 + \ dots + a_n = S也适合宽度w的寄存器。na 1a 2a n a 1 + a 2 + + a n = S wwa1,a2,ana1+a2++an=Sw

在我看来,我们总是可以将数字置换为b1,b2,bn,以便每个前缀和Si=b1+b2++bi也适合宽度为w的寄存器w

基本上,动机是在固定宽度的寄存器机器上计算总和S=Sn,而不必担心任何中间阶段的整数溢出。

是否有一种快速(最好是线性时间)算法来找到这种排列(假设ai作为输入数组给出)?(或者说是否不存在这样的排列)。


3
后续措施:检测总和中的溢出 -是否有一种更快的方法考虑了典型的处理器功能?
吉尔(Gilles)'所以

1
只需使用二进制补码寄存器求和即可。即使它在中间溢出,您的前提条件也保证溢出将被抵消,并且结果将是正确的。:P
CodesInChaos

@CodeInChaos:真的吗?
Aryabhata 2012年

1
我认同。你基本上在一组模2 ^ n,其中您选择从规范化表示工作-2^(n-1)2^(n-1)-1。当然,它需要二进制补码和定义明确的溢出行为,但是在像C#这样的语言中,它应该可以工作。
CodesInChaos 2012年

@CodeInChaos:难道没有两种可能性可以给相同的余数取模吗?您基本上是在说,无论顺序如何,都永远不会发生其中之一。还是我错过了什么?2n
Aryabhata 2012年

Answers:


10

策略
以下线性时间算法采用基于部分和的符号选择正数或负数来在左右徘徊的策略。预处理数字列表;在执行加法时,它会即时计算输入的排列。0

算法

  1. 分区成两个列表中,正元件和负极元件。零可以被过滤掉。 P 中号a1,,anPM
  2. 令。Sum=0
  3. 虽然两个列表都是非空的
  4.       如果 { ; ; }S u m = S u m + M M = 尾巴M Sum>0Sum:=Sum+head(M)M:=tail(M)
  5.        else { ; ; }P = 尾巴P Sum:=Sum+head(P)P:=tail(P)
  6. 当两个列表中的一个变空,加入剩余的列表的其余。S

正确性
可以在数字列表的长度上使用简单的归纳参数来确定正确性。

首先,证明如果全部为正(或全部为负),并且它们的和不会引起溢出,则前缀和也不会。这很简单。a1,,an

其次,证明在范围之内是算法循环的不变性。显然,这在进入循环时是正确的,因为。现在,如果,在范围内添加负数不会导致超出范围。类似地,当添加在范围内的正数时,不会导致超出范围。因此,退出循环后,在范围之内。小号Ù = 0 小号ü > 0 小号ü 小号ü 小号ü 0 小号ü 小号ù SumSum=0Sum>0SumSumSum0SumSum

现在,可以应用第一个结果,并且这些结果加在一起足以证明总和永远不会超出范围。


为了实现高效的就地实现,请执行以下操作:a)使用隐式枢轴进行Quicksort分区(双指针变体),然后b)求和,将每个指针以负响应的方式移动通过区域。正数。0
拉斐尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.