2011-09-27 9 views
6

I'm stumped. Ecco la mia prova.non riesce quando non dovrebbe, in Testcase Smalltalk Unit

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

L'asserzione non deve fallire. Il calcolo del quadrato di ogni elemento è corretto. Così ho fatto "step in test", mostra che il risultato del metodo squareOfAllElements e # (1.44 9 26.01 49) sono entrambi uguali ma asseriscono valori falsi. perché? Cosa sto facendo di sbagliato qui? Qualsiasi aiuto è apprezzato.

risposta

8

Si tratta di numeri in virgola mobile qui. I numeri in virgola mobile sono inesatti per definizione e non dovresti mai confrontarli usando # =.

Per i dettagli, vedere la sezione 1.1 del progetto di capitolo sui numeri in virgola di Pharo galleggianti Esempio: http://stephane.ducasse.free.fr/Web/Draft/Float.pdf

0

Tuttavia, il messaggio uguaglianza confronto, # =, viene inviato alla raccolta presumibilmente restituito da #squareOfAllElements.

È possibile riscrivere la sua dichiarazione come prova:

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

che metterà alla prova lo stesso di quello precedente, ma verrà eseguito uno #assert: per ogni elemento.

Un'altra opzione sarebbe quella di implementare una variazione di #hasEqualElements: in termini di Float >> # uguale: invece di # =.

0

Come detto in altre risposte, Float non sono esatti. Ricorda inoltre che Visualworks Float ha l'impostazione predefinita di precisione singola (circa 7 posizioni decimali), se hai posfix il tuo numero float con la lettera d, come 5.1d otterrai una precisione doppia (circa 15 posizioni decimali), meno inesatta, ma ancora inesatta.

Un'ulteriore fonte di confusione è che due Float diversi possono stampare con la stessa rappresentazione approssimativa decimale in Visualworks.

5.1 squared printString 
-> '26.01' 

ma

5.1 squared = 26.01 
-> false 

Nota che la recente Squeak o stampe Pharo appena sufficiente decimali di distinguere Float diverso (e li reinterpretano invariato)

5.1 squared 
->26.009999999999998 

In alternativa, è possibile utilizzare il cosiddetto FixedPoint (in VisualWorks o ScaledDecimals in altri formati) per eseguire operazioni esatte:

Attenzione anche a questa altra trappola: un Punto Fisso (ScaledDecimals) stampa solo tanti decimali dopo il punto di frazione come gli è stato detto, ma internamente può contenere più (infinitamente molti).

5.1s1 squared printString 
-> '26.0s1' 

ma

5.1s1 squared = 26.01s2 
-> true