2011-09-27 2 views
6

Je suis perplexe. Voici mon test.assert échoue quand il ne devrait pas, dans Smalltalk Unit testcase

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

L'affirmation ne doit pas échouer. Le calcul du carré de chaque élément est correct. J'ai donc fait un "step into test", montre que le résultat de la méthode squareOfAllElements et # (1.44 9 26.01 49) sont tous les deux identiques mais que assert est évalué à false. Pourquoi? Qu'est-ce que je fais mal ici? Toute aide est appréciée.

Répondre

8

Vous avez ici affaire à des nombres à virgule flottante. Les nombres à virgule flottante sont inexacts par définition et vous ne devriez jamais les comparer en utilisant # =.

Pour plus de détails à la section 1.1 du projet de chapitre sur les nombres à virgule flottante de Pharo par exemple: http://stephane.ducasse.free.fr/Web/Draft/Float.pdf

0

Cependant, le message d'égalité de comparaison, # =, est envoyé à la collection vraisemblablement retourné par #squareOfAllElements.

Vous pouvez réécrire votre déclaration de test:

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

qui testera le même que le précédent, mais se déroulera un #assert: par élément.

L'autre option serait d'implémenter une variante de #hasEqualElements: en termes de Float >> # equal: au lieu de # =.

0

Comme indiqué dans les autres réponses, Float sont inexacts. Souvenez-vous aussi que Visualworks Float par défaut à une seule précision (environ 7 décimales), si vous posfix votre nombre float avec la lettre d, comme 5.1d vous obtiendrez double précision (environ 15 décimales), moins inexact, mais toujours inexact.

Une autre source de confusion est que deux types de fichiers Float peuvent imprimer avec la même représentation décimale approximative dans Visualworks.

5.1 squared printString 
-> '26.01' 

mais

5.1 squared = 26.01 
-> false 

Notez que Squeak récentes ou impressions Pharo seulement décimaux assez pour distinguer les différents Float (et les réinterprètent inchangé)

5.1 squared 
->26.009999999999998 

Vous pouvez également utiliser le soi-disant FixedPoint (dans VisualWorks, ou ScaledDecimals dans d'autres versions) pour effectuer des opérations exactes:

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

Méfiez-vous également de cet autre piège: un FixedPoint (ScaledDecimals) imprime seulement autant de décimales après le point de fraction qu'on le lui a demandé, mais en interne il peut en contenir plus (infiniment).

5.1s1 squared printString 
-> '26.0s1' 

mais

5.1s1 squared = 26.01s2 
-> true 
Questions connexes