# Arithmetic oddity

**URL:** <https://www.ruby-forum.com/t/arithmetic-oddity/141994>\
**Category:** Ruby\
**Created:** [July 2, 2008, 1:33pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994 "2008-07-02T13:33:13Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![kookymind](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/3ab097/32.png) [@kookymind](https://www.ruby-forum.com/u/kookymind)\
**Post date:** [July 2, 2008, 1:33pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994/1 "2008-07-02T13:33:13Z")

</div>

> > l = [1.0, 1.0, 2.0\*\*0.5]  
> > =\> [1.0, 1.0, 1.4142135623731]
> 
> > s = l.map {|e| e\*\*2}  
> > =\> [1.0, 1.0, 2.0]
> 
> > puts ‘foo’ if s[2] == s[1] + s[0]  
> > =\> nil
> 
> > puts ‘foo’ if 2.0 == 1.0 + 1.0  
> > foo  
> > =\> nil

Does anyone know why s[2] == s[1] + s[0] is false ?

---

<div class="post-metadata">

**Author:** ![kookymind](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/3ab097/32.png) [@kookymind](https://www.ruby-forum.com/u/kookymind)\
**Post date:** [July 2, 2008, 2:08pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994/2 "2008-07-02T14:08:57Z")

</div>

On 2 Jul 2008, at 12:30, Minh T. wrote:

> Does anyone know why s[2] == s[1] + s[0] is false ?  
> If you check in IRB you’ll find that ((2.0 \*\* 0.5) \*\* 2.0) == 2.0  
> returns false. That will be due to rounding errors in performing the  
> sequence of floating point operations.

Ellie

## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)

raise ArgumentError unless @reality.responds\_to? :reason

---

<div class="post-metadata">

**Author:** ![kookymind](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/3ab097/32.png) [@kookymind](https://www.ruby-forum.com/u/kookymind)\
**Post date:** [July 2, 2008, 2:51pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994/3 "2008-07-02T14:51:31Z")

</div>

It still look odd as the value in s[2] is 2.0 which doesn’t seems to  
have any rounding problem.

In any case is there any workaround to fix get the condition as true ?

Eleanor McHugh wrote:

> On 2 Jul 2008, at 12:30, Minh T. wrote:
> 
> > Does anyone know why s[2] == s[1] + s[0] is false ?  
> > If you check in IRB you’ll find that ((2.0 \*\* 0.5) \*\* 2.0) == 2.0  
> > returns false. That will be due to rounding errors in performing the  
> > sequence of floating point operations.
> 
> Ellie
> 
> ## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)
> 
> raise ArgumentError unless @reality.responds\_to? :reason

---

<div class="post-metadata">

**Author:** ![kookymind](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/3ab097/32.png) [@kookymind](https://www.ruby-forum.com/u/kookymind)\
**Post date:** [July 2, 2008, 3:16pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994/4 "2008-07-02T15:16:21Z")

</div>

On 2 Jul 2008, at 13:48, Minh T. wrote:

> It still look odd as the value in s[2] is 2.0 which doesn’t seems to  
> have any rounding problem.
> 
> In any case is there any workaround to fix get the condition as true ?

Floating point representations are in many cases (such as irrational  
numbers like square root of 2) only approximations to a given value,  
you therefore have to test that the value is accurate to a given  
precision (number of significant digits). For example, given:

x = (1.0 + 1.0) \*\* 0.5

you could write your test as:

(x \*\* 2.0).between?(1.9999, 2.0001)

Ellie

## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)

raise ArgumentError unless @reality.responds\_to? :reason

---

<div class="post-metadata">

**Author:** ![kookymind](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/3ab097/32.png) [@kookymind](https://www.ruby-forum.com/u/kookymind)\
**Post date:** [July 2, 2008, 4:02pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994/5 "2008-07-02T16:02:43Z")

</div>

On 2 Jul 2008, at 14:25, Minh T. wrote:

> It doesn’t look very elegant though to need such kind of hacking to  
> make  
> it base operator to work as expected.

And that method also imposes considerable runtime cost. As I said, use  
a comparison such as (2.0).between?(1.99999, 2.00001) as that’s:

a. computationally much less expensive;  
b. what a floating-point ‘==’ actually means.

Also you should probably read

> **[Floating-point arithmetic](https://en.wikipedia.org/wiki/Floating_point)**
>
> In computing, floating-point arithmetic (FP) is arithmetic that represents a subset of real numbers using an integer with a fixed precision, called the significand, scaled by an integer exponent of a fixed base.
> Numbers of this form are called floating-point numbers.: 3 : 10 
> For example, 12.345 is a floating-point number in a base-ten representation with five digits of precision:
> However, 12.3456 is not a floating-point number with five base-ten digits of precision.
> In practice, most floatin...

and then do some further research into floating point number  
representations to gain some deeper insight into what is actually  
meant by 2.0 when it’s converted into binary format. It may inspire  
you to more elegant ways of solving whatever problem it is that you’re  
working on.

Ellie

## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)

raise ArgumentError unless @reality.responds\_to? :reason

---

<div class="post-metadata">

**Author:** ![kookymind](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/3ab097/32.png) [@kookymind](https://www.ruby-forum.com/u/kookymind)\
**Post date:** [July 2, 2008, 4:05pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994/6 "2008-07-02T16:05:39Z")

</div>

2008/7/2 Minh T. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> I tried with
> 
> s = l.map {|e| (e\*\*2).to\_s.to\_f}
> 
> instead of
> 
> s = l.map {|e| e\*\*2}
> 
> and it now works.

But it works only accidentally! This is likely to break soon again.

> It doesn’t look very elegant though to need such kind of hacking to make  
> it base operator to work as expected.

No, no, no! The operator works as expected. There is even an IEEE  
standard defining how floating point math has to behave. You must  
_never_ rely on == when doing float math. In this case you rather  
need to do either of these

- resort to decimal math with BigDecimal

- define equality as a max difference (“epsilon”) between two float  
values and test that

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![kookymind](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/3ab097/32.png) [@kookymind](https://www.ruby-forum.com/u/kookymind)\
**Post date:** [July 2, 2008, 4:09pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994/7 "2008-07-02T16:09:45Z")

</div>

On 2 Jul 2008, at 15:01, Robert K. wrote:

> - resort to decimal math with BigDecimal
> 
> - define equality as a max difference (“epsilon”) between two float  
> values and test that

Phrased much better than my replies 🙂

Ellie

## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)

raise ArgumentError unless @reality.responds\_to? :reason

---

<div class="post-metadata">

**Author:** ![kookymind](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/3ab097/32.png) [@kookymind](https://www.ruby-forum.com/u/kookymind)\
**Post date:** [July 2, 2008, 3:28pm UTC](https://www.ruby-forum.com/t/arithmetic-oddity/141994/8 "2008-07-02T15:28:28Z")

</div>

I tried with

s = l.map {|e| (e\*\*2).to\_s.to\_f}

instead of

s = l.map {|e| e\*\*2}

and it now works.

It doesn’t look very elegant though to need such kind of hacking to make  
it base operator to work as expected.

Eleanor McHugh wrote:

> On 2 Jul 2008, at 13:48, Minh T. wrote:
> 
> > It still look odd as the value in s[2] is 2.0 which doesn’t seems to  
> > have any rounding problem.
> > 
> > In any case is there any workaround to fix get the condition as true ?
> 
> Floating point representations are in many cases (such as irrational  
> numbers like square root of 2) only approximations to a given value,  
> you therefore have to test that the value is accurate to a given  
> precision (number of significant digits). For example, given:
> 
> x = (1.0 + 1.0) \*\* 0.5
> 
> you could write your test as:
> 
> (x \*\* 2.0).between?(1.9999, 2.0001)
> 
> Ellie
> 
> ## Eleanor McHugh Games With Brains [http://slides.games-with-brains.net](http://slides.games-with-brains.net)
> 
> raise ArgumentError unless @reality.responds\_to? :reason
