2016-04-27 10 views
19

Dato il codice C:Perché colata a int non pavimento tutte doppie in C

#include <math.h> 
#include <stdio.h> 
int main(){ 
int i; 
double f=log(2.0)/log(pow(2.0,1.0/2.0)); 
printf("double=%f\n",f); 
printf("int=%d\n",(int) f); 
} 

ottengo l'output:

double=2.000000 
int=1 

f è apparentemente almeno 2,0. Perché il cast value non è 2?

+11

Sembra che la premessa la domanda è falsa, dalle risposte. Il vero "problema" è che printf arrotonda numeri in virgola mobile. – user35702

+0

Si potrebbe anche considerare un caso in cui int ha la stessa dimensione del doppio e si fa qualcosa come 'log ((double) int_64_variable)'. Sono più incline a farlo su un pezzo di carta che a scrivere un programma c per questo. ;) – sjsam

+1

Si noti inoltre che il lancio in 'int' non * non * floor ma piuttosto tronca verso zero. Questo è importante per i valori negativi. – jamesdlin

risposta

34

Poiché il valore della doppia era meno di 2

double=1.99999999999999978 
int=1 

provare, ma questa volta aggiungere un po 'di precisione

#include <math.h> 
#include <stdio.h> 
int main(){ 
int i; 
double f=log(2.0)/log(pow(2.0,1.0/2.0)); 
printf("double=%0.17f\n",f); 
printf("int=%d\n",(int) f); 
} 

fuorviante in quanto l'inferno la prima volta che si verifica esso. Ora, se provi questo

#include <math.h> 
#include <stdio.h> 
int main(){ 
int i; 
double f=log(2.0)/log(pow(2.0,1.0/2.0)); 
printf("double=%0.17f\n",f); 
printf("int=%d\n",(int) f); 
printf("int=%d\n", (int)round(f)); 
} 

Girerà correttamente il valore. Se si guarda nella pagina man (su un Mac, almeno) si vedrà il seguente commento ...

round, lround, llround -- round to integral value, regardless of rounding direction 

Che cosa si intende per direzione, è tutto specificato nella IEEE 754. Se si seleziona il pavimento different ways to round to an integer... è menzionato come arrotondamento verso -ve infinity che in questo caso è stato verso 1 :)

7

integer non assume un valore arrotondato ma rende un troncamento. Quindi, se f è uguale a 1.999999999999 [..] 9, il valore int sarà 1.

Inoltre, poiché il doppio vuole essere il più accurato possibile, prenderà un valore arrotondato considerando il numero di caratteri può mostrare, che è 2.000000.

7

I tipi di punti mobili non sono in grado di rappresentare esattamente alcuni numeri. Sebbene matematicamente, lo calculation should be exactly 2, con i punti mobili IEEE754, il risultato risulti leggermente inferiore a 2. Per ulteriori informazioni, vedere this question.

Se si aumenta la precisione del vostro output specificando %.20f invece di %f, si vedrà che il numero non è esattamente 2, e che quando la stampa con minore precisione, il risultato è semplicemente arrotondato.

Durante la conversione in un int tuttavia, la piena precisione del tipo a virgola mobile viene utilizzato, e poiché si tratta di poco meno di 2, il risultato quando si converte in un numero intero è 1.