Bezpieczne podsumowanie przelewu

13

Załóżmy, że podano mi liczb całkowitych o stałej szerokości (tzn. Mieszczą się one w rejestrze szerokości ), tak że ich suma również mieści się w rejestrze szerokości .w a 1 , a 2 , a n a 1 + a 2 + + a n = S wnwa1,a2,ana1+a2++an=Sw

Wydaje mi się, że zawsze możemy permutować liczby na tak, że każda suma prefiksu również mieści się w rejestrze szerokości .S i = b 1 + b 2 + + b i wb1,b2,bnSi=b1+b2++biw

Zasadniczo motywacją jest obliczenie sumy na maszynach o stałej szerokości bez martwienia się o przelanie liczb całkowitych na dowolnym etapie pośrednim.S=Sn

Czy istnieje szybki (najlepiej liniowy czas) algorytm do znalezienia takiej permutacji (zakładając, że podano jako tablicę wejściową)? (lub powiedzieć, czy taka permutacja nie istnieje).ai

Aryabhata
źródło
3
Dalsze działania: Wykrywanie przepełnienia sumowania - czy istnieje szybsza metoda, która uwzględnia typowe funkcje procesora?
Gilles 'SO - przestań być zły'
1
Wystarczy użyć rejestrów uzupełnienia do dwóch i zsumować je. Nawet jeśli przepełni się w środku, twój warunek wstępny gwarantuje, że przepełnienia zostaną anulowane, a wynik będzie prawidłowy. : P
CodesInChaos
@CodeInChaos: Czy to naprawdę prawda?
Aryabhata
1
Chyba tak. Zasadniczo pracujesz w grupowym module 2 ^ n, w którym wybierasz reprezentację kanoniczną od -2^(n-1)do 2^(n-1)-1. Wymaga to oczywiście uzupełnienia dwóch i dobrze zdefiniowanego zachowania przepełnienia, ale w języku takim jak C # powinno działać.
CodesInChaos
@CodeInChaos: Czy nie ma dwóch możliwości, które dają tę samą resztę modulo ? Mówisz w zasadzie, bez względu na zamówienie, jeden z nich nigdy się nie wydarzy. A może coś mi brakuje? 2n
Aryabhata

Odpowiedzi:

10

Strategia
Poniższy algorytm czasu liniowego przyjmuje strategię najechania kursorem około , wybierając liczby dodatnie lub ujemne na podstawie znaku sumy częściowej. Przetwarza listę liczb; oblicza permutację danych wejściowych w locie podczas wykonywania dodawania.0

Algorytm

  1. Partycja do obu listach, pozytywne elementy i negatywne elementy . Zera można odfiltrować. P Ma1,,anPM
  2. Niech .Sum=0
  3. Chociaż obie listy nie są puste
  4.        If { ; ; }Sum>0Sum:=Sum+head(M)M:=tail(M)
  5.        else { ; ; }Sum:=Sum+head(P)P:=tail(P)
  6. Gdy jeden z dwóch list staje się pusta, dodać resztę pozostałego do listy .S

Poprawność
Poprawność można ustalić za pomocą prostego argumentu indukcyjnego dotyczącego długości listy liczb.

Po pierwsze, udowodnij, że jeśli są dodatnie (lub wszystkie ujemne), a ich suma nie powoduje przepełnienia, to też nie sumują prefiksu. To jest proste.a1,,an

Po drugie, udowodnienie, że mieści się w granicach, jest niezmiennikiem pętli algorytmu. Oczywiście jest to prawdą po wejściu do pętli, ponieważ . Teraz, jeśli , dodanie liczby ujemnej mieszczącej się w granicach do nie spowoduje, że przekroczy granice. Podobnie, gdy dodanie liczby dodatniej, która jest w granicach do sumy, nie powoduje, że wychodzi poza granice. Zatem po wyjściu z pętli mieści się w granicach.S u m = 0 S u m > 0 S u m S u m S u m 0 S u m S u mSumSum=0Sum>0SumSumSum0SumSum

Teraz można zastosować pierwszy wynik i razem są one wystarczające, aby udowodnić, że suma nigdy nie wychodzi poza granice.

Dave Clarke
źródło
W kierunku wydajnej implementacji w miejscu wykonaj a) Szybkie dzielenie na partycje (wariant z dwoma wskaźnikami) z niejawną osią a następnie b ) zsumuj , przesuwając wskaźnik przez obszar z ujemnym resp. liczby dodatnie. 0
Raphael