2015-02-20 18 views
6

Il formato in virgola mobile IEEE 754 è ben definito su tutte le piattaforme? In termini sia di formato bit che di endianness?IEEE 754/iec 559

Sono disposto a aggiungere il seguente al mio codice (per una versione iniziale):

static_assert(std::numeric_limits<float>::is_iec559, "Only support IEC 559 (IEEE 754) float"); 
static_assert(sizeof(float) * CHAR_BIT == 32, "Only support float => Single Precision IEC 559 (IEEE 754)"); 

static_assert(std::numeric_limits<double>::is_iec559, "Only support IEC 559 (IEEE 754) double"); 
static_assert(sizeof(float) * CHAR_BIT == 64, "Only support double => Double Precision IEC 559 (IEEE 754)"); 

static_assert(std::numeric_limits<long double>::is_iec559, "Only support IEC 559 (IEEE 754) long double"); 
static_assert(sizeof(float) * CHAR_BIT == 128, "Only support long double => Exteneded Precision IEC 559 (IEEE 754)"); 
// More asserts if required. 
// I noticed my current system has a sizeof(long double) => 128 
// But numeric_limits<long double>::digits => 63 
// So we are not storing quad precision floats only extended. 

Se scrivo il mio float/double/long double in formato binario possono queste essere trasportati tra i sistemi senza ulteriori interpretazioni . cioè ...

void write(std::ostream& stream, double value) 
{ 
    stream.write(reinterpret_cast<char const*>(&value), 8); 
} 

.... 

double read(std::istream& stream) 
{ 
    double value; 
    stream.read(reinterpret_cast<char*>(&value), 8); 
    return value; 
} 

O ho bisogno di rompere il raddoppio in componenti interi per il trasporto (come suggerito da this answer):

La differenza qui è che io sono disposto a limitare la mia rappresentazione supportato per IEEE -754 questo fondamentalmente risolverà la mia memorizzazione binaria di valori in virgola mobile o devo fare ulteriori passi?

Nota: per piattaforme non conformi (quando le trovo) sono disposto a specificare il codice in modo che leggano/scrivano IEEE-754 nella rappresentazione locale. Ma voglio sapere se il bit/endian è abbastanza definito come multipiattaforma per supportare lo storage/il trasporto.

+0

Endianness non specificato. Quindi vorrai convertire tutto in big o little-endian. – tmyklebu

+0

@tmyklebu: hai un riferimento che posso leggere che dice questo? Tutti gli altri con cui parlo dicono (anche se non mi hanno mostrato nemmeno lo standard). –

+0

Sono confuso. Vuoi un riferimento che dice che un altro riferimento non dice qualcosa? – tmyklebu

risposta

3

Il formato bit è ben definito, ma non tutte le macchine sono little-endian. Lo standard IEEE non richiede nemmeno numeri a virgola mobile per essere un certo endian. È possibile eseguire il seguente programma per vedere il modello byte del double42.0:

#include <stdio.h> 
#include <numeric> 
#include <limits> 
using namespace std; 

int main() { 
    double d = 42; 
    printf("%i\n", std::numeric_limits<double>::is_iec559); 
    for (char *c = (char *)&d; c != (char *)(&d+1); c++) { 
    printf("%02hhx ", *c); 
    } 
    printf("\n"); 
} 

Su una vecchia, non più mantenuto macchina Sun con g ++ 3.4.5, questa stampa

1 
40 45 00 00 00 00 00 00 

Su una macchina in funzione x86_64 un g recente molto più ++:

1 
00 00 00 00 00 00 45 40 
+0

Qual è il valore di: 'std :: :: numeric_limits digits' –

+1

ma sono abbastanza sicuro che è la prova inconfutabile che l'endianess non è parte dello standard e quindi non posso usare la tecnica semplice nella domanda e deve fare del lavoro per compensare le diverse architetture. –

+0

@LokiAstari: 'digits' è 53 su entrambe le piattaforme. A parte il fatto che non è nello standard, l'altro argomento per cui endianness non è standard è che * piccole * -endian piattaforme sono quelle che si sarebbero rovinate se facesse parte dello standard. Inoltre, sarebbe scomodo avere il significato e un numero rappresentato nell'endian sbagliato su qualsiasi piattaforma. – tmyklebu

1

Prima di tutto, si consiglia di modificare il codice in modo tale che esso controlla correttamente per le dimensioni di tipo ...

static_assert(std::numeric_limits<float>::is_iec559, "Only support IEC 559 (IEEE 754) float"); 
static_assert(sizeof(float) * CHAR_BIT == 32, "Only support float => Single Precision IEC 559 (IEEE 754)"); 

static_assert(std::numeric_limits<double>::is_iec559, "Only support IEC 559 (IEEE 754) double"); 
static_assert(sizeof(double) * CHAR_BIT == 64, "Only support double => Double Precision IEC 559 (IEEE 754)"); 

static_assert(std::numeric_limits<long double>::is_iec559, "Only support IEC 559 (IEEE 754) long double"); 
static_assert(sizeof(long double) * CHAR_BIT == 128, "Only support long double => Exteneded Precision IEC 559 (IEEE 754)"); 

Il fatto è, che IEEE-754 non richiede molto tempo per essere doppio 128 un po 'lungo A seconda del compilatore e della piattaforma, la lunghezza di tale tipo può variare. Tuttavia, specifica binary128, che potrebbe essere o non essere supportato dal compilatore, a seconda della piattaforma e dell'implementazione (gcc ha un tipo __float128 non standard per quello). Lo standard richiede solo il doppio lungo per essere altrettanto preciso, come il doppio, rendendolo solitamente lungo 80 bit (gcc) o 64 (VS).

Se si limita la rappresentazione supportata a IEEE-754, non si dovrebbe incorrere in alcun problema.

0

a leggere e scrivere IEEE 754 portabile, utilizzare queste routine. Se la piattaforma non è IEEE 754, si potrebbe perdere un paio di bit, ma si otterrà comunque la rappresentazione più vicina possibile.

https://github.com/MalcolmMcLean/ieee754

Problemi correlati