I keep running into this type of problem:
user=> (- 12.305 12.3049)
9.999999999976694E-5
Have all good days,
David Sletten
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
Comparison is semi-decidable only: it terminates only in certain case
(finite number of decimals)
or when the number are different.
big-decimal or fractions are a good approximation, though.
and again it does exactly what it promises to do:
epsilon is maybe wrong-named here because it is not absolute value, but
amount of significant figures. it is multiplied by x to get precision. so
what you are asking is
|12.3049 - 12.305| <= 12.3049 * 0.00001 which holds true
The number that you are typing as 12.305 is actually being stored in the computer as this:
1100.0100111000010100011110101110000101000111101011100
This number is actually this fraction:
1731774794212311/140737488355328
So here is the true value in decimal:
12.304999999999999715782905695959
It is not possible to represent 12.305 any closer than that on conventional hardware.
Likewise your 12.3049 is this:
1100.0100111000001101111011010010100010001100111001110
Which is this fraction:
3463521440926951/281474976710656
Or in decimal:
12.304899999999999948840923025272
This is the best approximation for 12.3049.
When you scale epsilon (0.00001) by about 12, you can see that these two numbers are "equal" as expected in the sense defined by float=.
Have all good days,
David Sletten
Then you can't use floats.
As others have explained, floats are imprecise by nature, being
limited to finite binary fractions. To make matters worse, you don't
input the numbers in binary, but in decimal, which means most of the
fractions you can input can't be represented as a float - so you get
an approximation. Given that the numbers are "fuzzy", the concept of
equality also becomes "fuzzy" - whether two numbers are equal will
depend on the context. So you have to choose the equality that's
appropriate for the context.
If you want precise numbers, Clojure has three options:
1) If you can represent everything as integers, then BigInteger is
probably the easiest to use, with the obvious drawback that it can't
handle fractional values, nor can it represent as large a value as a
float since you run out of memory. Letting units represent 1/1000's:
user> (- 123050 123049)
1
2) If you're going to stay in the world of decimal fractions, use
BigDecimal. This has some of the problems of floats, but between
allowing arbitrary precision and the input representation matching the
internal representation, they're not nearly as obnoxious.
user> (- 12.305M 12.3049M)
0.0001M
3) Clojure's rationals let you represent all rational values, until
you run out of memory. If you want a decimal approximation after the
calculation is done, that's easy to get as well:
user> (- 12305/1000 123049/10000)
1/10000
user> (float (- 12305/1000 123049/10000))
1.0E-4
<mike
--
Mike Meyer <m...@mired.org> http://www.mired.org/consulting.html
Independent Network/Unix/Perforce consultant, email for more information.
O< ascii ribbon campaign - stop html mail - www.asciiribbon.org
The more that I think about it, the more I would rather have a set of
equalities that always work. float= was a good try.
> On Tue, Oct 12, 2010 at 3:35 PM, cej38 <junke...@gmail.com> wrote:
>
> > The more that I think about it, the more I would rather have a set of
> > equalities that always work. float= was a good try.
> <RANT>
Maybe initially, but not later on...
> Floating point is not broken.
> </RANT>
Well, no more broken than any other representation of numbers on the
computer. All of them have problems of one sort or another. For
almost any problem you're going to solve with a computer, picking the
right representation for your data is a crucial step!
While you may understand the mathematics of numbers quite well, no
computerized representation will give you that behavior (even integers
are usually weird, either having a number which has no additive
inverse, or having two zeros). You can expect every mathematical
entity to have this problem: pretty much every computer representation
will not have some property or properties of the original, so you have
to figure out which properties you really care about, and pick the
representation that has those properties.
That picking the right representation of numbers is a crucial step may
be surprising, but it's still true. Most languages have settled on the
same set of choices (in order of decreasing use): integers, either
with or without size limits; floats; decimals, either with or without
explicit lengths; and rationals. You can expect that most problems can
be dealt with adequately by one of these. If not - well, there are
lots of other choices out there that you can play with as well.
The only way to do so is to have numbers with infinite precision.
For example as lazy-seq of their digits.
But:
- it is slow
- equality is semi-decidable only.
> For example, in base 10, 1/3 * 3 = 0.99999...
It may seem counterintuitive, but that statement is perfectly true.
1 = 0.9999...
That's a good test of how well you understand infinity.
Of course, the problem arises when we truncate the string of 9's, which we must invariably do in a computer-based representation.
I'm clearly not a mathematician, but doesn't 0.99999... asymptotically
approach 1, i.e. never reaching it? How is that the same as 1?
This representation implies the sum of the series (iterate #(/ % 10)
9/10), and that sum behaves as you say. However, since the series is
infinite, you can prove that the number it represents is actually
equal to one, like so:
1) a = 0.999... # define a as 0.999...
2) 10a = 9.999... # multiply both sides by 10
3) 10a - a = 9.999... - 0.999... # subtract equation 1 from equation 2
4) 9a = 9 # simplify
5) a = 1 # divide both sides by 9.
The subtraction step doesn't work unless the sequence is infinite, if
a is any finite sequence of 9s, you'll get a number whose decimal
representation is matches the re 8\.(9)*1. This relies on the property
that adding 1 to an infinite number gives you back the same infinite
number, so that:
(= (rest (map #(* % 10) (iterate #(/ % 10) 9/10)))
(iterate #(/ % 10) 9/10))
is true, but I don't recommend typing that into a repl to check it!
Hmm. I wonder if you could represent irrationals as lazy sequences,
and do arithmetic on those?
1/3 = .333333...
2/3 = .666666...
3/3 = .999999...
Think of 3/3 as 1/3 (that is .33333...) times 3.
-Terrance Davis
www.terrancedavis.com
>> For any two real numbers /a/ and /b/ there exists an infinite number
>> of real numbers /c /such that /a < c < b/. However, there do not
>> exist any numbers between 0.99999... and 1, thus they must be same number.
>>
>> As it turns out, it took mathematicians a long time to nail down
>> formally exactly what we naively think of as "numbers".
>>
>> Matt
>>
>> On Wed, Oct 13, 2010 at 6:27 PM, Felix H. Dahlke <f...@ubercode.de
>> <mailto:f...@ubercode.de>> wrote:
>>
>> On 13/10/10 22:28, David Sletten wrote:
>> >
>> > On Oct 12, 2010, at 5:44 PM, Brian Hurt wrote:
>> >
>> >> For example, in base 10, 1/3 * 3 = 0.99999...
>> >
>> > It may seem counterintuitive, but that statement is perfectly true.
>> > 1 = 0.9999...
>> >
>> > That's a good test of how well you understand infinity.
>>
>> I'm clearly not a mathematician, but doesn't 0.99999... asymptotically
>> approach 1, i.e. never reaching it? How is that the same as 1?
>>
>>
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clo...@googlegroups.com
>> <mailto:clo...@googlegroups.com>
>> Note that posts from new members are moderated - please be patient
>> with your first post.
>> To unsubscribe from this group, send email to
>> clojure+u...@googlegroups.com
>> <mailto:clojure+u...@googlegroups.com>
Let study the sequence sn = 0.9999...9 , with n 9s.
Or s0= 0 and s(n+1) = sn + 9 / 10 ^n
lim sn = 0.99999.......
and lim sn = 1.
so ....
If I remember my meth correctly,
the number 0.9999...... does not exist.
This not a legal decimal sequence.
(Any decimal sequence finishing by 9999...... is forbidden to allow a
one to one mapping between real numbers and
decimal sequence.)
This kind of infinity is one of the reason equality is not devidable
on real numbers.
You can manipulate square root directly. For example by defining
numbers as a map from ratio to ratio.sqr
sqrt(5) is represented by {5 1}
sqrt(5) + 3. sqrt(2) by {5 1 , 2 3}
15 + sqrt(3) ----> {1 15, 3 1}
adding is just a reduce of one map into the other.
neg is a map.
multiplying is more complex. For each two pairs in the map
[a b] [c d], you check wether (ac) can be written as sqr(e).f
(For example 2 * 6 can be written as sqr(2)*3)
If it is the case, you return [f (* e b d)]
else you return [(* a c) (* b d)]
Dividing is more difficult.
I don't know if it is the most efficien way to do that, but it is the
easiest to code.
Best,
Nicolas.
I am kinda sorry that I started this whole thing. I don't need
another lesson in limits. The simple fact of the matter is that, in
my code, I run into a place where I have a comparison (= some-value
(some-function some-data)), the function, data, and value can change.
In a use case that I am interested in, I run into the problem stated,
user=> (= 0.0001 (- 12.305 12.3049))
false
I am OK with replacing the = function with something like float=
discussed above, but whatever I change it two needs to work. If
anyone has found a way, that reliably works, please post it here.
Further, <, >, <=, and >= would also be appreciated. Thank you.
> I am kinda sorry that I started this whole thing. I don't need
> another lesson in limits. The simple fact of the matter is that, in
> my code, I run into a place where I have a comparison (= some-value
> (some-function some-data)), the function, data, and value can change.
> In a use case that I am interested in, I run into the problem stated,
>
> user=> (= 0.0001 (- 12.305 12.3049))
> false
>
> I am OK with replacing the = function with something like float=
> discussed above, but whatever I change it two needs to work. If
> anyone has found a way, that reliably works, please post it here.
> Further, <, >, <=, and >= would also be appreciated. Thank you.
>
>
If you define 2 of them, then you get the rest for free. We already have float=:
(defn float=
([x y] (float= x y 0.00001))
([x y epsilon]
(let [scale (if (or (zero? x) (zero? y)) 1 (Math/abs x))]
(<= (Math/abs (- x y)) (* scale epsilon)))) )
If x < y, then in our case x should be more than epsilon below y:
(defn float<
([x y] (float< x y 0.00001))
([x y epsilon]
(let [scale (if (or (zero? x) (zero? y)) 1 (Math/abs x))]
(< x (- y (* scale epsilon)))) ))
(defn float<=
([x y] (or (float< x y) (float= x y)))
([x y epsilon] (or (float< x y epsilon) (float= x y epsilon))))
(defn float>
([x y] (not (float<= x y)))
([x y epsilon] (not (float<= x y epsilon))))
(defn float>=
([x y] (or (float> x y) (float= x y)))
([x y epsilon] (or (float> x y epsilon) (float= x y epsilon))))
Then you determine how strict epsilon needs to be:
(float< 12.3049 12.305) => false
(float< 12.3049 12.305 1e-6) => true
(float<= 12.305 12.3049) => true
(float<= 12.305 12.3049 1e-6) => false
(float> 12.305 12.3049 1e-6) => true
> (defn float=
> ([x y] (float= x y 0.00001))
> ([x y epsilon]
> (let [scale (if (or (zero? x) (zero? y)) 1 (Math/abs x))]
> (<= (Math/abs (- x y)) (* scale epsilon)))) )
You're scaling epsilon incorrectly here. Epsilon defines the smallest
value that yields a value greater than one when added to one. If you're
not using it along with one, you're using it incorrectly.
What you need to do is scale epsilon by having its exponent match the
value with which you want to use it, while maintaining its mantissa. The
C library offers functions ldexp()¹ and frexp()² to split and scale the
exponent of a floating point number, respectively; Common Lisp offers
DECODE-FLOAT³ and SCALE-FLOAT for the same purpose.
I don't know of any standard functions in Java -- or Clojure -- that
allow one to destructure a floating point number like this. It's
possible to use Float#floatToRawIntBits(), an understanding of IEEE 754,
and tweezers to get there.
If you assume you have a function called `scaled-epsilon' that accepts
the exemplar value with which you intend to use epsilon,
(defn scaled-epsilon [n] ...)
you can use the following function `same?' to compare your floating
point values, assuming they're nonnegative:
,----
| (defn same?
| [m n]
| (if (< n m)
| (sufficiently-close? n m)
| (sufficiently-close? m n)))
|
| (defn- sufficiently-close?
| [smaller larger]
| (or (zero? larger)
| (if (zero? smaller)
| (< larger (scaled-epsilon 0.0)))
| (zero? (- 1 (/ smaller larger)))))
`----
Note too that scaling epsilon must take into account whether you intend
to add it or subtract it from some companion number. It's common to use
the word "epsilon" to mean some fudge factor without considering what
the value really means for a floating point number. Indeed, using it
properly in Java is still too difficult.
Footnotes:
¹ http://www.dinkumware.com/manuals/?manual=compleat&page=math.html#frexp
² http://www.dinkumware.com/manuals/?manual=compleat&page=math.html#ldexp
³ http://www.lispworks.com/documentation/HyperSpec/Body/f_dec_fl.htm#decode-float
http://www.lispworks.com/documentation/HyperSpec/Body/f_dec_fl.htm#scale-float
--
Steven E. Harris
public static boolean compareDoubles(double tolerance, double d1, double d2) {
// handle 0.0 specifically, as it will screw with our division
// catch overflow cases, we will divide by d1 which could increase the value of d2
if ((d1abs < 1.0) && (d2abs > d1abs*Double.MAX_VALUE)) { return false; }
// and very small numbers cleanly with a single tolerance