Come posso rilevare l'overflow della moltiplicazione dei numeri interi senza segno?


618

Stavo scrivendo un programma in C ++ per trovare tutte le soluzioni di un b = c , dove un , b e c insieme utilizzano tutte le cifre 0-9 esattamente una volta. Il programma eseguito ciclicamente i valori di un e b , e ha una routine cifre conteggio ogni volta su un , b ed un b per verificare se la condizione cifre stata soddisfatta.

Tuttavia, è possibile generare soluzioni spurie quando a b trabocca il limite intero. Ho finito per verificare questo usando un codice come:

unsigned long b, c, c_test;
...
c_test=c*b;         // Possible overflow
if (c_test/b != c) {/* There has been an overflow*/}
else c=c_test;      // No overflow

Esiste un modo migliore di testare l'overflow? So che alcuni chip hanno un flag interno impostato quando si verifica un overflow, ma non ho mai visto l'accesso tramite C o C ++.


Fai attenzione che l' overflow firmato int è un comportamento indefinito in C e C ++ e quindi devi rilevarlo senza effettivamente causarlo. Per l'overflow firmato int prima dell'aggiunta, vedere Rilevamento dell'overflow firmato in C / C ++ .


21
Informazioni che potrebbero essere utili su questo argomento: Capitolo 5 di "Codifica sicura in C e C ++" di Seacord - http://www.informit.com/content/images/0321335724/samplechapter/seacord_ch05.pdf Classi SafeInt per C ++ - http : //blogs.msdn.com/david_leblanc/archive/2008/09/30/safeint-3-on-codeplex.aspx - http://www.codeplex.com/SafeInt Libreria IntSafe per C: - [ blogs.msdn .com / michael_howard / archiv
Michael Burr,

3
Seacord's Secure Coding è un'ottima risorsa, ma non usare IntegerLib. Vedi blog.regehr.org/archives/593 .
1111

32
L'opzione del compilatore gcc -ftrapvfarà sì che generi un SIGABRT su overflow di numeri interi (con segno). Vedi qui .
nibot,

1
Non risponde alla domanda di overflow, ma un altro modo di affrontare il problema sarebbe quello di utilizzare una libreria BigNum come GMP per garantire sempre una precisione sufficiente. Non dovrai preoccuparti di overflow se assegni abbastanza cifre in anticipo.
Wrdieter,

1
Le informazioni fornite da @HeadGeek nella sua risposta sono più o meno quelle che direi. Tuttavia, con un'aggiunta. Il modo in cui stai rilevando overflow per una moltiplicazione ora è probabilmente il più veloce. Su ARM, come ho commentato nella risposta di HeadGeek, puoi utilizzare l' clzistruzione o la __clz(unsigned)funzione per determinare il rango del numero (dove si trova il suo bit più alto). Poiché non sono sicuro che sia disponibile su x86 o x64, suppongo che non lo sia e dirò che trovare il bit più significativo richiederà le peggiori log(sizeof(int)*8)istruzioni.
nonsensickle

Risposte:


229

Vedo che stai utilizzando numeri interi senza segno. Per definizione, in C (non conosco C ++), l'aritmetica senza segno non trabocca ... quindi, almeno per C, il tuo punto è discutibile :)

Con numeri interi con segno, una volta che si è verificato un overflow, si è verificato un comportamento indefinito (UB) e il programma può fare qualsiasi cosa (ad esempio: rendere i test inconcludenti). 

#include <limits.h>

int a = <something>;
int x = <something>;
a += x;              /* UB */
if (a < 0) {         /* Unreliable test */
  /* ... */
}

Per creare un programma conforme, è necessario verificare l'overflow prima di generare tale overflow. Il metodo può essere utilizzato anche con numeri interi senza segno:

// For addition
#include <limits.h>

int a = <something>;
int x = <something>;
if ((x > 0) && (a > INT_MAX - x)) /* `a + x` would overflow */;
if ((x < 0) && (a < INT_MIN - x)) /* `a + x` would underflow */;

// For subtraction
#include <limits.h>
int a = <something>;
int x = <something>;
if ((x < 0) && (a > INT_MAX + x)) /* `a - x` would overflow */;
if ((x > 0) && (a < INT_MIN + x)) /* `a - x` would underflow */;

// For multiplication
#include <limits.h>

int a = <something>;
int x = <something>;
// There may be a need to check for -1 for two's complement machines.
// If one number is -1 and another is INT_MIN, multiplying them we get abs(INT_MIN) which is 1 higher than INT_MAX
if ((a == -1) && (x == INT_MIN)) /* `a * x` can overflow */
if ((x == -1) && (a == INT_MIN)) /* `a * x` (or `a / x`) can overflow */
// general case
if (a > INT_MAX / x) /* `a * x` would overflow */;
if ((a < INT_MIN / x)) /* `a * x` would underflow */;

Per la divisione (eccetto la INT_MINe -1caso particolare), non v'è alcuna possibilità di andare oltre INT_MINo INT_MAX.


97
I numeri interi senza segno non si sovrappongono strettamente in C ++ (ISO / IEC 14882: 2003 3.9.1.4). Il mio uso di "overflow" nella domanda era il significato più colloquiale, inteso a includere il wrapping ben definito di tipi senza segno, poiché ero interessato a interi senza segno che rappresentavano numeri interi matematici positivi, non numeri interi positivi mod 2 ^ 32 (o 2 ^ 64). La distinzione tra overflow come deviazione dal comportamento matematico di numeri interi infiniti e overflow come comportamento indefinito nel linguaggio sembra raramente essere resa esplicita.
Chris Johnson,

15
Quel test non ha bisogno di essere x >= 0- x > 0sarà sufficiente (se x == 0, quindi x + anon può traboccare per ovvi motivi).
caf

2
@pmg, c'è una citazione di supporto dallo standard?
Pacerier,

5
Mi piace questo approccio ... Tuttavia, fai attenzione: il rilevamento dell'overflow di moltiplicazione assume una x positiva. Per x == 0, porta alla divisione per rilevamento zero e per x negativo, rileva sempre erroneamente l'overflow.
Franz D.

4
if ((a < INT_MIN / x))il test è troppo tardi. È if (x == -1) necessario prima un test.
chux - Ripristina Monica l'

164

Non è un modo per determinare se un'operazione possa troppopieno, utilizzando le posizioni dei più significativi one-bit operandi e un po 'di conoscenza di base binaria matematica.

Inoltre, ogni due operandi comporterà (al massimo) un bit in più rispetto al massimo a un bit dell'operando più grande. Per esempio:

bool addition_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
    return (a_bits<32 && b_bits<32);
}

Per la moltiplicazione, ogni due operandi comporterà (al massimo) la somma dei bit degli operandi. Per esempio:

bool multiplication_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
    return (a_bits+b_bits<=32);
}

Allo stesso modo, puoi stimare la dimensione massima del risultato aalla potenza di in bquesto modo:

bool exponentiation_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a);
    return (a_bits*b<=32);
}

(Sostituisci il numero di bit per il tuo intero di destinazione, ovviamente.)

Non sono sicuro del modo più veloce per determinare la posizione del bit più alto in un numero, ecco un metodo a forza bruta:

size_t highestOneBitPosition(uint32_t a) {
    size_t bits=0;
    while (a!=0) {
        ++bits;
        a>>=1;
    };
    return bits;
}

Non è perfetto, ma ciò ti darà una buona idea se due numeri potrebbero traboccare prima di eseguire l'operazione. Non so se sarebbe più veloce del semplice controllo del risultato nel modo che hai suggerito, a causa del loop nella highestOneBitPositionfunzione, ma potrebbe (specialmente se in precedenza sapessi quanti bit c'erano negli operandi).


98
e ovviamente potresti rinominare la più altaOneBitPosition per accedere :)
Oliver Hallam

37
Sì, è la stessa operazione di log2, ma non sarebbe necessariamente ovvio per qualcuno che non aveva una preparazione matematica.
Head Geek,

48
Questo algoritmo non sottovaluta le risposte sicure? 2 ^ 31 + 0 verrebbe rilevato come non sicuro in quanto più altoOneBitPosition (2 ^ 31) = 32. (2 ^ 32 - 1) * 1 rilevato come non sicuro da 32 + 1> 32. 1 ^ 100 rilevato come non sicuro da 1 * 100 > 32.
clahey,

19
secondo il tuo multiplication_is_safe 0x8000 * 0x10000overflow (le posizioni dei bit sono 16 + 17 = 33 che è > 32 ), anche se non lo fa perché 0x8000 * 0x10000 = 0x80000000ovviamente si adatta ancora a un int senza segno a 32 bit. Questo è solo uno degli esempi di maggio per i quali questo codice non funziona. 0x8000 * 0x10001, ...
Michi il

13
@GT_mh: il tuo punto? Come ho già detto, non è perfetto; è una regola empirica che dirà definitivamente quando qualcosa è sicuro, ma non c'è modo di determinare se ogni calcolo andrebbe bene senza fare il calcolo completo. 0x8000 * 0x10000non è "sicuro" da questa definizione, anche se risulta essere a posto.
Head Geek

147

Clang 3.4+ e GCC 5+ offrono built-in aritmetici controllati. Offrono una soluzione molto rapida a questo problema, soprattutto se confrontato con i controlli di sicurezza dei bit-test.

Per l'esempio nella domanda di OP, funzionerebbe così:

unsigned long b, c, c_test;
if (__builtin_umull_overflow(b, c, &c_test))
{
    // Returned non-zero: there has been an overflow
}
else
{
    // Return zero: there hasn't been an overflow
}

La documentazione di Clang non specifica se c_testcontiene il risultato di overflow se si è verificato un overflow, ma la documentazione di GCC afferma che lo fa. Dato che a questi due piace essere__builtin compatibili, probabilmente è sicuro supporre che sia così che funziona anche Clang.

Esiste un'operazione __builtinper ogni operazione aritmetica che può traboccare (addizione, sottrazione, moltiplicazione), con varianti firmate e non firmate, per dimensioni int, lunghe e lunghe. La sintassi per il nome è __builtin_[us](operation)(l?l?)_overflow:

  • uper non firmato o sper firmato ;
  • operazione è una delle add, suboppure mul;
  • nessun lsuffisso significa che gli operandi sono ints; uno lsignifica long; due ls media long long.

Quindi, per un'aggiunta intera lunga firmata controllata, sarebbe __builtin_saddl_overflow. L'elenco completo è disponibile nella pagina della documentazione di Clang .

GCC 5+ e Clang 3.8+ offrono inoltre builtins generici che funzionano senza specificare il tipo dei valori: __builtin_add_overflow, __builtin_sub_overflowe __builtin_mul_overflow. Funzionano anche su tipi più piccoli di int.

I builtin si abbassano a ciò che è meglio per la piattaforma. Su x86, controllano le bandiere carry, overflow e sign.

Il file cl.exe di Visual Studio non ha equivalenti diretti. Per aggiunte e sottrazioni non firmate, includerai <intrin.h>ti permetterà di usare addcarry_uNNe subborrow_uNN(dove NN è il numero di bit, come addcarry_u8o subborrow_u64). La loro firma è un po 'ottusa:

unsigned char _addcarry_u32(unsigned char c_in, unsigned int src1, unsigned int src2, unsigned int *sum);
unsigned char _subborrow_u32(unsigned char b_in, unsigned int src1, unsigned int src2, unsigned int *diff);

c_in/b_in è il flag carry / loan sull'input e il valore di ritorno è il carry / loan sull'output. Non sembra avere equivalenti per operazioni firmate o moltiplicazioni.

Altrimenti, Clang per Windows è ora pronto per la produzione (abbastanza buono per Chrome), quindi potrebbe essere anche un'opzione.


__builtin_sub_overflownon è sicuramente in Clang 3.4.
Richard Cook,

2
@RichardCook, ci è voluto del tempo ma Clang ha i builtin generici dalla versione 3.9.
zneak,

@tambre, non credo ci siano.
zneak,

4
Secondo i documenti , __builtin_add_overflowe gli amici dovrebbero già essere disponibili su Clang 3.8.
Lekensteyn,

2
Grazie. Funziona benissimo. Qualche idea su quale sia la funzione corrispondente per Visual c ++? Non riesco a trovarli.
Mudit Jain,

53

Alcuni compilatori forniscono l'accesso al flag di overflow dei numeri interi nella CPU che è possibile testare, ma questo non è standard.

È inoltre possibile verificare la possibilità di overflow prima di eseguire la moltiplicazione:

if ( b > ULONG_MAX / a ) // a * b would overflow

11
... oppure usa numeric_limits <TYPE> :: max ()
Jonas Gulle,

20
Non dimenticare di gestire a = 0 - quindi le interruzioni di divisione.
Thelema,

16
@Thelema: "Non dimenticare di gestire a = 0" - e INT_MIN / -1.
1111

1
E se b == ULONG_MAX / a? Quindi può ancora adattarsi, dato che adivide ULONG_MAXsenza residui.
il suino

Divertente che, per quanto riguarda le prestazioni, una moltiplicazione è piuttosto veloce rispetto a una divisione e stai aggiungendo una divisione per ogni moltiplicazione. Questa non sembra la soluzione.
DrumM,

40

Avvertenza: GCC può ottimizzare un controllo di overflow durante la compilazione -O2. L'opzione -Wallti darà un avviso in alcuni casi come

if (a + b < a) { /* Deal with overflow */ }

ma non in questo esempio:

b = abs(a);
if (b < 0) { /* Deal with overflow */ }

L'unico modo sicuro è quello di verificare l'overflow prima che si verifichi, come descritto nel documento CERT , e questo sarebbe incredibilmente noioso da usare sistematicamente.

La compilazione con -fwrapvrisolve il problema, ma disabilita alcune ottimizzazioni.

Abbiamo disperatamente bisogno di una soluzione migliore. Penso che il compilatore dovrebbe emettere un avviso di default quando si effettua un'ottimizzazione che si basa sul overflow che non si verifica. La situazione attuale consente al compilatore di ottimizzare un controllo di overflow, il che è inaccettabile secondo me.


8
Si noti che i compilatori possono fare solo con firmati tipi interi; l'overflow è completamente definito per i tipi interi senza segno. Tuttavia, sì, è una trappola abbastanza pericolosa!
SamB

1
"Penso che il compilatore dovrebbe emettere un avviso di default quando si effettua un'ottimizzazione che si basa sul overflow che non si verifica." - quindi for(int k = 0; k < 5; k++) {...}dovrebbe emettere un avvertimento?
user253751

2
@immibis: Perché dovrebbe? I valori di kpossono essere facilmente determinati al momento della compilazione. Il compilatore non deve fare alcuna ipotesi.
MikeMB,

2
@immibis: Per citare quanto sopra: "Penso che il compilatore dovrebbe emettere un avviso di default quando si effettua un'ottimizzazione che si basa sul overflow che non si verifica."
MikeMB,

1
@MikeMB L'ottimizzazione in cui il compilatore non si preoccupa di verificare che nsia inferiore a 32, prima di emettere un'istruzione shift che utilizza solo i 5 bit inferiori di n?
user253751,

30

Clang ora supporta i controlli di overflow dinamico per numeri interi sia firmati che non firmati. Vedi l' opzione -fsanitize = intero . Per ora, è l'unico compilatore C ++ con controllo dinamico di overflow completamente supportato per scopi di debug.


25

Vedo che molte persone hanno risposto alla domanda sull'overflow, ma volevo affrontare il suo problema originale. Ha detto che il problema era trovare una b = c in modo tale che tutte le cifre vengano utilizzate senza ripetere. Ok, non è quello che ha chiesto in questo post, ma penso ancora che fosse necessario studiare il limite superiore del problema e concludere che non avrebbe mai bisogno di calcolare o rilevare un overflow (nota: non sono competente in matematica quindi ho fatto questo passo per passo, ma il risultato finale è stato così semplice che questo potrebbe avere una formula semplice).

Il punto principale è che il limite superiore richiesto dal problema per a, b o c è 98.765.432. Ad ogni modo, iniziando dividendo il problema nelle parti banali e non banali:

  • x 0 == 1 (tutte le permutazioni di 9, 8, 7, 6, 5, 4, 3, 2 sono soluzioni)
  • x 1 == x (nessuna soluzione possibile)
  • 0 b == 0 (nessuna soluzione possibile)
  • 1 b == 1 (nessuna soluzione possibile)
  • a b , a> 1, b> 1 (non banale)

Ora non ci resta che dimostrare che non sono possibili altre soluzioni e che solo le permutazioni sono valide (e quindi il codice per stamparle è banale). Torniamo al limite superiore. In realtà il limite superiore è c ≤ 98.765.432. È il limite superiore perché è il numero più grande con 8 cifre (10 cifre in totale meno 1 per ciascuna aeb). Questo limite superiore è solo per c perché i limiti di aeb devono essere molto più bassi a causa della crescita esponenziale, come possiamo calcolare, variando b da 2 al limite superiore:

    9938.08^2 == 98765432
    462.241^3 == 98765432
    99.6899^4 == 98765432
    39.7119^5 == 98765432
    21.4998^6 == 98765432
    13.8703^7 == 98765432
    9.98448^8 == 98765432
    7.73196^9 == 98765432
    6.30174^10 == 98765432
    5.33068^11 == 98765432
    4.63679^12 == 98765432
    4.12069^13 == 98765432
    3.72429^14 == 98765432
    3.41172^15 == 98765432
    3.15982^16 == 98765432
    2.95305^17 == 98765432
    2.78064^18 == 98765432
    2.63493^19 == 98765432
    2.51033^20 == 98765432
    2.40268^21 == 98765432
    2.30883^22 == 98765432
    2.22634^23 == 98765432
    2.15332^24 == 98765432
    2.08826^25 == 98765432
    2.02995^26 == 98765432
    1.97741^27 == 98765432

Si noti, ad esempio, l'ultima riga: si dice che 1.97 ^ 27 ~ 98M. Quindi, ad esempio, 1 ^ 27 == 1 e 2 ^ 27 == 134.217.728 e questa non è una soluzione perché ha 9 cifre (2> 1.97, quindi in realtà è più grande di ciò che dovrebbe essere testato). Come si può vedere, le combinazioni disponibili per il test aeb sono davvero piccole. Per b == 14, dobbiamo provare 2 e 3. Per b == 3, iniziamo da 2 e ci fermiamo a 462. Tutti i risultati sono garantiti per essere inferiori a ~ 98M.

Ora prova tutte le combinazioni sopra e cerca quelle che non ripetono alcuna cifra:

    ['0', '2', '4', '5', '6', '7', '8'] 84^2 = 7056
    ['1', '2', '3', '4', '5', '8', '9'] 59^2 = 3481
    ['0', '1', '2', '3', '4', '5', '8', '9'] 59^2 = 3481 (+leading zero)
    ['1', '2', '3', '5', '8'] 8^3 = 512
    ['0', '1', '2', '3', '5', '8'] 8^3 = 512 (+leading zero)
    ['1', '2', '4', '6'] 4^2 = 16
    ['0', '1', '2', '4', '6'] 4^2 = 16 (+leading zero)
    ['1', '2', '4', '6'] 2^4 = 16
    ['0', '1', '2', '4', '6'] 2^4 = 16 (+leading zero)
    ['1', '2', '8', '9'] 9^2 = 81
    ['0', '1', '2', '8', '9'] 9^2 = 81 (+leading zero)
    ['1', '3', '4', '8'] 3^4 = 81
    ['0', '1', '3', '4', '8'] 3^4 = 81 (+leading zero)
    ['2', '3', '6', '7', '9'] 3^6 = 729
    ['0', '2', '3', '6', '7', '9'] 3^6 = 729 (+leading zero)
    ['2', '3', '8'] 2^3 = 8
    ['0', '2', '3', '8'] 2^3 = 8 (+leading zero)
    ['2', '3', '9'] 3^2 = 9
    ['0', '2', '3', '9'] 3^2 = 9 (+leading zero)
    ['2', '4', '6', '8'] 8^2 = 64
    ['0', '2', '4', '6', '8'] 8^2 = 64 (+leading zero)
    ['2', '4', '7', '9'] 7^2 = 49
    ['0', '2', '4', '7', '9'] 7^2 = 49 (+leading zero)

Nessuno di questi corrisponde al problema (che può essere visto anche dall'assenza di '0', '1', ..., '9').

Il codice di esempio che lo risolve segue. Nota anche che è scritto in Python, non perché necessita di interi di precisione arbitrari (il codice non calcola nulla di più grande di 98 milioni), ma perché abbiamo scoperto che la quantità di test è così piccola che dovremmo usare un linguaggio di alto livello per fare uso dei suoi contenitori e librerie integrati (nota anche: il codice ha 28 righe).

    import math

    m = 98765432
    l = []
    for i in xrange(2, 98765432):
        inv = 1.0/i
        r = m**inv
        if (r < 2.0): break
        top = int(math.floor(r))
        assert(top <= m)

        for j in xrange(2, top+1):
            s = str(i) + str(j) + str(j**i)
            l.append((sorted(s), i, j, j**i))
            assert(j**i <= m)

    l.sort()
    for s, i, j, ji in l:
        assert(ji <= m)
        ss = sorted(set(s))
        if s == ss:
            print '%s %d^%d = %d' % (s, i, j, ji)

        # Try with non significant zero somewhere
        s = ['0'] + s
        ss = sorted(set(s))
        if s == ss:
            print '%s %d^%d = %d (+leading zero)' % (s, i, j, ji)

1
perché non usi 9.876.543.210 come limite superiore?
Tom Roggero,

3
Perché è necessario utilizzare 2 cifre per il lato sinistro dell'equazione.
hdante

2
Non che faccia la differenza, ma il limite superiore può effettivamente essere preso come 98765410 poiché hai dichiarato che i valori sull'LHS sono> 1
Paul Childs,

24

Ecco una soluzione "non portatile" alla domanda. Le CPU Intel x86 e x64 hanno il cosiddetto registro EFLAGS , che viene compilato dal processore dopo ogni operazione aritmetica intera. Salterò una descrizione dettagliata qui. I flag pertinenti sono il flag "Overflow" (maschera 0x800) e il flag "Carry" (maschera 0x1). Per interpretarli correttamente, si dovrebbe considerare se gli operandi sono di tipo con o senza segno.

Ecco un modo pratico per controllare i flag da C / C ++. Il codice seguente funzionerà su Visual Studio 2005 o versioni successive (sia a 32 che a 64 bit), nonché su GNU C / C ++ a 64 bit.

#include <cstddef>
#if defined( _MSC_VER )
#include <intrin.h>
#endif

inline size_t query_intel_x86_eflags(const size_t query_bit_mask)
{
    #if defined( _MSC_VER )

        return __readeflags() & query_bit_mask;

    #elif defined( __GNUC__ )
        // This code will work only on 64-bit GNU-C machines.
        // Tested and does NOT work with Intel C++ 10.1!
        size_t eflags;
        __asm__ __volatile__(
            "pushfq \n\t"
            "pop %%rax\n\t"
            "movq %%rax, %0\n\t"
            :"=r"(eflags)
            :
            :"%rax"
            );
        return eflags & query_bit_mask;

    #else

        #pragma message("No inline assembly will work with this compiler!")
            return 0;
    #endif
}

int main(int argc, char **argv)
{
    int x = 1000000000;
    int y = 20000;
    int z = x * y;
    int f = query_intel_x86_eflags(0x801);
    printf("%X\n", f);
}

Se gli operandi fossero moltiplicati senza overflow, otterresti un valore di ritorno di 0 da query_intel_eflags(0x801) , ovvero non sono impostati né i flag carry né overflow. Nel codice di esempio fornito principale (), si verifica un overflow e entrambi i flag sono impostati su 1. Questo controllo non implica ulteriori calcoli, quindi dovrebbe essere abbastanza veloce.


21

Se hai un tipo di dati che è più grande di quello che vuoi testare (supponi di fare un'aggiunta a 32 bit e di avere un tipo a 64 bit), questo rileverà se si è verificato un overflow. Il mio esempio è per un'aggiunta a 8 bit. Ma può essere ingrandito.

uint8_t x, y;    /* Give these values */
const uint16_t data16    = x + y;
const bool carry        = (data16 > 0xFF);
const bool overflow     = ((~(x ^ y)) & (x ^ data16) & 0x80);

Si basa sui concetti spiegati in questa pagina: http://www.cs.umd.edu/class/spring2003/cmsc311/Notes/Comb/overflow.html

Per un esempio a 32 bit, 0xFFdiventa 0xFFFFFFFFe 0x80diventa 0x80000000e infine uint16_tdiventa a uint64_t.

NOTA : questo intercetta overflow di addizione / sottrazione di numeri interi e mi sono reso conto che la tua domanda comporta una moltiplicazione. In tal caso, la divisione è probabilmente l'approccio migliore. Questo è comunemente un modo in cui le callocimplementazioni assicurano che i parametri non trabocchino quando vengono moltiplicati per ottenere la dimensione finale.


Il collegamento è interrotto: HTTP 403: proibito
Peter Mortensen,

18

Il modo più semplice è convertire le unsigned longs in unsigned long longs, fare la moltiplicazione e confrontare il risultato con 0x100000000LL.

Probabilmente scoprirai che questo è più efficiente che fare la divisione come hai fatto nel tuo esempio.

Oh, e funzionerà in C e C ++ (dato che hai taggato la domanda con entrambi).


Ho appena dato un'occhiata al manuale di glibc . C'è una menzione di una trappola per overflow di interi ( FPE_INTOVF_TRAP) come parte di SIGFPE. Sarebbe l'ideale, a parte le brutte parti del manuale:

FPE_INTOVF_TRAP Overflow intero (impossibile in un programma C a meno che non si abiliti il ​​trapping overflow in un modo specifico dell'hardware).

Un po 'un peccato davvero.


4
Heh ... quello che non ho detto è che sto ponendo questa domanda in preparazione della stesura di un programma per risolvere un problema con numeri più grandi, in cui sto già usando int long long. Poiché long long int non è (presumibilmente) nello standard C ++, mi sono bloccato con la versione a 32 bit per evitare confusione.
Chris Johnson,

Consiglierei di usare ULONG_MAXquale è più facile da scrivere e più portatile della codifica 0x100000000.
jw013,

24
Questo non funziona quando longe long longhanno le stesse dimensioni (ad esempio su molti compilatori a 64 bit).
Interjay

Fare affidamento sui segnali per dirti degli overflow sarebbe comunque molto lento.
SamB,

@SamB Solo se ci si aspettava che gli overflow fossero frequenti.
user253751

18

Ecco un modo molto veloce per rilevare l'overflow per almeno aggiunte, che potrebbe dare un vantaggio per la moltiplicazione, la divisione e il power-of.

L'idea è che proprio perché il processore lascerà il valore a zero e che C / C ++ verrà sottratto da qualsiasi processore specifico, è possibile:

uint32_t x, y;
uint32_t value = x + y;
bool overflow = value < (x | y);

Ciò garantisce che se un operando è zero e uno no, l'overflow non verrà rilevato in modo errato ed è significativamente più veloce di molte operazioni NOT / XOR / AND / test come precedentemente suggerito.

Come sottolineato, questo approccio, sebbene migliore di altri modi più elaborati, è ancora ottimizzabile. Di seguito è riportata una revisione del codice originale contenente l'ottimizzazione:

uint32_t x, y;
uint32_t value = x + y;
const bool overflow = value < x; // Alternatively "value < y" should also work

Un modo più efficiente ed economico per rilevare l'overflow di moltiplicazione è:

uint32_t x, y;
const bool overflow = (x >> 16U) * (y >> 16U);
uint32_t value = overflow ? UINT32_MAX : x * y;

Ciò comporta UINT32_MAX in caso di overflow o il risultato della moltiplicazione. È un comportamento strettamente indefinito consentire alla moltiplicazione di procedere per numeri interi con segno in questo caso.


Non sono d'accordo a causa della teoria del calcolo. Consideriamo quanto segue: y> x, overflow del valore, y è solo maggiore di x a causa del bit di segno impostato (1 + 255, ad esempio, per i caratteri non firmati) valore di test e x risulterebbe in overflow = false - da qui l'uso del logico o per prevenire questo comportamento rotto.
DX-MON

Il test funziona per i numeri forniti (x: = 1, y: = 255, size = uint8_t): il valore sarà 0 (1 + 255) e 0 <1 è vero. Funziona davvero per ogni coppia di numeri.
Gunther Piez,

Hmm, hai un buon punto. Mi attengo ancora al lato della sicurezza usando il trucco o anche se, dato che qualsiasi buon compilatore lo ottimizzerebbe, il fornitore è effettivamente corretto per tutti gli input, compresi i numeri non traboccanti come "0 + 4" in cui il risultato non sarebbe troppo pieno.
DX-MON,

4
Se c'è un overflow, di x+y>=256e value=x+y-256. Perché y<256vale sempre, (y-256) è negativo e quindi value < xè sempre vero. La prova per il caso non traboccante è abbastanza simile.
Gunther Piez,

2
@ DX-MON: il tuo primo metodo è necessario se hai anche un bit di riporto da una precedente aggiunta. uint32_t x[N], y[N], z[N], carry=0; for (int i = 0; i < N; i++) { z[i] = x[i] + y[i] + carry; carry = z[i] < (x[i] | y[i]); }Se non si utilizzano ori valori, non sarà possibile distinguere tra un operando e il bit di carry pari a zero e un operando che è 0xffffffffe il bit di carry che è uno.
Matt

14

Non è possibile accedere al flag di overflow da C / C ++.

Alcuni compilatori consentono di inserire istruzioni trap nel codice. Su GCC l'opzione è -ftrapv.

L'unica cosa portatile e indipendente dal compilatore che puoi fare è controllare da solo gli overflow. Proprio come hai fatto nel tuo esempio.

Però, -ftrapv sembra non fare nulla su x86 utilizzando l'ultimo GCC. Immagino sia un residuo di una vecchia versione o specifico di qualche altra architettura. Mi aspettavo che il compilatore inserisse un codice operativo INTO dopo ogni aggiunta. Sfortunatamente non lo fa.


Forse varia: -ftrapv sembra funzionare bene usando GCC 4.3.4 su una scatola Cygwin. C'è un esempio su stackoverflow.com/questions/5005379/…
Nate Kohl,

3
Entrambi avete ragione. -ftrapv fa il lavoro ma solo per gli interi con segno
ZAB

14

Per numeri interi senza segno, basta verificare che il risultato sia inferiore a uno degli argomenti:

unsigned int r, a, b;
r = a + b;
if (r < a)
{
    // Overflow
}

Per numeri interi con segno puoi controllare i segni degli argomenti e del risultato.

Numeri interi di segni diversi non possono traboccare e numeri interi dello stesso segno traboccano solo se il risultato è di un segno diverso:

signed int r, a, b, s;
r = a + b;
s = a>=0;
if (s == (b>=0) && s != (r>=0))
{
    // Overflow
}

Bene, il primo metodo funzionerebbe anche con numeri interi con segno, no? char result = (char)127 + (char)3;sarebbe -126; più piccolo di entrambi gli operandi.
primfaktor,

1
Oh, capisco, il problema è che non è definito per i tipi firmati.
primfaktor,

27
-1 trabocco di numeri con segno comporta un comportamento indefinito (quindi il test è troppo tardi per essere effettivamente utile).
Voo

1
@primfaktor non funziona per int firmato: char ((- 127) + (-17)) = 112. Per int firmato devi controllare il bit di segno degli argomenti e del risultato
phuclv,

3
Come già detto, la soluzione per intero con segno non funziona a causa del comportamento indefinito di a + b in caso di overflow. Il controllo dell'overflow con numero intero con segno deve essere eseguito prima dell'operazione.
Marwan Burelle,

11

Avevo bisogno di rispondere a questa stessa domanda per i numeri in virgola mobile, dove il mascheramento e lo spostamento dei bit non sembrano promettenti. L'approccio che mi sono basato su funziona con numeri firmati e non, numeri interi e in virgola mobile. Funziona anche se non esiste un tipo di dati più grande da promuovere per i calcoli intermedi. Non è il più efficiente per tutti questi tipi, ma poiché funziona per tutti, vale la pena usarlo.

Test di overflow, aggiunta e sottrazione firmati:

  1. Ottieni le costanti che rappresentano i valori più grandi e più piccoli possibili per il tipo, MAXVALUE e MINVALUE.

  2. Calcola e confronta i segni degli operandi.

    un. Se uno dei due valori è zero, né l'aggiunta né la sottrazione possono traboccare. Salta i test rimanenti.

    b. Se i segni sono opposti, l'aggiunta non può traboccare. Salta i test rimanenti.

    c. Se i segni sono uguali, la sottrazione non può traboccare. Salta i test rimanenti.

  3. Test per overflow positivo di MAXVALUE.

    un. Se entrambi i segni sono positivi e MAXVALUE - A <B, l'aggiunta trabocca.

    b. Se il segno di B è negativo e MAXVALUE - A <-B, la sottrazione traboccerà.

  4. Test per overflow negativo di MINVALUE.

    un. Se entrambi i segni sono negativi e MINVALUE - A> B, l'aggiunta trabocca.

    b. Se il segno di A è negativo e MINVALUE - A> B, la sottrazione traboccerà.

  5. Altrimenti, nessun overflow.

Test di overflow, moltiplicazione e divisione firmati:

  1. Ottieni le costanti che rappresentano i valori più grandi e più piccoli possibili per il tipo, MAXVALUE e MINVALUE.

  2. Calcola e confronta le magnitudini (valori assoluti) degli operandi con uno. (Di seguito, supponiamo che A e B siano queste magnitudini, non gli originali firmati.)

    un. Se uno dei due valori è zero, la moltiplicazione non può traboccare e la divisione produrrà zero o infinito.

    b. Se uno dei due valori è uno, la moltiplicazione e la divisione non possono traboccare.

    c. Se la grandezza di un operando è inferiore all'uno e dell'altro è maggiore di uno, la moltiplicazione non può traboccare.

    d. Se le magnitudini sono entrambe inferiori a una, la divisione non può traboccare.

  3. Test per overflow positivo di MAXVALUE.

    un. Se entrambi gli operandi sono maggiori di uno e MAXVALUE / A <B, la moltiplicazione traboccerà.

    b. Se B è inferiore a uno e MAXVALUE * B <A, la divisione trabocca.

  4. Altrimenti, nessun overflow.

Nota: l'overflow minimo di MINVALUE è gestito da 3, perché abbiamo assunto valori assoluti. Tuttavia, se ABS (MINVALUE)> MAXVALUE, avremo alcuni rari falsi positivi.

I test per underflow sono simili, ma coinvolgono EPSILON (il numero positivo più piccolo maggiore di zero).


1
Almeno sui sistemi POSIX, il segnale SIGFPE può essere abilitato per punti in virgola mobile / overflow.
Chris Johnson,

Durante la conversione in virgola mobile e viceversa, (secondo i miei test su una macchina a 32 bit) è molto più lento rispetto alle altre soluzioni.
JanKanis,

Un revisore ha rilevato un caso mancante per la parte di sottrazione 2. Sono d'accordo sul fatto che 0 - MINVALUE traboccherebbe. Quindi è necessario aggiungere test per questo caso.
Paul Chernoch,

<pedantic> I numeri interi non sono underflow (= diventano troppo vicini allo zero per essere rappresentati con precisione). 1.0e-200 / 1.0e200sarebbe un esempio di underflow effettivo, supponendo che IEEE raddoppi. Il termine corretto qui, invece, è overflow negativo. </pedantic>
Arne Vogel

Per essere precisi, il motivo per cui gli interi non sono considerati underflow è a causa del comportamento di troncamento definito, ad esempio 1/INT_MAXpotrebbe essere considerato underflow, ma il linguaggio impone semplicemente il troncamento a zero.
Arne Vogel,

8

CERT ha sviluppato un nuovo approccio per rilevare e segnalare l'overflow di numeri interi con segno, il wrapping di numeri interi senza segno e il troncamento di numeri interi utilizzando il modello intero con intervallo infinito "come se" (AIR). Il CERT ha pubblicato un rapporto tecnico che descrive il modello e ha prodotto un prototipo funzionante basato su GCC 4.4.0 e GCC 4.5.0.

Il modello intero AIR produce un valore equivalente a uno che sarebbe stato ottenuto utilizzando numeri interi a intervallo infinito o risulta in una violazione del vincolo di runtime. A differenza dei precedenti modelli di numeri interi, i numeri interi AIR non richiedono trap precisi e, di conseguenza, non interrompono o inibiscono la maggior parte delle ottimizzazioni esistenti.


Non ho visto nulla di utile al link, ma sembra un modello che ho sostenuto a lungo. Supporta la stragrande maggioranza delle utili ottimizzazioni, e allo stesso tempo supporta utili garanzie semantiche che la maggior parte delle implementazioni può fornire essenzialmente gratuitamente. Se il codice sa che gli input per una funzione saranno validi in tutti i casi in cui l'output è importante , ma non sa in anticipo se l'output sarà importante, essere in grado di lasciare che si verifichino overflow nei casi in cui non influiranno su nulla più facile ed efficiente che doverli prevenire a tutti i costi.
supercat

8

Un altro strumento interessante è il CIO: un controllo di overflow di numeri interi per C / C ++ .

Questo è un compilatore di Clang con patch , che aggiunge controlli al codice in fase di compilazione.

Ottieni un output simile al seguente:

CLANG ARITHMETIC UNDEFINED at <add.c, (9:11)> :
Op: +, Reason : Signed Addition Overflow,
BINARY OPERATION: left (int32): 2147483647 right (int32): 1

1
Questa patch è ora unita per clangare la base di codice tra altri disinfettanti, vedi la mia risposta.
ZAB,

7

Un'altra variante di una soluzione, utilizzando il linguaggio assembly, è una procedura esterna. Questo esempio per la moltiplicazione di numeri interi senza segno usando g ++ e fasm in Linux x64.

Questa procedura moltiplica due argomenti interi senza segno (32 bit) (secondo la specifica per amd64 (sezione 3.2.3 Passaggio parametri ).

Se la classe è INTEGER, viene utilizzato il successivo registro disponibile della sequenza% rdi,% rsi,% rdx,% rcx,% r8 e% r9

(edi ed esi registra nel mio codice)) e restituisce il risultato o 0 se si è verificato un overflow.

format ELF64

section '.text' executable

public u_mul

u_mul:
  MOV eax, edi
  mul esi
  jnc u_mul_ret
  xor eax, eax
u_mul_ret:
ret

Test:

extern "C" unsigned int u_mul(const unsigned int a, const unsigned int b);

int main() {
    printf("%u\n", u_mul(4000000000,2)); // 0
    printf("%u\n", u_mul(UINT_MAX/2,2)); // OK
    return 0;
}

Collegare il programma con il file oggetto asm. Nel mio caso, in Qt Creator , aggiungilo a LIBSin un file .pro.


5

Calcola i risultati con i doppi. Hanno 15 cifre significative. Il tuo requisito ha un limite superiore rigido su c di 8 8  - può contenere al massimo 8 cifre. Pertanto, il risultato sarà preciso se si trova nel raggio d'azione e non traboccerà altrimenti.


5

Prova questa macro per testare il bit di overflow delle macchine a 32 bit (adattata la soluzione di Angel Sinigersky)

#define overflowflag(isOverflow){   \
size_t eflags;                      \
asm ("pushfl ;"                     \
     "pop %%eax"                    \
    : "=a" (eflags));               \
isOverflow = (eflags >> 11) & 1;}

L'ho definito come una macro perché altrimenti il ​​bit di overflow sarebbe stato sovrascritto.

La successiva è una piccola applicazione con il codice di cui sopra:

#include <cstddef>
#include <stdio.h>
#include <iostream>
#include <conio.h>
#if defined( _MSC_VER )
#include <intrin.h>
#include <oskit/x86>
#endif

using namespace std;

#define detectOverflow(isOverflow){     \
size_t eflags;                      \
asm ("pushfl ;"                     \
    "pop %%eax"                     \
    : "=a" (eflags));               \
isOverflow = (eflags >> 11) & 1;}

int main(int argc, char **argv) {

    bool endTest = false;
    bool isOverflow;

    do {
        cout << "Enter two intergers" << endl;
        int x = 0;
        int y = 0;
        cin.clear();
        cin >> x >> y;
        int z = x * y;
        detectOverflow(isOverflow)
        printf("\nThe result is: %d", z);
        if (!isOverflow) {
            std::cout << ": no overflow occured\n" << std::endl;
        } else {
            std::cout << ": overflow occured\n" << std::endl;
        }

        z = x * x * y;
        detectOverflow(isOverflow)
        printf("\nThe result is: %d", z);
        if (!isOverflow) {
            std::cout << ": no overflow ocurred\n" << std::endl;
        } else {
            std::cout << ": overflow occured\n" << std::endl;
        }

        cout << "Do you want to stop? (Enter \"y\" or \"Y)" << endl;

        char c = 0;

        do {
            c = getchar();
        } while ((c == '\n') && (c != EOF));

        if (c == 'y' || c == 'Y') {
            endTest = true;
        }

        do {
            c = getchar();
        } while ((c != '\n') && (c != EOF));

    } while (!endTest);
}

4
Non tutte le macchine a 32 bit sono compatibili con Intel x86, e non tutti i compilatori supportano la sintassi dell'assemblaggio gnu (trovo divertente che tu _MSC_VERpubblichi un codice che verifica anche se i compilatori MS lo respingeranno tutti).
Ben Voigt,

2

Catching Integer Overflows in C indica una soluzione più generale di quella discussa da CERT (è più generale in termini di tipi gestiti), anche se richiede alcune estensioni GCC (non so quanto siano ampiamente supportate).


2

Non è possibile accedere al flag di overflow da C / C ++.

Non sono d'accordo con questo. È possibile scrivere un linguaggio di assembly inline e utilizzare joun'istruzione (jump overflow) supponendo di essere su x86 per intercettare l'overflow. Naturalmente, il tuo codice non sarebbe più portabile su altre architetture.

Guarda info ase info gcc.


8
assemblatore inline non è una funzionalità C / C ++ e indipendente dalla piattaforma. Su x86 puoi usare l'istruzione in invece di branch tra l'altro.
Nils Pipenbrinck,

0

Per espandere la risposta di Head Geek, c'è un modo più veloce di fare addition_is_safe;

bool addition_is_safe(unsigned int a, unsigned int b)
{
    unsigned int L_Mask = std::numeric_limits<unsigned int>::max();
    L_Mask >>= 1;
    L_Mask = ~L_Mask;

    a &= L_Mask;
    b &= L_Mask;

    return ( a == 0 || b == 0 );
}

Questo utilizza un'architettura macchina sicura, in quanto gli interi senza segno a 64 e 32 bit funzioneranno comunque bene. Fondamentalmente, creo una maschera che maschererà tutto tranne il bit più significativo. Quindi, maschera entrambi i numeri interi e se uno di essi non ha quel bit impostato, l'aggiunta è sicura.

Ciò sarebbe ancora più veloce se preinizializzi la maschera in qualche costruttore, poiché non cambia mai.


5
Questo non è corretto Il trasporto potrebbe portare bit da posizioni inferiori che causeranno un trabocco. Valuta di aggiungere UINT_MAX + 1. Dopo il mascheramento, averrà impostato il bit alto, ma 1diventerà zero e quindi la funzione tornerà true, l'aggiunta è sicura, ma si è diretti direttamente per l'overflow.
il suino


-1

La risposta di MSalter è una buona idea.

Se è richiesto il calcolo dei numeri interi (per precisione), ma è disponibile il virgola mobile, è possibile fare qualcosa del tipo:

uint64_t foo(uint64_t a, uint64_t b) {
    double dc;

    dc = pow(a, b);

    if (dc < UINT_MAX) {
       return (powu64(a, b));
    }
    else {
      // Overflow
    }
}

Di solito, direi che ripetere il calcolo in virgola mobile è una cattiva idea, ma per questo caso specifico di esponenziale a ^ c, potrebbe benissimo essere più efficiente. Ma il test dovrebbe essere (c * log(a) < max_log), doveconst double max_log = log(UINT_MAX)
Toby Speight,

-1

Il set di istruzioni x86 include un'istruzione di moltiplicazione senza segno che memorizza il risultato in due registri. Per usare quell'istruzione da C, si può scrivere il seguente codice in un programma a 64 bit (GCC):

unsigned long checked_imul(unsigned long a, unsigned long b) {
  unsigned __int128 res = (unsigned __int128)a * b;
  if ((unsigned long)(res >> 64))
    printf("overflow in integer multiply");
  return (unsigned long)res;
}

Per un programma a 32 bit, è necessario rendere il risultato a 64 bit e i parametri a 32 bit.

Un'alternativa consiste nell'utilizzare intrinseco dipendente dal compilatore per controllare il registro flag. La documentazione GCC per l'overflow intrinseco è disponibile in 6.56 Funzioni integrate per eseguire l'aritmetica con il controllo dell'overflow .


1
È necessario utilizzare il tipo senza segno a 128 bit __uint128per evitare l'overflow con segno e spostare a destra un valore negativo.
Chqrlie,

Cosa sono gli "istinti dipendenti dal compilatore" e gli "istinti di overflow" ? Intendi " funzioni intrinseche " ? Hai un riferimento? (Rispondere modificando la risposta , non qui nei commenti (a seconda dei casi).)
Peter Mortensen,

-3
#include <stdio.h>
#include <stdlib.h>

#define MAX 100 

int mltovf(int a, int b)
{
    if (a && b) return abs(a) > MAX/abs(b);
    else return 0;
}

main()
{
    int a, b;

    for (a = 0; a <= MAX; a++)
        for (b = 0; b < MAX; b++) {

        if (mltovf(a, b) != (a*b > MAX)) 
            printf("Bad calculation: a: %d b: %d\n", a, b);

    }
}

-3

Un modo chiaro per farlo sarebbe quello di sovrascrivere tutti gli operatori (+ e * in particolare) e verificare la presenza di un overflow prima di eseguire le operazioni.


6
Solo che non è possibile ignorare gli operatori per i tipi predefiniti. Dovresti scrivere una classe per quello e riscrivere il codice client per usarlo.
Blaisorblade,

-3

Dipende da cosa lo usi. Eseguendo l'aggiunta o la moltiplicazione DWORD (unsigned long), la soluzione migliore è utilizzare ULARGE_INTEGER.

ULARGE_INTEGER è una struttura di due DWORD. È possibile accedere al valore completo come "QuadPart" mentre l'accesso DWORD alto è "HighPart" e l'accesso DWORD basso come "LowPart".

Per esempio:

DWORD
My Addition(DWORD Value_A, DWORD Value_B)
{
    ULARGE_INTEGER a, b;

    b.LowPart = Value_A;  // A 32 bit value(up to 32 bit)
    b.HighPart = 0;
    a.LowPart = Value_B;  // A 32 bit value(up to 32 bit)
    a.HighPart = 0;

    a.QuadPart += b.QuadPart;

    // If  a.HighPart
    // Then a.HighPart contains the overflow (carry)

    return (a.LowPart + a.HighPart)

    // Any overflow is stored in a.HighPart (up to 32 bits)

6
Sfortunatamente, questa è una soluzione solo per Windows. Altre piattaforme non hanno ULARGE_INTEGER.
Mistico

-3

Per eseguire una moltiplicazione senza segno senza traboccare in modo portatile è possibile utilizzare quanto segue:

... /* begin multiplication */
unsigned multiplicand, multiplier, product, productHalf;
int zeroesMultiplicand, zeroesMultiplier;
zeroesMultiplicand = number_of_leading_zeroes( multiplicand );
zeroesMultiplier   = number_of_leading_zeroes( multiplier );
if( zeroesMultiplicand + zeroesMultiplier <= 30 ) goto overflow;
productHalf = multiplicand * ( c >> 1 );
if( (int)productHalf < 0 ) goto overflow;
product = productHalf * 2;
if( multiplier & 1 ){
   product += multiplicand;
   if( product < multiplicand ) goto overflow;
}
..../* continue code here where "product" is the correct product */
....
overflow: /* put overflow handling code here */

int number_of_leading_zeroes( unsigned value ){
   int ctZeroes;
   if( value == 0 ) return 32;
   ctZeroes = 1;
   if( ( value >> 16 ) == 0 ){ ctZeroes += 16; value = value << 16; }
   if( ( value >> 24 ) == 0 ){ ctZeroes +=  8; value = value <<  8; }
   if( ( value >> 28 ) == 0 ){ ctZeroes +=  4; value = value <<  4; }
   if( ( value >> 30 ) == 0 ){ ctZeroes +=  2; value = value <<  2; }
   ctZeroes -= x >> 31;
   return ctZeroes;
}

-4

Il modo più semplice per verificare l'overflow è eseguire la convalida controllando se il valore corrente è inferiore al valore precedente. Ad esempio, supponiamo di avere un ciclo per stampare i poteri di 2:

long lng;
int n;
for (n = 0; n < 34; ++n)
{
   lng = pow (2, n);
   printf ("%li\n", lng);
}

L'aggiunta di overflow verificando il modo in cui ho descritto risulta in questo:

long signed lng, lng_prev = 0;
int n;
for (n = 0; n < 34; ++n)
{
    lng = pow (2, n);
    if (lng <= lng_prev)
    {
        printf ("Overflow: %i\n", n);
        /* Do whatever you do in the event of overflow.  */
    }
    printf ("%li\n", lng);
    lng_prev = lng;
}

Funziona con valori senza segno nonché con valori con segno positivo e negativo.

Naturalmente, se si volesse fare qualcosa di simile per diminuire i valori invece di aumentarli, capovolgere il <=segno per realizzarlo >=, supponendo che il comportamento di underflow sia uguale al comportamento di overflow. In tutta onestà, è portatile quanto si ottiene senza accesso al flag di overflow della CPU (e ciò richiederebbe un codice assembly inline, rendendo comunque il tuo codice non portatile attraverso le implementazioni).


9
Se trabocca un valore firmato, il comportamento del programma non è definito. Non è garantito avvolgersi.
David Stone,
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.