# Is this a bug?

**URL:** <https://www.ruby-forum.com/t/is-this-a-bug/195275>\
**Category:** Ruby\
**Created:** [September 20, 2010, 11:38pm UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275 "2010-09-20T23:38:06Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![gjenkins](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/6f9a4e/32.png) [@gjenkins](https://www.ruby-forum.com/u/gjenkins)\
**Post date:** [September 20, 2010, 11:38pm UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275/1 "2010-09-20T23:38:06Z")

</div>

for following version:  
ruby 1.9.1p129 (2009-05-12 revision 23412) [i386-darwin9.7.0]

irb(main):002:0\> sprintf("%.1f",-1.05)  
=\> “-1.1”  
irb(main):003:0\> sprintf("%.1f",-32.05)  
=\> “-32.0”

note the inconsistent rounding.

-1.05 rounds to -1.1  
and  
-32.50 rounds to -32.0

from sprintf

---

<div class="post-metadata">

**Author:** ![gjenkins](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/6f9a4e/32.png) [@gjenkins](https://www.ruby-forum.com/u/gjenkins)\
**Post date:** [September 20, 2010, 11:50pm UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275/2 "2010-09-20T23:50:47Z")

</div>

> note the inconsistent rounding.
> 
> -1.05 rounds to -1.1  
> and  
> -32.50 rounds to -32.0
> 
> from Â sprintf

For me it looks like you are rounding -32.05, not -32.50.

> irb(main):003:0\> sprintf("%.1f",-32.05)

Regards, Rimantas

---

<div class="post-metadata">

**Author:** ![gjenkins](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/6f9a4e/32.png) [@gjenkins](https://www.ruby-forum.com/u/gjenkins)\
**Post date:** [September 20, 2010, 11:53pm UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275/3 "2010-09-20T23:53:19Z")

</div>

Rimantas L. wrote:

> > note the inconsistent rounding.
> > 
> > -1.05 rounds to -1.1  
> > and  
> > -32.50 rounds to -32.0
> > 
> > from Â sprintf
> 
> For me it looks like you are rounding -32.05, not -32.50.
> 
> > irb(main):003:0\> sprintf("%.1f",-32.05)
> 
> Regards, Rimantas

Yes, I intend to round -32.05 to the nearest 1 decimal place not to a  
whole number. sprintf is suppose to round to the precision you specify.

---

<div class="post-metadata">

**Author:** ![gjenkins](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/6f9a4e/32.png) [@gjenkins](https://www.ruby-forum.com/u/gjenkins)\
**Post date:** [September 21, 2010, 12:00am UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275/4 "2010-09-21T00:00:00Z")

</div>

Gerry Jenkins wrote:

> Gerry Jenkins wrote:
> 
> > Rimantas L. wrote:
> > 
> > > > note the inconsistent rounding.
> > > > 
> > > > -1.05 rounds to -1.1  
> > > > and  
> > > > -32.50 rounds to -32.0
> > > > 
> > > > from Â sprintf
> > > 
> > > For me it looks like you are rounding -32.05, not -32.50.
> > > 
> > > > irb(main):003:0\> sprintf("%.1f",-32.05)
> > > 
> > > Regards, Rimantas
> > 
> > Yes, I intend to round -32.05 to the nearest 1 decimal place not to a  
> > whole number. sprintf is suppose to round to the precision you specify.
> 
> OK also inconsistent:
> 
> irb(main):007:0\> sprintf("%.0f",-1.5)  
> =\> “-2”  
> irb(main):008:0\> sprintf("%.0f",-10.5)  
> =\> “-10”
> 
> -1.5 rounds down to -2  
> -10.5 rounds up to -10

fails even positive numbers:

sprintf("%.0f",10.5)  
=\> “10”

irb(main):013:0\> sprintf("%.0f",11.5)  
=\> “12”

---

<div class="post-metadata">

**Author:** ![gjenkins](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/6f9a4e/32.png) [@gjenkins](https://www.ruby-forum.com/u/gjenkins)\
**Post date:** [September 20, 2010, 11:58pm UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275/5 "2010-09-20T23:58:10Z")

</div>

Gerry Jenkins wrote:

> Rimantas L. wrote:
> 
> > > note the inconsistent rounding.
> > > 
> > > -1.05 rounds to -1.1  
> > > and  
> > > -32.50 rounds to -32.0
> > > 
> > > from Â sprintf
> > 
> > For me it looks like you are rounding -32.05, not -32.50.
> > 
> > > irb(main):003:0\> sprintf("%.1f",-32.05)
> > 
> > Regards, Rimantas
> 
> Yes, I intend to round -32.05 to the nearest 1 decimal place not to a  
> whole number. sprintf is suppose to round to the precision you specify.

OK also inconsistent:

irb(main):007:0\> sprintf("%.0f",-1.5)  
=\> “-2”  
irb(main):008:0\> sprintf("%.0f",-10.5)  
=\> “-10”

-1.5 rounds down to -2  
-10.5 rounds up to -10

---

<div class="post-metadata">

**Author:** ![gjenkins](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/6f9a4e/32.png) [@gjenkins](https://www.ruby-forum.com/u/gjenkins)\
**Post date:** [September 21, 2010, 12:32am UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275/6 "2010-09-21T00:32:56Z")

</div>

On Sep 20, 2010, at 18:00 , Gerry Jenkins wrote:

> fails even positive numbers:
> 
> sprintf(“%.0f”,10.5)  
> =\> “10”
> 
> irb(main):013:0\> sprintf(“%.0f”,11.5)  
> =\> “12”

> **[Floating-point arithmetic |](https://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding)**
>
> By their nature, all numbers expressed in floating-point format are rational numbers with a terminating expansion in the relevant base (for example, a terminating decimal expansion in base-10, or a terminating binary expansion in base-2). Irrational numbers, such as π or √2, or non-terminating rational numbers, must be approximated. The number of digits (or bits) of precision also limits the set of rational numbers that can be represented exactly. For example, the decimal number 123456789 cannot ...

“Rounding is used when the exact result of a floating-point operation  
(or a conversion to floating-point format) would need more digits than  
there are digits in the significand. There are several different  
rounding schemes (or rounding modes). Historically, truncation was the  
typical approach. Since the introduction of IEEE 754, the default method  
(round to nearest, ties to even, sometimes called Banker’s Rounding) is  
more commonly used.”

As for the original issue, how numbers ending in 0.05 are rounded for  
display with 1 digit after the decimal:

It does seem “inconsistent”, but it isn’t wrong. Both 32.1 and 32.0 are  
equally distant from 32.05. Internally, floating point numbers are  
represented as binary digits, so 32.05 isn’t _exactly_ 32.05, but the  
closest value that can be represented in binary, which will be ever so  
slightly higher or lower.

Try looking at the numbers with more decimal points and you’ll see what  
I mean:

irb(main):043:0\> sprintf(“%.1f”,-29.05)  
=\> “-29.1”  
irb(main):044:0\> sprintf(“%.1f”,-30.05)  
=\> “-30.1”  
irb(main):045:0\> sprintf(“%.1f”,-31.05)  
=\> “-31.1”  
irb(main):046:0\> sprintf(“%.1f”,-32.05)  
=\> “-32.0”  
irb(main):047:0\> sprintf(“%.1f”,-33.05)  
=\> “-33.0”  
irb(main):048:0\> sprintf(“%.1f”,-34.05)  
=\> “-34.0”  
irb(main):049:0\> sprintf(“%.20f”,-29.05)  
=\> “-29.05000000000000071054”  
irb(main):050:0\> sprintf(“%.20f”,-30.05)  
=\> “-30.05000000000000071054”  
irb(main):051:0\> sprintf(“%.20f”,-31.05)  
=\> “-31.05000000000000071054”  
irb(main):052:0\> sprintf(“%.20f”,-32.05)  
=\> “-32.04999999999999715783”  
irb(main):053:0\> sprintf(“%.20f”,-33.05)  
=\> “-33.04999999999999715783”  
irb(main):054:0\> sprintf(“%.20f”,-34.05)  
=\> “-34.04999999999999715783”

So what it’s rounding isn’t the exact number you’re typing in, but the  
internal representation of that number in binary floating point format.

There are ways of tweaking the math so that the rounding seems more  
consistent, but no matter what, the values you enter won’t be precisely  
equal to that value when you’re using floating point numbers.

If you’re not careful about rounding floating point digits, you can end  
up with something like this:

[![](https://img.thedailywtf.com/images/200902/errord/DSC00669.JPG) ](https://img.thedailywtf.com/images/200902/errord/DSC00669.JPG)

Ben

---

<div class="post-metadata">

**Author:** ![gjenkins](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/6f9a4e/32.png) [@gjenkins](https://www.ruby-forum.com/u/gjenkins)\
**Post date:** [September 21, 2010, 12:39am UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275/7 "2010-09-21T00:39:25Z")

</div>

Thank you Ben,

I did discover that there are various ways of rounding just before your  
reply at [Rounding - Wikipedia](http://en.wikipedia.org/wiki/Rounding)

I am writing a ruby web based unit testing for my java students to  
submit their programs to.

My real problem is that sprintf in ruby behaves differently in this  
regard to how java rounds.

Oh well, I fixed it by creating unit test data that was within the  
precision of the final java output, so that rounding was not used in the  
unit testing.

Ben G. wrote:

> On Sep 20, 2010, at 18:00 , Gerry Jenkins wrote:
> 
> > fails even positive numbers:
> > 
> > sprintf(“%.0f”,10.5)  
> > =\> “10”
> > 
> > irb(main):013:0\> sprintf(“%.0f”,11.5)  
> > =\> “12”
> 
> [Floating-point arithmetic - Wikipedia](http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding)
> 
> “Rounding is used when the exact result of a floating-point operation  
> (or a conversion to floating-point format) would need more digits than  
> there are digits in the significand. There are several different  
> rounding schemes (or rounding modes). Historically, truncation was the  
> typical approach. Since the introduction of IEEE 754, the default method  
> (round to nearest, ties to even, sometimes called Banker’s Rounding) is  
> more commonly used.”
> 
> As for the original issue, how numbers ending in 0.05 are rounded for  
> display with 1 digit after the decimal:
> 
> It does seem “inconsistent”, but it isn’t wrong. Both 32.1 and 32.0 are  
> equally distant from 32.05. Internally, floating point numbers are  
> represented as binary digits, so 32.05 isn’t _exactly_ 32.05, but the  
> closest value that can be represented in binary, which will be ever so  
> slightly higher or lower.
> 
> Try looking at the numbers with more decimal points and you’ll see what  
> I mean:
> 
> irb(main):043:0\> sprintf(“%.1f”,-29.05)  
> =\> “-29.1”  
> irb(main):044:0\> sprintf(“%.1f”,-30.05)  
> =\> “-30.1”  
> irb(main):045:0\> sprintf(“%.1f”,-31.05)  
> =\> “-31.1”  
> irb(main):046:0\> sprintf(“%.1f”,-32.05)  
> =\> “-32.0”  
> irb(main):047:0\> sprintf(“%.1f”,-33.05)  
> =\> “-33.0”  
> irb(main):048:0\> sprintf(“%.1f”,-34.05)  
> =\> “-34.0”  
> irb(main):049:0\> sprintf(“%.20f”,-29.05)  
> =\> “-29.05000000000000071054”  
> irb(main):050:0\> sprintf(“%.20f”,-30.05)  
> =\> “-30.05000000000000071054”  
> irb(main):051:0\> sprintf(“%.20f”,-31.05)  
> =\> “-31.05000000000000071054”  
> irb(main):052:0\> sprintf(“%.20f”,-32.05)  
> =\> “-32.04999999999999715783”  
> irb(main):053:0\> sprintf(“%.20f”,-33.05)  
> =\> “-33.04999999999999715783”  
> irb(main):054:0\> sprintf(“%.20f”,-34.05)  
> =\> “-34.04999999999999715783”
> 
> So what it’s rounding isn’t the exact number you’re typing in, but the  
> internal representation of that number in binary floating point format.
> 
> There are ways of tweaking the math so that the rounding seems more  
> consistent, but no matter what, the values you enter won’t be precisely  
> equal to that value when you’re using floating point numbers.
> 
> If you’re not careful about rounding floating point digits, you can end  
> up with something like this:
> 
> [http://img.thedailywtf.com/images/200902/errord/DSC00669.JPG](http://img.thedailywtf.com/images/200902/errord/DSC00669.JPG)
> 
> Ben

---

<div class="post-metadata">

**Author:** ![gjenkins](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/6f9a4e/32.png) [@gjenkins](https://www.ruby-forum.com/u/gjenkins)\
**Post date:** [September 21, 2010, 8:39am UTC](https://www.ruby-forum.com/t/is-this-a-bug/195275/8 "2010-09-21T08:39:16Z")

</div>

On 21.09.2010 00:39, Gerry Jenkins wrote:

> I did discover that there are various ways of rounding just before your  
> reply at [Rounding - Wikipedia](http://en.wikipedia.org/wiki/Rounding)
> 
> I am writing a ruby web based unit testing for my java students to  
> submit their programs to.
> 
> My real problem is that sprintf in ruby behaves differently in this  
> regard to how java rounds.

Since you are coming from a Java background I guess you are aware that  
JUnit’s TestCase uses a delta for equals comparisons of float and  
double:

[http://www.junit.org/junit/javadoc/3.8.1/junit/framework/Assert.html](http://www.junit.org/junit/javadoc/3.8.1/junit/framework/Assert.html)

> Oh well, I fixed it by creating unit test data that was within the  
> precision of the final java output, so that rounding was not used in the  
> unit testing.

The proper solution IMHO would be a comparison of numeric values (i.e.  
not of strings) that takes the delta into account much the same way as  
it’s done in JUnit because there is also named mismatch between the  
binary internal representation and the decimal external representation  
that we humans love to use.

Cheers

robert
