assert fails when it should not, in Smalltalk Unit testcase
I'm stumped. Here is my testcase.
theTestArray := #(1.2 3 5.1 7).
self assert: theTestArray squareOfAllElements = #(1.44 9 26.01 49).
The assert should not fail. On calculating the square of each element is correct. So I did "step into test", shows that the result of the method squareOfAllElements and #(1.44 9 26.01 49) are both the same but assert evaluates to false. why? What 开发者_开发百科am I doing wrong here? Any help is appreciated.
You are dealing with floating point numbers here. Floating point numbers are inexact by definition and you should never compare them using #=.
For details check Section 1.1 of the draft chapter on floating point numbers of Pharo by Example: http://stephane.ducasse.free.fr/Web/Draft/Float.pdf
However, the comparison equality message, #=, is sent to the collection presumably returned by #squareOfAllElements.
You can rewrite your test statement as:
theTestArray := #(1.2 3 5.1 7).
theSquaredArray := theTestArray collect: [:each | each squared].
theTestArray with: theSquaredArray do: [:a :b | self assert: (a equals: b) ].
That will test the same as the previous one, but will run one #assert: per element.
Other option would be to implement a variation of #hasEqualElements: in terms of Float>>#equal: instead of #=.
As said in other answers, Float are inexact. Also remember that Visualworks Float default to single precision (about 7 decimal places), if you posfix your float number with letter d, like 5.1d you'll get double precision (about 15 decimal places), less inexact, but still inexact.
One additional source of confusion is that two different Float can print with the same approximate decimal representation in Visualworks.
5.1 squared printString
-> '26.01'
but
5.1 squared = 26.01
-> false
Note that recent Squeak or Pharo prints just enough decimals to distinguish different Float (and reinterpret them unchanged)
5.1 squared
->26.009999999999998
Alternatively, you can use the so called FixedPoint (in VisualWorks, or ScaledDecimals in other flavours) to perform exact operations:
theTestArray := #(1.2s 3 5.1s 7).
self assert: theTestArray squareOfAllElements = #(1.44s 9 26.01s 49).
Also beware of this other trap: a FixedPoint (ScaledDecimals) prints only as many decimals after the fraction point as it was told to, but internally it can hold more (infinitely many).
5.1s1 squared printString
-> '26.0s1'
but
5.1s1 squared = 26.01s2
-> true
精彩评论