2010-03-31 1 views
0

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

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

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 
+3

Как насчет определений 'sumTuples' и' FrequencyLists'? – Nefrubyr

+0

Они несколько длинные, как вы думаете, это поможет их добавить? Я на самом деле явно набрал 'sumTuples' для' sumTuples :: [(Int, Int, Int, Int)] -> (Int, Int, Int, Int) '. –

ответ

8

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

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

:t sumTup 
:t sumFixTup 

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

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

Ghci затем преобразует их в целые числа, чтобы сравнить их с sumFixTup, но может преобразовывать их в Ints при расчете делителя в 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 никогда не сравнивались напрямую, поэтому мое раннее редактирование было основано на неправильном чтении.

+0

Хех, у нас была такая же интуиция; Мне любопытно, если это правда. – Dan

+0

Фактически, согласно http://www.haskell.org/ghc/docs/latest/html/libraries/base-4.2.0.0/Data-Int.html, 'Int' гарантируется как минимум 30 -bit signed int – newacct

+0

Фактически 'sumFixTup' имеет тип' (Num t, Num t1, Num t2, Num t3) => (t, t1, t2, t3) '. – kennytm

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