2015-02-02 11 views
10

Sono perso nel rapporto di clojure. Non riesco a capirlo Perché i test di uguaglianza e disuguaglianza si comportano in questo modo?perché clojure clojure.lang.Ratio 3/2 not = 1,5

(= 3/2 1.5) 
;; false 
(>= 3/2 1.5) 
;; true 
(> 3/2 1.5) 
;;false 
(not= 3/2 1.5) 
;; true 
+0

questa domanda non è un duplicato di: http://stackoverflow.com/questions/2364566/and-in-clojure?rq=1 perché la lingua è cambiata da quando è stata posta la domanda, quindi gli esempi in quella domanda sono stati stabiliti la risposta non funziona Si pone anche la domanda da un contesto diverso –

+0

A proposito, questo non è specifico per i rapporti. '(= 1 1.0)' restituisce 'false'. – Thumbnail

risposta

12

Usa == per i confronti numerici in cui si desidera sapere se due numeri rappresentano lo stesso numero indipendentemente dal tipi:

user> (= 3/2 1.5) 
false 
user> (== 3/2 1.5) 
true 

Anche se tenere presente che == è solo per i numeri e getta, se dato qualcosa non un numero.

user> (== :1 :1) 
ClassCastException clojure.lang.Keyword cannot be cast to java.lang.Number clojure.lang.Numbers.equiv (Numbers.java:206) 
+1

Come mostra la tua risposta, '(==: 1: 1)' genera un'eccezione. Non restituisce false, come prima o qualsiasi altra cosa. – Thumbnail

+0

Mi dispiace, ho dimenticato di modificare la mia risposta dopo aver provato e aggiunto l'esempio. –

2

Clojure si sforza di tenere lontano da carri come sono suscettibili di errori di arrotondamento:

user=> (+ 0.1 0.2) 
0.30000000000000004 
user=> 

Così il vero motivo per il confronto ha esito negativo è che non c'è modo preciso per rappresentare 1.5 internamente, e il momento in cui il parser Clojure consuma informazioni "1.5" è potenzialmente perso.

Utilizzando frazioni, non c'è alcuna perdita di informazioni, così la forma frazione 3/2 possono essere liberamente passare attorno ad altre funzioni senza timore di errori di arrotondamento fuga as was the case with the infamous Patriot missile bug.

+2

Hmm. Supponendo che Clojure stia usando i float IEEE 754 binary64 (come Java, e praticamente tutti gli altri linguaggi mainstream), '1.5' assolutamente * può * essere rappresentato con precisione, dal momento che è perfettamente espresso in binario come' 1.1'. '1.4' sarebbe diverso, naturalmente ... –

+1

ok, il fraseggio corretto sarebbe _ ogni volta che Clojure consuma un float, le informazioni potrebbero andare perse ..." _ – ekarak

1

poche parole, in rapporto Clojure è un tipo. Non prova a convertirlo in double o float o qualcosa del genere. In questo modo è possibile preservare ciò che il numero rappresenta in realtà senza perdere precisione.

Check-out Il discorso di Rich Hickey chiamato "Clojure for Java Programmers" in YouTube, lo spiega meglio.

Problemi correlati