Per ottenere la somma esatta di un long[]
sto usando il seguente frammento.somma esatta di un lungo array
public static BigInteger sum(long[] a) {
long low = 0;
long high = 0;
for (final long x : a) {
low += (x & 0xFFFF_FFFFL);
high += (x >> 32);
}
return BigInteger.valueOf(high).shiftLeft(32).add(BigInteger.valueOf(low));
}
Funziona bene elaborando i numeri divisi in due metà e infine combinando le somme parziali. Sorprendentemente, questo metodo funziona anche:
public static BigInteger fastestSum(long[] a) {
long low = 0;
long high = 0;
for (final long x : a) {
low += x;
high += (x >> 32);
}
// We know that low has the lowest 64 bits of the exact sum.
// We also know that BigInteger.valueOf(high).shiftLeft(32) differs from the exact sum by less than 2**63.
// So the upper half of high is off by at most one.
high >>= 32;
if (low < 0) ++high; // Surprisingly, this is enough to fix it.
return BigInteger.valueOf(high).shiftLeft(64).add(BigInteger.valueOf(low));
}
Io Non credono che il fastestSum
dovrebbe funzionare come è. Credo che possa funzionare, ma che qualcosa di più deve essere fatto nella fase finale. Tuttavia, passa tutti i miei test (compresi test casuali di grandi dimensioni). Quindi, sto chiedendo: Qualcuno può provare che funziona o trovare un controesempio?
Dovrebbe funzionare, ma, a mia conoscenza, si dipende da un comportamento non definito. Soprattutto [** Gli operatori interi non indicano overflow o underflow in alcun modo **] (https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.2 .2 # JLS-4.2.2). – dhke
@dhke, forse stai confondendo Java con C. JLS 15.18.2 dice, in parte, "Se un'aggiunta integer sovrasta, il risultato sono i bit di ordine inferiore della somma matematica rappresentati in alcuni due sufficientemente grandi -completamento del formato Se si verifica un overflow, il segno del risultato non è uguale al segno della somma matematica dei due valori dell'operando. " Il linguaggio Java ha un comportamento piccolo, se non definito, almeno per i programmi a thread singolo. –
@JohnBollinger Concordato. Come scrive dhke, non ci sono indicazioni di overflow, ma non ne utilizzo. E il risultato è corretto mod 2 ** 64, quindi i minimi 64 bit sono corretti. Sono solo preoccupato per i 32 bit più alti. – maaartinus