Разные результаты при применении функции к одинаковым значениям - PullRequest
0 голосов
/ 31 марта 2010

Я просто немного копаюсь в Хаскеле и начал с того, что пытался вычислить фи-коэффициент двух слов в тексте. Однако я столкнулся с очень странным поведением, которое не могу объяснить.

После того, как все разобрали, я получил этот код для воспроизведения проблемы:

let sumTup = (sumTuples∘concat) frequencyLists
let sumFixTup = (138, 136, 17, 204)
putStrLn (show ((138, 136, 17, 204) == sumTup))
putStrLn (show (phi sumTup))
putStrLn (show (phi sumFixTup))

Это выводит:

True
NaN
0.4574206676616167

Таким образом, хотя sumTup и sumFixTup показывают одинаковое значение, они ведут себя по-разному при передаче в phi.

Определение phi:

phi (a, b, c, d) = 
    let dividend = fromIntegral(a * d - b * c)
        divisor = sqrt(fromIntegral((a + b) * (c + d) * (a + c) * (b + d)))
    in dividend / divisor

1 Ответ

8 голосов
/ 31 марта 2010

Это может быть случай целочисленного переполнения. Значение, передаваемое в fromIntegral в вашем делителе, равно 3191195800, что больше, чем может вместить 32-разрядное знаковое Int.

В ghci (или что вы используете), используйте

:t sumTup
:t sumFixTup

чтобы увидеть типы этих переменных. Я предполагаю, что вы обнаружите, что sumTup - это (Int, Int, Int, Int) (переполнение), а sumFixTup - это (Integer, Integer, Integer, Integer) (не переполнение).

Редактировать: если подумать, кортеж Ints не может быть равен кортежу целых чисел. Тем не менее, я думаю, что ghci исправит тип sumFixTup как кортеж целых чисел, тогда как sumTup, вероятно, имеет тип вида (Num a) => (a, a, a, a) или (Integral a) => (a, a, a, a), который зависит от функции, определяющей его. 1017 *

Затем Ghci преобразует их в целые числа для сравнения с sumFixTup, но может преобразовывать их в целые числа при вычислении делителя в phi, вызывая переполнение.


Другое редактирование: KennyTM, вы наполовину правы:

Prelude> :t (1,2,3,4)
(1,2,3,4) :: (Num t, Num t1, Num t2, Num t3) => (t, t1, t2, t3)
Prelude> let tup = (1,2,3,4)
Prelude> :t tup
tup :: (Integer, Integer, Integer, Integer)

Итак, для примеров, приведенных в вопросе:

putStrLn (show ((138, 136, 17, 204) == sumTup))

Литерал (138, 136, 17, 204) выводится как кортеж Int, чтобы соответствовать sumTup, и они сравниваются равными.

putStrLn (show (phi sumTup))

sumTup состоит из Int с, вызывая переполнение, как указано выше.

putStrLn (show (phi sumFixTup))

sumFixTup состоит из Integer с, что дает правильный результат. Обратите внимание, что sumTup и sumFixTup никогда не сравнивались напрямую, поэтому мое более раннее редактирование было основано на неправильном прочтении.

...