Sommatoria sicura di tracimazione


13

Supponiamo che mi vengano dati numeri interi a larghezza fissa (cioè si inseriscano in un registro di larghezza w ), a 1 , a 2 , ... a n tale che la loro somma a 1 + a 2 + + a n = S si inserisca anche in un registro di larghezza w .nwa1,a2,ana1+a2++an=Sw

Mi sembra che possiamo sempre permutare i numeri per tale che ogni somma prefisso S i = b 1 + b 2 + + b i rientra anche a un registro di larghezza w .b1,b2,bnSi=b1+b2++biw

Fondamentalmente, la motivazione è calcolare la somma su macchine a registro a larghezza fissa senza doversi preoccupare di overflow di numeri interi in qualsiasi fase intermedia.S=Sn

C'è un rapido (tempo preferibilmente aria) algoritmo per trovare una tale permutazione (assumendo che il sono date come un array input)? (o dire se tale permutazione non esiste).ai


3
Follow-up: rilevamento dell'overflow in somma : esiste un metodo più veloce che tiene conto delle caratteristiche tipiche del processore?
Gilles 'SO- smetti di essere cattivo' il

1
Basta usare due registri complemento e sommarli. Anche se trabocca nel mezzo, la tua pre-condizione garantisce che gli overflow si annullino e il risultato sarà corretto. : P
Codici A Caos il

@CodeInChaos: è davvero vero?
Aryabhata,

1
Credo di si. In pratica stai lavorando in un gruppo modulo 2 ^ n, dove scegli la rappresentazione canonica da -2^(n-1)a 2^(n-1)-1. Naturalmente richiede il complemento a due e un comportamento di overflow ben definito, ma in un linguaggio come C # dovrebbe funzionare.
CodesInChaos

@CodeInChaos: Non ci sono due possibilità che danno lo stesso resto modulo ? In pratica stai dicendo, indipendentemente dall'ordine, uno di loro non può mai accadere. Oppure mi sfugge qualcosa? 2n
Aryabhata,

Risposte:


10

Strategia
Il seguente algoritmo a tempo lineare adotta la strategia di rimanere in bilico intorno a , scegliendo numeri positivi o negativi in ​​base al segno della somma parziale. Elabora la lista dei numeri; calcola la permutazione dell'input al volo , mentre esegue l'aggiunta.0

Algoritmo

  1. Partizionare in un due liste, gli elementi positivi P e gli elementi negativi M . Gli zeri possono essere filtrati.a1,,anPM
  2. Sia .Sum=0
  3. Mentre entrambi gli elenchi sono non vuoti
  4.       Se { S u m : = S u m + testa ( M ) ; M : = coda ( M ) ; }Sum>0Sum:=Sum+head(M)M:=tail(M)
  5.       else { ; P : = coda ( P ) ; }Sum:=Sum+head(P)P:=tail(P)
  6. Quando una delle due liste si svuota, aggiungere il resto della lista rimanente per .S

Correttezza La
correttezza può essere stabilita usando un semplice argomento induttivo sulla lunghezza dell'elenco di numeri.

Innanzitutto, prova che se sono tutti positivi (o tutti negativi), e la loro somma non provoca overflow, allora non fanno neppure le somme del prefisso. Questo è semplice.a1,,an

In secondo luogo, dimostrare che è all'interno dei limiti è un invariante del ciclo dell'algoritmo. Chiaramente, questo è vero all'entrata nel loop, come S u m = 0 . Ora, se S u m > 0 , l'aggiunta di un numero negativo entro i limiti a S u m non fa sì che S u m esca dai limiti. Allo stesso modo, quando S u m 0 sommando un numero positivo entro i limiti da sommare non fa sì che S u m esca dai limiti. Quindi all'uscita dal loop,SumSum=0Sum>0SumSumSum0Sum è nei limiti.Sum

Ora, il primo risultato può essere applicato e insieme questi sono sufficienti per dimostrare che la somma non va mai oltre i limiti.


Verso un'implementazione sul posto efficiente, eseguire a) Quicksort-partitioning (la variante a due puntatori) con pivot implicito e quindi b) sommare, spostando un puntatore ciascuno attraverso l'area con resp. numeri positivi. 0
Raffaello
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.