2014-06-29 7 views

risposta

10

notazione esadecimale di Swift per i numeri a virgola mobile è solo una variante del notation introduced for C in the C99 standard sia per l'ingresso e l'uscita (con il formato printf %a).

Lo scopo di tale notazione è di essere sia facile da interpretare da parte degli esseri umani sia di rendere i bit dello IEEE 754 representation piuttosto riconoscibili. La rappresentazione IEEE 754 utilizza la base due. Di conseguenza, per un normale numero a virgola mobile, quando il numero precedente a p è compreso tra 1 e 2, il numero dopo p è direttamente il valore del campo esponente della rappresentazione IEEE 754. Questo è in linea con il duplice obiettivo di umano-leggibilità e la vicinanza alla rappresentazione bit:

$ cat t.c 
#include <stdio.h> 

int main(){ 
    printf("%a\n", 3.14); 
} 
$ gcc t.c && ./a.out 
0x1.91eb851eb851fp+1 

Il numero 0x1.91eb851eb851fp+1 può essere visto per essere leggermente superiore al 3 perché l'esponente è 1 e il significante è vicina 0x1.9, un po ' sopra 0x1.8, che indica il centro esatto tra due potenze di due.

Questo formato aiuta a ricordare che i numeri che hanno una rappresentazione compatta in decimale non sono necessariamente semplici in binario. Nell'esempio sopra, 3.14 utilizza tutte le cifre del significato e approssimativo (e anche così, non è rappresentato esattamente).

Esadecimale viene utilizzato per il numero prima dello p, che corrisponde al significato e nel formato IEEE 754, perché è più compatto di binario. Il significato di un numero binario64 IEEE 754 richiede 13 cifre esadecimali dopo il 0x1. da rappresentare completamente, che è molto, ma in binario sarebbero richieste 52 cifre, il che è francamente poco pratico.

La scelta di esadecimale ha effettivamente i suoi svantaggi: a causa di questa scelta, le diverse rappresentazioni equivalenti per lo stesso numero non sono sempre facili da riconoscere come equivalenti. Ad esempio, 0x1.3p1 e 0x2.6p0 rappresentano lo stesso numero, sebbene le loro cifre non abbiano nulla in comune. In binario, le due notazioni corrisponderebbero a 0b1.0011p1 e 0b10.011p0, che sarebbe più facile da vedere come equivalente. Per fare un altro esempio, 3.14 può anche essere rappresentato come 0xc.8f5c28f5c28f8p-2, che è estremamente difficile da vedere come lo stesso numero di 0x1.91eb851eb851fp+1. Questo problema non esisterebbe se il numero dopo il p rappresentasse una potenza di 16, come suggerito nella domanda, ma l'unicità della rappresentazione non era un obiettivo quando C99 era standardizzato: era la vicinanza alla rappresentazione IEEE 754.

+0

Sarebbe corretto dire che ogni numero in virgola mobile di un particolare tipo avrebbe una rappresentazione canonica unica in quella forma, se si dovessero specificare rappresentazioni particolari per +/- zero e altrimenti richiesto che la cifra iniziale sia un '1' e che il numero di cifre specificato sia sufficiente per" compilare "il tipo? – supercat

+0

L'output del compilatore @supercat è in pratica normalizzato in modo simile a questo (sulla mia piattaforma di compilazione, ad eccezione di 'long double 'a 80 bit, ecco come ho ottenuto il modulo alternativo per 3.14). Consentire tutte le varianti nella direzione di input ha i suoi vantaggi, ad esempio per gli interi (0x7fffffff.0p0) e per le voci di tabella (come in http://stackoverflow.com/a/23726810/139746) –

+0

È certamente utile per un compilatore accettare rappresentazioni non canoniche, specialmente in situazioni in cui molti valori sono frazioni della forma m/2^p * per lo stesso p *. L'output di sin (x) ha un intervallo dinamico * significativo * costante che si estende da 0 a 1, anche quando x è vicino a pi; mostrare i valori in forma denormalizzata rende il loro significato relativo molto più chiaro rispetto a mostrarli in forma normalizzata. – supercat

Problemi correlati