ho voluto vedere se GCC ridurrebbe a - (b - c)
-(a + c) - b
con numeri interi con e senza segno così ho creato due testriduzioni algebrica delle espressioni intere firmati in C/C++
//test1.c
unsigned fooau(unsigned a, unsigned b, unsigned c) { return a - (b - c); }
signed fooas(signed a, signed b, signed c) { return a - (b - c); }
signed fooms(signed a) { return a*a*a*a*a*a; }
unsigned foomu(unsigned a) { return a*a*a*a*a*a; }
//test2.c
unsigned fooau(unsigned a, unsigned b, unsigned c) { return (a + c) - b; }
signed fooas(signed a, signed b, signed c) { return (a + c) - b; }
signed fooms(signed a) { return (a*a*a)*(a*a*a); }
unsigned foomu(unsigned a) { return (a*a*a)*(a*a*a); }
ho compilato prima con gcc -O3 test1.c test2.c -S
e guardarono la montaggio. Per entrambi i test fooau
erano identici, tuttavia non lo era lo fooas
.
Per quanto comprendo aritmetica senza segno può essere derivato da the following formula
(a%n + b%n)%n = (a+b)%n
che può essere usato per mostrare che l'aritmetica senza segno è associativa. Ma dal signed overflow is undefined behavior questa uguaglianza non è necessariamente valida per l'aggiunta firmata (cioè l'aggiunta firmata non è associativa) il che spiega perché GCC non ha ridotto a - (b - c)
a (a + c) - b
per gli interi con segno. Ma possiamo dire a GCC di usare questa formula usando -fwrapv
. L'utilizzo di questa opzione fooas
per entrambi i test è identico.
Ma che dire della moltiplicazione? Per entrambi i test, fooms
e foomu
sono stati semplificati in tre moltiplicazioni (a*a*a*a*a*a to (a*a*a)*(a*a*a)
). Ma moltiplicazione può essere scritto come addizione ripetuta in modo da utilizzare la suddetta formula Credo si possa dimostrare che
((a%n)*(b%n))%n = (a*b)%n
che ritengo possono anche mostrare che la moltiplicazione modulare senza segno è associativo pure. Ma dal momento che GCC ha utilizzato solo tre moltiplicazioni per foomu
, ciò dimostra che GCC presuppone che la moltiplicazione dell'intero con segno sia associativa.
Questa mi sembra una contraddizione. Per l'aggiunta l'aritmetica firmata non era associativa ma per la sua moltiplicazione.
due domande:
E 'vero che l'aggiunta non è associativo con interi con segno, ma la moltiplicazione è in C/C++?
Se l'overflow con segno viene utilizzato per l'ottimizzazione, non è il fatto che GCC non riduce l'espressione algebrica e non ottimizza l'ottimizzazione? Non sarebbe meglio per l'ottimizzazione usare
-fwrapv
(ho capito chea - (b - c)
a(a + c) - b
non è molto ridotto ma sono preoccupato per casi più complicati)? Questo significa che l'ottimizzazione a volte utilizzando-fwrapv
è più efficiente e talvolta non lo è?
Cosa succede a 'fooms' e' foomu' se si crea il corpo 'a * a * a * a * a' - vale a dire. un ** numero ** dispari di multipli? Ottimizzano ancora lo stesso? Con un numero pari, il segno è irrilevante in quanto il risultato sarà sempre positivo. – kdopen
@kdopen, è lo stesso: 'fooms' e' foomu' producono lo stesso codice e usano 3 moltiplicazioni per 'a * a * a * a * a'. –