2012-04-27 14 views
13

¿Alguien puede explicar este comportamiento? Soy muy consciente de la representación a nivel de máquina de los números de coma flotante. Esto parece estar relacionado con printf y sus formatos. Ambos números están representados exactamente por notación de punto flotante (verificar: multiplicar por 64 da un número entero).printf comportamiento de redondeo para dobles

#include <stdio.h> 
#include <iostream> 
using namespace std; 

int main() { 
    double x1=108.765625; 
    printf("%34.30f\n", x1); 
    printf("%9.5f\n", x1); 
    printf("%34.30f\n", x1*64); 

    double x2=108.046875; 
    printf("%34.30lf\n", x2); 
    printf("%9.5f\n", x2); 
    printf("%34.30f\n", x2*64); 
} 

Salida:

> 108.765625000000000000000000000000 
> 108.76562 
> 6961.000000000000000000000000000000 
> 108.046875000000000000000000000000 
> 108.04688 
> 6915.000000000000000000000000000000 

Nota, el primer número se redondea hacia abajo, y el segundo se redondea hacia arriba.

+1

Puede que le interese mi artículo http://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/. Algunas implementaciones usan "round-half-away-from-zero" en lugar de "round-half-to-even". –

+0

Parece que Microsoft cambió su comportamiento de redondeo predeterminado en algún momento entre VS 2010 y VS2015. Acabo de actualizar de una a la otra y tengo algunos errores muy molestos y sutiles. [Este blog] (https://blogs.msdn.microsoft.com/vcblog/2014/06/18/c-runtime-crt-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1 /) probablemente esté destinado a resaltar el cambio, pero sería perdonado por perderlo por completo. – omatai

+0

depende de la implementación [Diferencias de redondeo en el sistema basado en Windows vs Unix en sprintf] (http://stackoverflow.com/q/4649554/995714), [Consistencia del comportamiento del redondeo C++ para las relaciones con sprintf] (http: // stackoverflow. com/q/31142600/995714) –

Respuesta

17

Es "la mitad redonda a la par" o "redondeo bancario". El último dígito de la representación redondeada se elige incluso si el número está exactamente a mitad de camino entre los dos.

http://linuxgazette.net/144/misc/lg/a_question_of_rounding_in_issue_143.html:
"Para la biblioteca de C de GNU, la regla de redondeo utilizado por printf() es 'banqueros redondeo' o 'ronda para incluso' Esto es más correcto que algunas otras bibliotecas de C, como dice la especificación C99. esa conversión a decimal debería usar el modo de redondeo IEEE seleccionado actualmente (redondeo bancario predeterminado) ".

+0

también: http://www.gnu.org/software/libc/manual/html_node/Rounding.html –

+1

El autor del artículo vinculado es incompetente. "La raíz binaria y decimal no comparten el mismo conjunto de números irracionales" - eso es una tontería. La racionalidad/irracionalidad es independiente de la base. –

+1

@R .. De hecho. Pero el pasaje citado del artículo es correcto, como el autor aprendió dolorosamente en su [informe de error] (http://sourceware.org/bugzilla/show_bug.cgi?id=4943). –

0

La salida %9.5f da el número con 5 dígitos después del punto decimal que es el más cercano al número fuente.