Сравнение списка поплавков - PullRequest
3 голосов
/ 22 октября 2010

Я написал код:

let rec compareVs v1 v2 =
 if List.length v1 == 0 then
  true
 else
  ((match v1 with [] -> 0. | h::l -> h) == (match v2 with [] -> 0. | h::l -> h)) && 
  (compareVs(match v1 with [] -> [] | h::l -> l) (match v2 with [] -> [] | h::l -> l))

И запустил его:

# compareVs [0.1;0.1] [0.1;0.1];;
- : bool = false

Не могу найти проблему. Пожалуйста, помогите.

EDIT

Проблема швов должна быть с плавающими сравнениями:

# 0.1 == 0.1;;
- : bool = false
# 1.0 == 1.0;;
- : bool = false

Как еще мы можем сравнить поплавки в ocaml?

Ответы [ 2 ]

11 голосов
/ 22 октября 2010

Используйте =, а не ==.

Плавающие являются ссылочными типами в ocaml, а == проверяет равенство ссылок. Так что 0.1 == 0.1 ложно.

Как правило, вы почти всегда хотите использовать =, а не == для сравнения двух значений.

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

Как примечание стиля, использование List.length для проверки, является ли список пустым, обычно плохая идея (во-первых, это O (n), даже если это можно сделать в O (1) с сопоставлением с образцом). Использование сопоставления с образцом в самом начале также немного очистит ваш код.

Как это:

let rec compareVs v1 v2 = match v1, v2 with
| [], []       -> true
| [], _
| _, []        -> false
| x::xs, y::ys -> x = y && compareVs xs ys

Да, и если это не просто упражнение, обратите внимание, что вы можете просто выполнить v1 = v2 и на самом деле не нужно писать для этого функцию.

5 голосов
/ 22 октября 2010

Sepp2k корректен, но в качестве дополнительного обсуждения по сравнению поплавков (что часто опасно) мне помогли следующие функции:

Это сравнивает два числа с плавающей точкой с допуском epsilon, и синтаксис будет аналогичен другим функциям с плавающей точкой. явно расширяется >. и другие очевидны.

let epsilon = 1.0e-10
let (=.) a b = (abs_float (a-.b)) < epsilon

Если вы имеете дело со многими экстремальными значениями с плавающей точкой, вам следует взглянуть на функцию classify_float в модуле pervasives . Я не припоминаю, как сравниваются значения NAN в функции =. Вы можете самостоятельно поэкспериментировать с этим, если вам нужно.

Я использовал это некоторое время, но на самом деле его допуск был очень низким (например, очень маленькое значение для epsilon, как указано выше). Это не учитывает того, что делает NAN - NAN. Так что это может быть бесполезно.

    let (=.) a b = match classify_float ( a -. b ) with
        | FP_infinite  | FP_nan | FP_normal -> false
        | FP_subnormal | FP_zero -> true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...