assert терпит неудачу, когда не должен, в тестовом примере Smalltalk Unit

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

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

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


person sherry    schedule 27.09.2011    source источник


Ответы (3)


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

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

person Lukas Renggli    schedule 27.09.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: с точки зрения Float>>#equal: вместо #=.

person Esteban A. Maringolo    schedule 18.10.2011

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

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

5.1 squared printString
-> '26.01'

но

5.1 squared = 26.01
-> false

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

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
person aka.nice    schedule 17.07.2012