Thanks for the very detailed explanation and all of the code examples.
I was a bit twiddler a long time ago.
(I enjoyed reading the opcodes in the mainframe dumps)

Lisp is a new language. And, I think it counts as the Language of
theYear,
since it is so different than Java.

I was playing with java.util.Date and range, by converting to number
with .getTime.
I couldn't figure out how to create a Date. I finally re-read the Date
constructor
and realized I had to coerce the number to a long. The compiler/
interpreter was
telling me the truth. There wasn't a Date constructor for number.

I was also playing with "with-precision" and "rounding".




On Mar 6, 9:06 pm, David Sletten <da...@bosatsu.net> wrote:
> On Mar 5, 2009, at 8:00 PM, mike.farn...@gmail.com wrote:
>
>
>
> > I thought it neat that clojure supports fractions (just like
> > Smalltalk).
> > user=> (/ 3)
> > 1/3
>
> > I was sort of surprised by this.
>
> > user=> (+ (float (* (/ 2) (/ 3))) (float (* (/ 2) (/ 3))) )
> > 0.33333334
>
> It comes as no surprise that certain numbers cannot be represented by  
> a finite string of decimal digits. We all realize that 1/3 =  
> 0.3333..., and the "..." part is critical. Take it away and the  
> equality goes away too. In other words, if that string of 3's stops,  
> then we don't have 1/3 anymore.
>
> This situation is true inside the computer too. The floating-point  
> representation of 1/3 is binary 0.01010101010101... Whereas in  
> decimal we have 1/3 = 3*1/10 + 3*1/100 + 3*1/1000 + ..., in binary we  
> have 1/3 = 0*1/2 + 1*1/4 + 0*1/8 + 1*1/16 + ... If this sum stops we  
> once again lose equality. However, the computer only has finite  
> memory in which to represent a floating-point number, so the string  
> of "01"s does in fact stop. The computer cannot represent 1/3 exactly  
> in floating-point. Suppose for the sake of argument that the computer  
> only stores the equivalent of 4 decimal digits. So we get 1/3 ->  
> 0.3333. But the true value is 0.3333 < 1/3 < 0.3334. In terms of the  
> binary representation, depending on how many bits are used the  
> decimal representation may be slightly closer to 0.3334 rather than  
> 0.3333. You saw that by using the "float" function, which coerces the  
> Ratio 1/3 to a single-precision float:
> (float 1/3) => 0.33333334
>
> If you had coerced to a double-precision float you would have seen this:
> (double 1/3) => 0.3333333333333333
>
> Neither one of these is more "correct" per se (the double is more  
> precise of course). They simply reflect the limitations of different  
> finite representations of 1/3.
>
> You can explore on your own by using Clojure's "rationalize" function  
> (which as far as I can tell mirrors Common Lisp's RATIONAL function  
> rather than its RATIONALIZE function):
> (rationalize (float 1/3)) => 416666679084301/1250000000000000
> (rationalize (double 1/3)) => 3333333333333333/10000000000000000
>
> How close are these to the true values?
> (- (rationalize (float 1/3)) 1/3) => 37252903/3750000000000000
> (- 1/3 (rationalize (double 1/3))) => 1/30000000000000000
>
> So the single-precision representation is slightly more than 1/3,  
> which is why you see the terminal 4.
>
> Here's a little program to help you look inside 1/3. Just type  
> (dec2bin/display-one-third <PRECISION>) where <PRECISION> is either  
> float or double (you will need to widen your terminal window):
> (ns dec2bin
>    (:use clojure.contrib.math))
>
> (defn integer-to-binary [i]
>    (if (zero? i)
>      "0"
>      (loop [i i
>             result ""]
>        (if (zero? i)
>          (apply str result)
>          (recur (quot i 2)
>                 (if (zero? (rem i 2))
>                   (cons \0 result)
>                   (cons \1 result)))) )))
>
> (defn fraction-to-binary [x digits]
>    (loop [n digits
>           fraction x
>           result ""]
>      (if (zero? n)
>        (apply str (reverse result))
>        (let [whole (quot (* 2 fraction) 1)
>              fraction (rem (* 2 fraction) 1)]
>          (recur (dec n) fraction (cons (char (+ whole (int \0)))  
> result)))) ))
>
> (defn decimal-to-binary
>    ([x] (decimal-to-binary x 10))
>    ([x digits]
>       (let [whole (integer-to-binary (quot x 1))
>             fraction (fraction-to-binary (rem x 1) digits)]
>         (format "%s.%s" whole fraction))))
>
> (defn display-one-third [f]
>    (prn (format "%5s %-20s %-40s %s" "bits" "floating-point"  
> "fraction" "binary"))
>    (let [precision (if (= f float) 16 32)]
>      (dotimes [i precision]
>        (let [j (inc i)
>              sum (reduce + (map #(/ (expt 2 (* 2 %))) (range 1 (inc  
> j))))]
>          (prn (format "%5d %-20s %-40s %s" (* 2 j) (str (f sum)) (str  
> sum) (decimal-to-binary sum (* 2 j)))) ))))
>
>
>
> >  (=  (+ (float (* (/ 2) (/ 3))) (float (* (/ 2) (/ 3))) ) (/ 3) )
> > yields true
>
> You have to be very careful comparing floating-point numbers. While  
> the above discussion of 1/3 should not be surprising, many people do  
> get surprised when they look at other numbers in floating-point. A  
> perfect example is 0.1. In decimal, this looks like a "nice" fraction  
> that terminates after 1 decimal place. However, binary fractions are  
> not represented using powers of 10: 1/10, 1/100, 1/1000, etc. We have  
> to represent 0.1 in terms of: 1/2, 1/4, 1/8, etc. The binary  
> representation of 0.1 is:
> 0.00011001100110011001100110011001100110011001100110011...
> Again this is an infinite string represented in a finite amount of  
> memory, so 0.1 is not exact. That's why you get this behavior:
> (loop [i 1
>         x 0.1]
>    (prn (format "%d %s %s" i (str x) (str (* i 0.1))))
>    (when-not (= i 10)
>      (recur (inc i) (+ x 0.1))))
>
> "1 0.1 0.1"
> "2 0.2 0.2"
> "3 0.30000000000000004 0.30000000000000004"
> "4 0.4 0.4"
> "5 0.5 0.5"
> "6 0.6 0.6000000000000001"
> "7 0.7 0.7000000000000001"
> "8 0.7999999999999999 0.8"
> "9 0.8999999999999999 0.9"
> "10 0.9999999999999999 1.0"
>
> Apparently adding 0.1 6 times is different from 6 * 0.1:
> (rationalize 0.6) => 3/5
> (rationalize (* 6 0.1)) => 6000000000000001/10000000000000000
> (rationalize (+ 0.1 0.1 0.1 0.1 0.1 0.1)) => 3/5
>
> Even worse is the potential for infinite loops:
> (defn trap [x]
>    (prn x)
>    (cond (= x 1) "How nice. 10 * 0.1 = 1"
>          (> x 1) "Whoops. Good thing I had an escape hatch."
>          :else (trap (+ x 0.1))))
>
> (trap 0.1)
> 0.1
> 0.2
> 0.30000000000000004
> 0.4
> 0.5
> 0.6
> 0.7
> 0.7999999999999999
> 0.8999999999999999
> 0.9999999999999999
> 1.0999999999999999
> "Whoops. Good thing I had an escape hatch."
>
> If you've read this far you'll want to take a look at the links Mark  
> provided earlier.
>
> Aloha,
> David Sletten
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to