2012-03-22 21 views
12

fiesta de GNU, versión 4.2.24:extraño "a la mitad, incluso" redondeo en diferentes idiomas

$> printf "%.0f, %.0f\n" 48.5 49.5 
48, 50 

de Ruby 1.8.7

> printf("%.0f, %.0f\n", 48.5, 49.5) 
48, 50 

Perl 5.12.4

$> perl -e 'printf("%.0f, %.0f\n", 48.5, 49.5)' 
48, 50 

gcc 4.5.3:

> printf("%.0f, %.0f\n", 48.5, 49.5); 
48, 50 

GHC, versión 7.0.4:

> printf "%.0f, %.0f\n" 48.5 49.5 
49, 50 

Wikipedia dice que este tipo de redondeo se llama round half to even:

Este es el modo por defecto utilizado en el estándar IEEE 754 funciones de computación y los operadores de redondeo .

¿Por qué este redondeo se usa por defecto en C, Perl, Ruby y bash, pero no en Haskell?

¿Es algún tipo de tradición o estándar? Y si es un estándar, ¿por qué es utilizado por esos idiomas y no lo usa Haskell? ¿Cuál es el punto de redondear la mitad a par?

+4

Creo que acabas de responder a tu propia pregunta. Es parte del estándar IEEE 754. –

+0

@Keith Irwin, creo que él quería saber qué estándar. ¿Por qué no publica eso como respuesta, con suerte con un enlace relevante? – ikegami

+2

Dmitry: Su pregunta menciona específicamente "IEEE 754". Ese es el estándar. – Gabe

Respuesta

11
GHCi> round 48.5 
48 
GHCi> round 49.5 
50 

La única diferencia es que no está utilizando printfround - presumiblemente debido a que tiene que ser capaz de reunir a más de números enteros simplemente enteros. No creo que IEEE 754 especifique nada sobre cómo implementar las funciones de formato de estilo printf, solo redondear, que Haskell hace correctamente.

Probablemente sería mejor si printf fuera coherente con round y las implementaciones en otros idiomas, pero no creo que sea realmente un gran problema.

+0

las funciones de formato de estilo printf se convierten a un formato decimal de punto fijo. IEEE 754 recomienda que las conversiones se realicen en el modo de redondeo actual, que es el más cercano, incluso de manera predeterminada. Tenga en cuenta que muchos lenguajes/plataformas siguen obteniendo este error a partir de 2012, utilizando las conversiones más parecidas, independientemente del modo de redondeo actual. –

+5

@PascalCuoq: ¡Gracias por la información! Sin embargo, Haskell simplemente no puede cumplir con esa recomendación, ya que 'printf' tiene que ser una función pura. Tendría que tomar el modo de redondeo como parámetro u operar en un contexto (por ejemplo, monádico) donde esa información esté disponible. – ehird

+0

Buen punto. Los estándares independientes del idioma como IEEE 754 dejan mucha ambigüedad y pueden ser inconvenientes para acomodar. Otra situación relativamente similar es la verificación de la lógica de Hoare de los programas de punto flotante imperativos, donde preferiría evitar pensar en el modo de redondeo como una parte adicional del estado del programa y el argumento de todas las funciones de coma flotante, pero debe hacerlo para manejar programas que lo modifican en tiempo de ejecución. –

2

No puedo decirlo con certeza, pero esto probablemente tiene que ver con el hecho de que este tipo de redondeo se usa comúnmente en funciones de contabilidad, ya que también se conoce como redondeo bancario. Si mira más allá en el artículo de Wikipedia sobre el redondeo, también notará que está predeterminado en IEEE 754, por lo que es probable que Haskell no esté siguiendo ese estándar.

+1

El artículo enlazado de Wiki dice que "el origen del término redondeo de los banqueros permanece más oscuro. Si este método de redondeo fue alguna vez un estándar en la banca, la evidencia ha resultado ser extremadamente difícil de encontrar. Por el contrario, la sección 2 del Informe de la Comisión La introducción del euro y el redondeo de los importes de las divisas [16] sugiere que anteriormente no existía un enfoque estándar para el redondeo en la banca, y especifica que los montos "a mitad de camino" deberían estar "redondeados". Entonces los banqueros __no usan__ el redondeo del banquero. –

+0

@ A.H. En realidad, todavía usan el redondeo bancario de forma limitada. Puedo afirmarlo con conocimiento, ya que solía trabajar para un grupo bancario. –

+0

Tengo conocimiento de primera mano del redondeo utilizado en instituciones financieras también. Pero no en los Estados Unidos. Pero la audiencia aquí también es internacional. –

6

"Round to even" es el valor predeterminado para usar con IEEE 754. Haskell probablemente debería cambiar a usarlo en printf por razones de coherencia. La línea correspondiente del código está en GHC.Float

f 0 (x:_) = (if x >= b2 then 1 else 0, []) 

lo tanto, si alguien quiere solucionarlo, pueden hacerlo. Como se señala en otro lugar, esto simplemente haría que la función roundTo sea utilizada por printf consistente con round aunque no estoy seguro de qué otro código podría romperse.

EDITAR: una versión anterior de esta respuesta tiene la ubicación incorrecta del código de redondeo. La única diferencia significativa entre las dos implementaciones es si están codificadas para usar la base 10.

+2

No creo que sea la línea correcta de código. 'Text.Printf' funciona con' String', no 'Text'. – ehird

+0

@ehird Text.Printf llama a una función auxiliar llamada 'dfmt'' que llama a otro asistente llamado' dfmt' que llama a 'showFFloat' de Numérico. Lo que hace desde allí depende la implementación, y cuando respondí esta pregunta, pensé que había rastreado el código GHC al módulo 'Data.Text', ahora necesito verificarlo. –

+0

parece correcto: a partir de GHC 7.4.1 la función 'roundTo' llamada por' formatRealFloat' se incluye en ese archivo en lugar de una llamada a 'Data.Text.etc'. Hace lo mismo, pero es consciente de la base –

Cuestiones relacionadas