Переполнение безопасного суммирования

13

Предположим, мне дано целых чисел фиксированной ширины (т.е. они помещаются в регистр ширины ), , так что их сумма a 1 + a 2 + + a n = S также помещается в регистр ширины ш .nwa1,a2,ana1+a2++an=Sw

Мне кажется, что мы всегда можем переставить числа в b1,b2,bn , чтобы каждая префиксная сумма Si=b1+b2++bi также помещалась в регистр ширины w .

По сути, мотивация состоит в том, чтобы вычислять сумму S=Sn на машинах с фиксированной шириной, не беспокоясь о целочисленных переполнениях на любом промежуточном этапе.

Существует ли быстрый (предпочтительно линейное время) алгоритм для поиска такой перестановки (при условии, что заданы как входной массив)? (или скажем, если такой перестановки не существует).ai

Арьябхата
источник
3
Последующие действия: обнаружение переполнения при суммировании - есть ли более быстрый метод, учитывающий типичные характеристики процессора?
Жиль "ТАК - перестань быть злым"
1
Просто используйте два регистра дополнения и суммируйте их. Даже если в середине произойдет переполнение, ваше предварительное условие гарантирует, что переполнения будут отменены, и результат будет правильным. : P
CodesInChaos
@CodeInChaos: это правда?
Арьябхата
1
Я думаю так. По сути, вы работаете в группе по модулю 2 ^ n, где вы выбираете каноническое представление от -2^(n-1)до 2^(n-1)-1. Конечно, требуется два дополнения и четко определенное поведение переполнения, но в языке, подобном C #, это должно работать.
CodesInChaos,
@CodeInChaos: нет ли двух вариантов, которые дают одинаковый остаток по модулю ? Вы в основном говорите, независимо от порядка, один из них никогда не может произойти. Или я что-то упустил? 2n
Арьябхата

Ответы:

10

Стратегия
Следующий алгоритм линейного времени принимает стратегию зависания около , выбирая положительные или отрицательные числа на основе знака частичной суммы. Он предварительно обрабатывает список номеров; он вычисляет перестановку входных данных на лету при выполнении сложения.0

Алгоритм

  1. Partition 1 , ... , п в двух списках, положительные элементы P и отрицательные элементы M . Нули можно отфильтровать.a1,...,aNпM
  2. Пусть .SUмзнак равно0
  3. Хотя оба списка не пусты
  4.       Если { S u m : = S u m + головка ( M ) ; М : = хвост ( М ) ; }SUм>0SUмзнак равноSUм+голова(M)Mзнак равнохвост(M)
  5.       иначе { ; P : = хвост ( P ) ; }SUмзнак равноSUм+голова(п)пзнак равнохвост(п)
  6. Когда один из двух списков станет пустым, добавьте остальную часть оставшегося списка на .S

Корректность
Корректность может быть установлена ​​с помощью прямого индуктивного аргумента длины списка чисел.

Прежде всего, докажите, что если все положительные (или все отрицательные) и их сумма не вызывает переполнения, то и суммы префиксов не делайте. Это просто.a1,...,aN

Во-вторых, доказать, что находится в пределах границ, является инвариантом цикла алгоритма. Понятно, что это верно при входе в цикл, так как S u m = 0 . Теперь, если S u m > 0 , добавление отрицательного числа, которое находится в пределах границ к S u m , не приводит к тому, что S u m выходит за пределы. Аналогично, когда S u m 0, добавление к сумме положительного числа, которое находится в пределах границ, не приводит к выходу S u m за пределы. Таким образом, выходя из цикла,SUмSUмзнак равно0SUм>0SUмSUмSUм0SUм находитсяпределах границ.SUм

Теперь можно применить первый результат, и их вместе достаточно, чтобы доказать, что сумма никогда не выходит за пределы.

Дэйв Кларк
источник
Для эффективной реализации на месте выполните a) разделение быстрой сортировки (вариант с двумя указателями) с неявным pivot и затем b) суммируйте, перемещая указатель каждый через область с отрицательным соотв. положительные числа. 0
Рафаэль