2016-12-06 3 views
1

Я пишу тест для функции, которая вычисляет тяжелые числа с плавающей запятой. Естественно, при вычислении поплавков вы не ожидаете получить точные результаты. Однако это проблема для моих тестов, так как мне нужно сравнить ожидаемые результаты с фактическими результатами, создаваемыми функцией.Сравнение списков поплавков с пониженной точностью

Результат моей функции - это алист поплавка. Например:

(is (my-function "arg1" "arg2") 
    '((0 1.0) 
     (1 2.0))) 

будет производить:

((0 1.00000014) (1 2.1)) is expected to be ((0 1) (1 2.1)) 

Мой вопрос: Как я могу пройти через ассоциативный список и сравнить каждое число с пониженной точностью?

prove Позволяет указать функцию тестирования при сравнении ожидаемых и фактических результатов. Вот мой код:

(defun compare-floats (f1 f2) 
    (= (round-to f1 6) 
    (round-to f2 6))) 

(defun round-to (number &optional (precision 6)) 
    (let ((div (expt 10 precision))) 
    (/ (round (* number div)) div))) 

(is (my-function "arg1" "arg2") 
    '((0 1.0) 
     (1 2.0)) 
    :test #'(lambda (expected actual) 
       (every #'identity 
         (mapcar #'(lambda (list1 list2) 
            (compare-floats (second list1) 
                (second list2))) 
           expected 
           actual)))) 

Это работает, но это не очень элегантно.

ответ

2

Мне кажется, что:

(every #'identity 
     (mapcar #'(lambda (list1 list2) 
        (compare-floats (second list1) 
            (second list2))) 
       expected 
       actual)) 

... может быть написано:

(every (lambda (list1 list2) 
     (compare-floats (second list1) (second list2))) 
     actual 
     expected) 

Обратите внимание, что every прекратит сравнения чисел, как только один тест возвращает NIL, который не является случай в вашей оригинальной функции. Если бы вы выполнили важные побочные эффекты, это было бы иначе.

Что касается тестирования поплавков, я использовал бы что-то вроде этого:

(defun floats-rougly-equal-p (f1 f2 &optional (precision 1e-6)) 
    (< (abs (- f1 f2)) precision)) 

Но если ваш код работает, не пытайтесь тратить слишком много времени на поиск наиболее элегантный подход.

+0

Спасибо! Намного приятнее. :) Я «трачу время», потому что я стараюсь стать лучше в программировании :) Конечно, можно сказать, что хороший разработчик знает, когда двигаться дальше ... – tsikov

+1

@tsikov Я понимаю. Это было просто предупреждение: '(declare (optimize (elegance 3)))' не стандартизирован. – coredump

2

LOOP:

(loop for (nil a) in actual 
     and (nil b) in expected 
     always (compare-floats a b)) 

Примечание кстати. что Common Lisp также предлагает двойные поплавки ...

Смежные вопросы