2011-04-06 26 views
5

He estado probando la función de techo y he obtenido algunos resultados extraños. Si realizo la operación ceil en un número decimal multiplicado por cien, obtengo un determinado resultado. Sin embargo, si realizo directamente ceil sobre el resultado de esa multiplicación, obtengo un resultado completamente diferente. Otro giro es que estos resultados diferentes solo ocurren para ciertos números. Cualquier ayuda sería apreciada.Extraños resultados con la función de techo C++

#include <stdio.h> 
#include <cmath> 

int main() 
{ 
cout << "The ceiling of " << 411 << " is " << ceil(411) << endl; 
cout << "The ceiling of 4.11*100 is " << ceil(4.11*100) << endl; 

cout << "The ceiling of " << 121 << " is " << ceil(121) << endl; 
cout << "The ceiling of 1.21*100 is " << ceil(1.21*100) << endl;; 
} 


OUTPUT: 

The ceiling of 411 is 411 
The ceiling of 4.11*100 is 412 
The ceiling of 121 is 121 
The ceiling of 1.21*100 is 121 

Respuesta

9

El problema aquí es que los números de punto flotante no se pueden representar de manera confiable por computadora. Eso significa que 4.11 no se representa como 4.11, sino algo muy parecido. Y cuando este "muy cerca de 4.11" número se multiplica por 100, el ceil del producto resulta ser 412, para su sorpresa! Pero una vez que sepa cómo se almacenan y recuperan los números de punto flotante, no es una sorpresa en absoluto.


Sólo hay que ver este interesante demostración:

float a = 3.2; //3.2 is double! 
if (a == 3.2) 
    cout << "a is equal to 3.2"<<endl; 
else 
    cout << "a is not equal to 3.2"<<endl; 

float b = 3.2f; //3.2f is a float. Note: f is appended to make it float! 
if (b == 3.2f) 
    cout << "b is equal to 3.2f"<<endl; 
else 
    cout << "b is not equal to 3.2f"<<endl; 

Salida:

a no es igual a 3.2
b es igual a 3.2f

hacer el experimento aquí en ideone: http://www.ideone.com/pAGzM

Intente cambiar el tipo de la variable a de float a double, vea the result again.

+0

Pero lo mismo ocurre incluso si uso el doble. Y esto siempre sucede con algunos números, pero no sucede con otros, eso es lo que realmente me confunde. – sowmya

+0

@sowmya: incluso los dobles son números de coma flotante. el tipo 'float' tiene menos precisión que el tipo' double'. Eso significa que "doble" se almacena con mayor precisión * comparativamente *, pero eso no significa que lo represente "con precisión". De hecho, 'doble' se llama así porque es un número de coma flotante de doble precisión. Vea esto: http://en.wikipedia.org/wiki/Double_precision_floating-point_format – Nawaz

+1

Usted usa 'double' en su código de muestra. No se usan números 'float' allí. –

5

Desde el FAQ:

[29.16] ¿Por qué es el punto flotante por lo inexacta? ¿Por qué esto no imprime 0.43?

#include <iostream> 

int main() 
{ 
    float a = 1000.43; 
    float b = 1000.0; 
    std::cout << a - b << '\n'; 
    ... 
} 

Negación: La frustración con redondeo/truncamiento/aproximación no es realmente un problema de C++; es un problema de ciencias de la computación . Sin embargo, la gente sigue preguntando sobre comp.lang.C++, por lo que lo que sigue es una respuesta nominal .

Respuesta: Punto flotante es una aproximación de . El estándar IEEE para flotador de 32 bits admite 1 bit de señal, 8 bits de exponente y 23 bits de mantisa. Como una mantisa de punto binario normalizada siempre tiene el formulario 0xxxde la forma 1.xxxxx ... el número 1 es caído y se obtienen efectivamente 24 bits de mantisa. El número 1000.43 (y muchos, muchos otros, incluidos algunos realmente comunes como 0.1) no es exactamente representable en formato doble float o . 1000.43 es en realidad representado como el bitpattern siguiente (la "s" muestra la posición del bit de signo, la "e" s muestran los posiciones de los bits de exponente, y la "M" s muestran las posiciones de la bits de mantisa):

seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm 
01000100011110100001101110000101 

La mantisa modificada es 1111101000.01101110000101 o 1000 + 7045/16384. La parte fraccionaria es 0.429992675781. Con 24 bits de mantisa, solo obtiene alrededor de 1 parte en 16M de precisión para flotar. El tipo doble proporciona más precisión (53 bits de mantisa).

También, ver [29.17] Why doesn't my floating-point comparison work?

1

La función ceil(x) devuelve el número entero más pequeño no menos x.

Dado que las constantes que escriba (como 4.11 o 1.21) no se representan con precisión, es posible que se representen con un número ligeramente menor o con un número ligeramente mayor o en casos excepcionales con los mismos números. P.ej. su compilador representa constante 4.11 como un número ligeramente mayor, por lo que 4.11*100 es ligeramente mayor que 411 así que ceil(4.11*100) == 412 (porque 412 es el número más pequeño no menos que el número ligeramente mayor que 411), pero 1.21 se representa como un número ligeramente menor, así 1.21*100 un poco más pequeño que 121 así que ceil(1.21*100)==121.

También tenga en cuenta que la multiplicación no es precisa también.

Cuestiones relacionadas