assert терпит неудачу, когда это не должно, в тестовом примере Smalltalk Unit - PullRequest
6 голосов
/ 27 сентября 2011

Я в тупике. Вот мой тестовый пример.

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

Утверждение не должно провалиться. По расчету квадрат каждого элемента является правильным. Итак, я сделал «шаг в тест», показывает, что результат метода squareOfAllElements и # (1.44 9 26.01 49) оба одинаковы, но assert оценивается как false. Зачем? Что я здесь не так делаю? Любая помощь приветствуется.

Ответы [ 3 ]

8 голосов
/ 27 сентября 2011

Вы имеете дело с числами с плавающей запятой здесь.Числа с плавающей запятой неточны по определению, и вы никогда не должны сравнивать их, используя # =.

Для получения подробной информации смотрите Раздел 1.1 черновика главы о числах с плавающей запятой Pharo в Примере : http://stephane.ducasse.free.fr/Web/Draft/Float.pdf

0 голосов
/ 18 июля 2012

Как сказано в других ответах, Float неточны. Также помните, что в Visualworks Float по умолчанию используется одинарная точность (около 7 десятичных знаков), если вы добавите число с плавающей запятой к букве d, например, 5.1d, вы получите двойную точность (около 15 десятичных знаков), менее неточную, но все же неточную. 1001 *

Еще одним источником путаницы является то, что два разных Float могут печатать с одинаковым приблизительным десятичным представлением в Visualworks.

5.1 squared printString
-> '26.01'

но

5.1 squared = 26.01
-> false

Обратите внимание, что последние Squeak или Pharo печатают достаточно десятичных знаков, чтобы различать различные значения с плавающей точкой (и интерпретировать их без изменений)

5.1 squared
->26.009999999999998

В качестве альтернативы вы можете использовать так называемую FixedPoint (в VisualWorks или ScaledDecimals в других вариантах) для выполнения точных операций:

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

Также остерегайтесь этой другой ловушки: FixedPoint (ScaledDecimals) печатает только столько десятичных знаков после точки дроби, сколько ему было сказано, но внутренне он может содержать больше (бесконечно много).

5.1s1 squared printString
-> '26.0s1'

но

5.1s1 squared = 26.01s2
-> true
0 голосов
/ 18 октября 2011

Однако сообщение о равенстве сравнения, # =, отправляется в коллекцию, предположительно возвращенную # squareOfAllElements.

Вы можете переписать свой тестовый оператор как:

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

Это будет проверять то же, что и предыдущий, но будет запускать один #assert: за элемент.

Другой вариант заключается в реализации варианта #hasEqualElements: в терминах с плавающей точкой >> # равный: вместо # =.

...