2011-09-27 10 views
6

Estoy perplejo. Aquí está mi testcase.la afirmación falla cuando no debería, en Smalltalk Unit testcase

theTestArray := #(1.2 3 5.1 7). 
self assert: theTestArray squareOfAllElements = #(1.44 9 26.01 49). 

La afirmación no debe fallar. Al calcular el cuadrado de cada elemento es correcto. Así que hice "paso a prueba", muestra que el resultado del método squareOfAllElements y # (1.44 9 26.01 49) son los mismos pero assert evalúa como falso. ¿por qué? ¿Qué estoy haciendo mal aquí? Cualquier ayuda es apreciada.

Respuesta

8

Aquí se trata de números de coma flotante. Los números de coma flotante son inexactos por definición y nunca debe compararlos usando # =.

Para más detalles revise Sección 1.1 del proyecto de capítulo sobre los números de punto flotante de Pharo por ejemplo: http://stephane.ducasse.free.fr/Web/Draft/Float.pdf

0

Sin embargo, el mensaje de comparación de igualdad, # =, se envía a la colección de suponer que devuelve #squareOfAllElements.

Puede volver a escribir su estado de prueba como:

theTestArray := #(1.2 3 5.1 7). 
theSquaredArray := theTestArray collect: [:each | each squared]. 
theTestArray with: theSquaredArray do: [:a :b | self assert: (a equals: b) ]. 

que pondrá a prueba el mismo que el anterior, pero se ejecutará una #assert: por elemento.

Otra opción sería implementar una variación de #hasEqualElements: en términos de Float >> # equal: en lugar de # =.

0

Como dije en otras respuestas, Float es inexacto. Además, recuerde que la flotación de Visualworks predeterminada con precisión única (alrededor de 7 lugares decimales), si posifica su número de flotación con la letra d, como 5.1d obtendrá una precisión doble (aproximadamente 15 decimales), menos inexacta, pero aún inexacta.

Una fuente adicional de confusión es que dos Float diferentes pueden imprimirse con la misma representación decimal aproximada en Visualworks.

5.1 squared printString 
-> '26.01' 

pero

5.1 squared = 26.01 
-> false 

Tenga en cuenta que Squeak reciente o impresiones Pharo sólo lo suficiente decimales para distinguir diferentes flotador (y reinterpretan sin cambios)

5.1 squared 
->26.009999999999998 

Como alternativa, puede utilizar la llamada FixedPoint (en VisualWorks o ScaledDecimales en otros sabores) para realizar operaciones exactas:

theTestArray := #(1.2s 3 5.1s 7). 
self assert: theTestArray squareOfAllElements = #(1.44s 9 26.01s 49). 

También tenga cuidado con esta otra trampa: un FixedPoint (ScaledDecimals) imprime solo tantos decimales después del punto de fracción como se le dijo, pero internamente puede contener más (infinitamente muchos).

5.1s1 squared printString 
-> '26.0s1' 

pero

5.1s1 squared = 26.01s2 
-> true 
Cuestiones relacionadas