#564 √ invalid
Tomasz

dangerous float operations

Reported by Tomasz | July 7th, 2008 @ 03:10 PM | in 2.x

While implementing storage of price/cost/balance in cents I've stumbled upon one nasty bug. Consider the following code:

class Account < ActiveRecord::Base
def balance=(amount)
  write_attribute(:balance, amount.to_f*100.0)
end
end

(analogous accessor code omitted)

It works as expected... usually. That is, there's one magical number - 4.6 - which sets the field balance not to 460, but to 459, thus screwing up the whole purpose of this.

4.6 is the only magical number I could find - others work like charm and expected.

In Ruby (not on Rails) works as expected:

class Act
  def balance=(amount)
    @balance = amount.to_f*100
  end
end

that is, for 4.6 works like for all the other numbers.

EDIT: This problem seems to be related to to_i method called on floats. AND it seems to be Ruby-related

irb(main):005:0> (895.0).to_i
=> 895
irb(main):006:0> (8.95*100).to_i
=> 894

(yes, I've just discovered that to_i just cuts away everything after the point)

Workaround: add a tiny number to the converted one OR use .round

irb(main):007:0> (8.95*100 + 0.0000001).to_i
=> 895
irb(main):007:0> (8.95*100).round
=> 895

Proposed solution: make field accessors for integer fields use .round instead of to_i.

As for now, I'm good with adding .round in my custom accessor.

Comments and changes to this ticket

  • Tomasz

    Tomasz July 7th, 2008 @ 03:37 PM

    Update: 8.95 is also a "magical number" inside ActiveRecord, i.e. balance=8.95 sets balance field to 894. Other numbers "around" seem OK.

    >> a.balance=(8.95)
    => 8.95
    >> a.balance
    => 894
    >> a.balance=(8.93)
    => 8.93
    >> a.balance
    => 893
    
  • isak

    isak August 7th, 2008 @ 01:23 PM

    There is no bug, floating point numbers are inaccurate by design.

    The only reason people muck around with cents for money values is to avoid the floating point issue. This approach really hasn't been viable since 1.2, when ActiveRecord finally got support for decimal columns, but it seems like many pick it up from outdated tutorials floating around on the web.

  • Jim Lindley

    Jim Lindley August 9th, 2008 @ 09:58 PM

    Tomasz,

    There's more info on the details here, but isak is right - storage of floating point numbers in binary representation is less accurate then you'd think.

  • Frederick Cheung
  • Tomasz

    Tomasz August 10th, 2008 @ 04:32 PM

    I know, I know. We're using INT columnt because of that and convert numbers on-the-fly by overloading amount and amount= methods in our models. But I've just realised it's a bad approach and we should just represent them as ints also internally, doing the "conversion" only on the view level.

    Sorry for the hassle, You can close it as invalid/wontfix/reporter_incompetent ;)

  • Tarmo Tänav

    Tarmo Tänav September 18th, 2008 @ 05:53 AM

    • → Tag changed from “activerecord bug” to “activerecord bug”
    • → State changed from “new” to “invalid”

Please Login or create a free account to add a new comment.

You can update this ticket by sending an email to from your email client. (help)

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Source available from github

The Git repository resides at http://github.com/rails

Check out the current development trunk (Edge Rails) with:

git clone git://github.com/rails/rails.git

Creating or reviewing a patch

See the contributor guide.

Creating a feature request

Please don't. If you want a new feature in Rails, you'll have to pull up your sleeves and get busy yourself. Or convince someone else to do it. See the contributor guide on how to get going. But posting them here is just going to lead to ticket root.

Creating a bug report

When creating a bug report, be sure to include as much relevant information as possible. Post the code sample that causes the problem. Preferably, alter the unit tests and show through either changed or added tests how the expected behavior is not occuring.

Security vulnerabilities should be reported via an email to security@rubyonrails.org, do not use trac for reporting security vulnerabilities. All content in trac is publicly available as soon as it is posted.

Then don't get your hopes up. Unless you have a "Code Red, Mission Critical, The World is Coming to an End" kinda bug, you're creating this ticket in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the ticket automatically will see any activity or that others will jump to fix it. Creating a ticket like this is mostly to help yourself start on the path of fixing the problem and for others to sign on to with a "I'm having this problem too".

Shared Ticket Bins