È importante avvisare sul troncamento delle costanti reali a 32 bit?

6

Sto scherzando con LLVM e sto guardando quello che servirebbe per creare un altro linguaggio strongmente tipizzato, e ora che sono intorno alla sintassi, ho notato che sembra essere un vero problema lingua digitata per avvisare le persone che le loro costanti reali non rientrano in una float :

// both in Java and C#
float foo = 3.2;
// error: implicitly truncating a double into a float
// or something along these lines

Perché non funziona in Java e C #? So che è facile aggiungere f dopo 3.2 , ma sta davvero facendo qualcosa di utile? Devo davvero essere che consapevole del fatto che sto usando reals a precisione singola invece di realizzazioni a doppia precisione? Forse mi manca qualcosa (che, in fondo, è il motivo per cui lo sto chiedendo).

Tieni presente che float foo = [const] non è la stessa cosa di float foo = [double variable] , dove il cast mi sembra normale.

    
posta zneak 06.02.2011 - 17:25
fonte

5 risposte

3

Se stai progettando un linguaggio tipizzato staticamente, potresti voler vedere come Haskell gestisce i valori letterali numerici. Ecco un esempio di come sono stati digitati in Haskell:

Prelude> :type 2
2 :: (Num t) => t
Prelude> :type 2.0
2.0 :: (Fractional t) => t
Prelude> :type pi
pi :: (Floating a) => a
Ciò significa che il letterale 2 è di un tipo che è un membro della classe Num , il letterale 2.0 è di un tipo che è un membro della classe Fractional , e pi restituisce un valore di un tipo che è un membro della classe Floating . I diversi tipi di numeri, ad esempio Int e Float sono membri delle classi di tipi appropriate. Ciò consente al compilatore di dedurre il tipo di letterale in base a dove verrà utilizzato o associato. Se passi 2 come parametro alla funzione che si aspetta un Float , il compilatore chiamerà l'implementazione di Float di fromInteger dietro le quinte, che la convertirà per te. Funziona perché Float è un membro della classe di tipi Num e un requisito per diventare membro di Num è avere un'implementazione di fromInteger .

Avrai bisogno di inferenza di tipo per far funzionare tutto questo. Ulteriori informazioni su tipi e classi in Haskell possono essere trovati qui .

    
risposta data 06.02.2011 - 22:22
fonte
1

Il compilatore Java si lamenta correttamente perché 3.2 (doppio) e 3.2f (float) sono diversi numeri dal suo punto di vista (e dal POV della specifica della lingua).

In formato binario ( IEEE 754 , salta il segno e il campo esponente) i numeri sono chiaramente diversi e ha senso che il compilatore presenti un errore in merito a troncamenti, perdita di precisione e probabile errore di arrotondamento.

3.2 : 1.1001100110011001100110011001100110011001100110011010
3.2f: 1.10011001100110011001101

È lo stesso tipo di errore se provi a scrivere:

short s = 70000;     // Assuming short is 16 bit integer
    
risposta data 06.02.2011 - 21:26
fonte
1

double si suppone che sia il tipo "normale" a virgola mobile e float un tipo da utilizzare quando è necessario salvare la memoria. Non c'è molto che puoi fare con float , che con java. lang.Math o System.Math con un sacco di double -solo funzioni.

Note that float foo = [const] is not the same thing as float foo = [double variable], where requiring the cast seems normal to me.

Loro sono uguali: float foo = [expression of type double] . Mantiene il compilatore più semplice per non distinguerli artificialmente.

    
risposta data 06.02.2011 - 19:22
fonte
1

Non si dovrebbe avvertire di troncare le quantità in virgola mobile, costanti o meno, a un 32% difloat. Qualsiasi quantità a virgola mobile ha una singola rappresentazione corretta a 32 bit. Tale rappresentazione non identificherà univocamente il numero, ma - se la quantità originale è conosciuta con precisione - identificherà un intervallo di valori in cui è noto che il numero è all'interno. In un solo caso angolare molto ristretto una conversione da double a float non produce un risultato rigorosamente con +/- 0.5lsb, e in quel caso stretto, il risultato sarà comunque entro 0.50000001lsb) Quali compilatori dovrebbero avvisare circa (ma ahimè no) sta lanciando nell'altra direzione - alimentando float a 32 bit in calcoli che si aspettano double . La conversione da double a float dovrebbe essere considerata perfettamente valida se il risultato del calcolo non verrà mai riconvertito in double . Viceversa, la trasmissione da float a double dovrebbe essere considerata dubbia anche quando non ci sarebbero altre basi per una diagnostica. Ad esempio, nell'istruzione double foo = (1.0f / 10.0f); tutte le costanti a virgola mobile sono rappresentate con precisione, ma il risultato è disattivato di un importo miliardi di volte superiore a quello che dovrebbe essere previsto in un double . Un simile incarico è molto più probabile che rappresenti un errore rispetto ad es. il passaggio di una double a una routine di disegno che si aspetta un float ; sfortunatamente, le lingue sembrano considerare queste ultime degne di una diagnosi e la prima no.

    
risposta data 12.07.2012 - 19:48
fonte
0

Mi sembra che un compilatore pedante che si lamenta del fatto che qualcosa possa portare a risultati inattesi è sempre una buona cosa.

Il compilatore potrebbe promuovere silenziosamente un tipo letterale a un tipo adatto, ma ciò implica congetture. L'autore lo voleva davvero promosso, o è in realtà un errore. Eliminare le congetture e basta barfare ha il vantaggio che l'utente è esplicito in ciò che il feed al compilatore, e quindi dovrebbe sapere cosa ottengono.

    
risposta data 07.02.2011 - 08:48
fonte

Leggi altre domande sui tag