2016-07-13 34 views
5

ho un successivo C espressione (variabili sono galleggianti 32-bit)virgola mobile zero implementazioni C (IEEE 754 invarianti?)

float result = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 

Supponendo che x0==x1 e y0==y1, (e con == intendo binario identità di rappresentazione), posso contare sul fatto che l'espressione sarà necessariamente valutata a zero (come in, tutti i bit del float sono impostati su 0)? In altre parole, posso supporre che i seguenti invarianti siano sempre validi?

memcmp(&a, &b, sizeof(float) == 0 => memcmp(a-b, (uint32_t)0, sizeof(float)) == 0 
0*a == 0.0 

È sicuro assumere che tutti i valori sono numeri finiti (non INFINITY o NaN).

Modifica: come indicato nelle risposte, le moltiplicazioni con 0 possono produrre zeri firmati. Posso ancora fare affidamento sul fatto che il risultato dell'espressione sarà pari a 0,0 utilizzando le regole FP-confronto, cioè .:

(result == 0.0) 

Edit 1: Sostituito tipo getta da memcmp chiama a illustrare la domanda migliore.

P.S. Sto limitando il mio codice solo ai compilatori C11 compatibili, nel caso in cui faccia qualche differenza. Sono anche disposto a fare affidamento sul supporto STDC_IEC_559 se ciò sarà d'aiuto per il mio caso.

+0

Possiamo assumere anche che 'y2 - y0' e' x2 - x0' saranno finiti? –

+0

@OliverCharlesworth: sì. Se non è così, sono d'accordo con i risultati non definiti. – MrMobster

+0

Quali tipi sono 'a' e' b'? Se non sono 'uint32_t', il tuo codice richiama il comportamento non definito (violazione della regola del tipo effettiva). Quindi tutto è permesso dallo standard.Lo stesso per 'ZERO' – Olaf

risposta

4

La citazione di C11 confonde la domanda perché IEEE 754 non è richiesto da alcun standard C.

Detto, solo assumendo IEEE 754 numeri in virgola 32 bit floating e senza fare ipotesi su x2 e y2 (diversi dai loro non essendo infinito o NaN) non si può assumere che tutti i bit del risultato sarà 0 I numeri IEEE 754 hanno due zeri, uno negativo e uno positivo e se l'espressione (y2 - y0) - (x2 - x0) è negativa, il risultato di moltiplicarlo con uno zero sarà uno zero negativo.

Siamo in grado di testare con questo breve esempio:

#include <stdio.h> 
#include <stdint.h> 

int 
main(int argc, char **argv) 
{ 
    union { 
     float f; 
     uint32_t i; 
    } foo; 

    float a = 0; 
    float b = -1; 

    foo.f = a * b; 
    printf("0x%x\n", foo.i); 

    return 0; 
} 

Il risultato (notare nessuna ottimizzazione dal momento che non voglio che il compilatore di essere intelligente):

$ cc -o foo foo.c && ./foo 
0x80000000 

Oh, ho solo ho notato che la seconda parte della domanda che hai chiamato "in altre parole" non è in realtà in altre parole perché è una domanda diversa.

Per cominciare:

(*(uint32_t*)(&a) == *(uint32_t*)(&b)) 

non è equivalente a a == b per virgola mobile perché -0 == 0. E con questo, l'altra parte del presupposto cade a pezzi perché -0 - 0 ti dà -0. Non sono in grado di fare qualsiasi altra sottrazione di numeri uguali generare uno zero negativo, ma ciò non significa che non sia possibile, sono abbastanza sicuro che gli standard non applicano lo stesso algoritmo per la sottrazione su tutte le implementazioni, quindi un po 'di segno potrebbe infiltrarsi lì dentro in qualche modo.

+0

Buona presa con quella cosa "zero negativo". In realtà indovinerei che la risposta sarebbe Sì (prima di leggere il tuo). –

+0

Grazie, Arte! Ovviamente avete ragione che menzionare lo standard IEEE è un po 'fuorviante. Quello che mi interessa di più è sapere se dovrei creare ulteriori controlli di identità su hardware comune, con compilatori C11 comuni o se posso tranquillamente saltare i controlli. Il commento zero firmato è molto utile! Sarei ok se facessi il confronto FP a 0 invece di 'zero bit-pattern' zero. Sarebbe al sicuro? – MrMobster

+0

@MrMobster La tua scommessa più sicura per confrontare un numero in virgola mobile su zero è 'a == 0.0'. Questo funzionerà a prescindere se a è negativo o positivo. – Art

Problemi correlati