2010-04-17 16 views
9

sto ottenendo un avvertimento benigna sulla perdita possibile di datiAvvertimento in caso di perdita di dati C++/C

avviso C4244: 'argomento': conversione da 'const int' a 'galleggiare', possibile perdita di dati

domanda

mi ricordo come se galleggiante ha una precisione maggiore rispetto int. Quindi, come posso perdere i dati se mi converto da un tipo di dati più piccolo (int) a un tipo di dati più grande (float)?

+0

Niente a che fare con il tuo problema specifico, ma se pensi che i float possano essere più veloci del doppio, hai torto: lo scopo dei float è minimizzare i requisiti di archiviazione, che raramente sono un problema per le moderne applicazioni. La scelta predefinita del tipo di dati deve essere doppia, non mobile. –

+1

@Neil: dipende molto dalla CPU. Ci sono molte architetture in cui il float è drammaticamente più veloce del doppio. – jalf

+0

@jalf Possibile, ma nella maggior parte delle situazioni in codice C o C++, i float saranno promossi in doppio comunque. –

risposta

14

Perché i numeri float non sono precisi. Non è possibile rappresentare tutti i valori possibili che unopuò contenere in uno float, anche se il valore massimo di uno float è molto più alto.

Ad esempio, eseguire questo semplice programma:

#include <stdio.h> 

int main() 
{ 
for(int i = 0; i < 2147483647; i++) 
{ 
    float value = i; 
    int ivalue = value; 
    if(i != ivalue) 
    printf("Integer %d is represented as %d in a float\n", i, ivalue); 
} 
} 

Vedrai rapidamente che ci sono migliaia miliardi di numeri interi che non possono essere rappresentati come float s. Ad esempio, tutti gli interi compresi nell'intervallo 16.777.219 e 16.777.221 sono rappresentati come 16.777.220.

EDIT nuovamente esecuzione che programma sopra indica che ci sono 2.071.986,175 milapositivi interi che non possono essere rappresentati con precisione come float s. Il che lascia approssimativamente solo 100 milioni di numeri interi positivi che si adattano correttamente a float. Ciò significa che solo un numero intero compreso tra ha ragione quando lo si inserisce in un float.

Mi aspetto che i numeri siano gli stessi per i numeri interi negativi.

+0

@BlueNovember: ogni numero intero> 2^24. – Stephen

+0

Non migliaia. Miliardi. – slacker

+0

il tuo codice converte un float (più grande) in int (più piccolo) quindi suppongo che ci sia una possibile perdita di dati. La mia domanda riguarda il fatto che int fluisca –

6

Sulla maggior parte delle architetture int e float hanno la stessa dimensione, in quanto hanno lo stesso numero di bit. Tuttavia, in un float questi bit sono divisi tra esponente e mantissa, il che significa che ci sono effettivamente meno bit di precisione nel float rispetto all'int. Questo è probabilmente solo un problema per i numeri interi più grandi, però.

Su sistemi in cui uno int è a 32 bit, un double è in genere a 64 bit e quindi può rappresentare esattamente qualsiasi int.

3

Entrambi i tipi sono composti da 4 byte (32 bit). Solo uno di questi consente una frazione (il galleggiante).

Prendi questo per un esempio flottante;

34,156

(intero) (frazione)

Ora usa la tua logica.; Se uno di questi deve salvare le informazioni sulle frazioni (dopotutto dovrebbe rappresentare un numero) significa che ha meno bit per la parte intera.

Quindi, un float può rappresentare un numero intero massimo che è inferiore alla capacità di tipo int.

Per essere più specifici, un "int" utilizza 32 bit per rappresentare un numero intero (numero intero senza segno massimo di 4.294.967.296). Un "float" usa 23 bit per farlo (numero intero senza segno massimo di 8.388.608).

Ecco perché quando si converte da int a float si potrebbero perdere dati.

Esempio: int = 1.158.354.125

Non è possibile memorizzare questo numero in un "galleggiare".

Maggiori informazioni su:

http://en.wikipedia.org/wiki/Single_precision_floating-point_format

http://en.wikipedia.org/wiki/Integer_%28computer_science%29

+0

Questo è leggermente sbagliato per alcuni motivi. Uno di questi è il 'float' con 24 bit per mantissa, non 23. Quindi ogni intero senza segno fino a 16777216 è esattamente rappresentabile. – slacker

+0

quanti bit fa il doppio uso per la mantisa? –

+0

Il galleggiante singolo IEEE 754 ha 23 bit di mantissa, che fornisce un intervallo effettivo di 24 bit perché l'esponente è normalizzato. La mantissa "ruba un po '" dall'esponente. –

0

Un float è di solito nel formato a precisione singola standard IEEE. Ciò significa che ci sono solo 24 bit di precisione in uno float, mentre uno int è probabile che sia 32 bit. Quindi, se il tuo int contiene un numero il cui valore assoluto non può rientrare in 24 bit, è probabile che sia arrotondato al numero rappresentabile più vicino.

+0

Nit: "Precision" ha un significato standard che è solo casualmente correlato all'intervallo dell'insieme di numeri rappresentabili. "Precision" è il numero positivo più piccolo che può essere aggiunto a 1.0 e produce un numero diverso da 1.0. La precisione di un int è quindi 1 (un bit, non 31 o 32). La precisione di un singolo float IEEE 754 è circa 5.96e-8 (24 bit). –

+0

@Jive Dadson: Ho usato la parola "precisione" in un modo più casuale (non formale). In questa risposta intendeva ovviamente "numero di bit significativi". – slacker

1

Precisione non importa. La precisione di int è 1, mentre la precisione di un float tipico (precisione singola IEEE 754) è approssimativamente 5.96e-8. Ciò che importa sono gli insiemi di numeri che i due formati possono rappresentare. Se ci sono numeri che int può rappresentare esattamente che float non può, allora c'è una possibile perdita di dati.

I float e gli ints sono in genere entrambi a 32 bit al giorno, ma ciò non è garantito. Supponendo che sia il caso sulla tua macchina, ne consegue che ci devono essere valori int che float non possono rappresentare esattamente, perché ci sono ovviamente valori float che int non può rappresentare esattamente. L'intervallo di un formato non può essere un super-set corretto dell'altro se entrambi i formati utilizzano lo stesso numero di bit in modo efficiente.

A 32 bit int ha effettivamente 31 bit che codificano per il valore assoluto del numero. Un float IEEE 754 ha effettivamente solo 24 bit che codificano per la mantissa (uno implicito).

0

Il fatto è che sia un float sia un int sono rappresentati utilizzando 32 bit. Il valore intero utilizza tutti i 32 bit in modo che possa contenere i numeri da -2 a 2 -1. Tuttavia, un float usa 1 bit per il segno (incluso -0.0f) e 8 bit per l'esponente. I mezzi 32 - 9 = 23 bit rimasti per la mantissa. Tuttavia, il float presuppone che se la mantissa e l'esponente non sono zero, allora la mantissa inizia con un 1. Quindi più o meno hai 24 bit per il tuo intero, invece di 32. Tuttavia, poiché può essere spostato, ospita più di 2 numeri interi.

A floating point uses a Sign, an eXponent, and a Mantissa 
S X X X X X X X X M M M M M M M M M M M M M M M M M M M M M M M 

An integer has a Sign, and a Mantissa 
S M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M 

Quindi, un numero intero come ad esempio:

1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 

si inserisce in un galleggiante, perché può essere spostato:

1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 
|  |        | 
|  +---------+     +---------+ 
|     |        | 
v     v        v 
S X X X X X X X X M M M M M M M M M M M M M M M M M M M M M M M 
1     1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 

io non ti mostro l'esponente perché il più delle volte commetti un errore nel calcolo, ma dovrebbe essere qualcosa come 5 (o -5?) perché ho spostato di 5 bit (ma devi aggiungere o sottrarre 128 ...). Questo ti mostra chiaramente che se devi spostare di 5 bit, perderai i 5 bit più bassi.

Quindi questo altro intero può essere convertito in un float con una perdita di 2 bit (ovvero quando si converte in un numero intero, gli ultimi due bit (11) sono impostati su zero (00) perché non sono stati salvati in il galleggiante):

1 0 0 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 
|  |        |    | | | | | 
|  +---------+     +---------+  +-+-+-+-+--> all lost 
|     |        | 
v     v        v 
S X X X X X X X X M M M M M M M M M M M M M M M M M M M M M M M 
1     1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 

Abbastanza semplice roba davvero.

NOTA IMPORTANTE: Sì, il primo 1 nel numero intero è il segno, quindi il primo 1 non viene copiato nella mantissa, si presume che sia 1 quindi non è necessario.

Problemi correlati