23

I've been waffling on how to deal with currency display and math in PHP, and for a long time have been storing it in MySQL using the DECIMAL type, and using money_format() to format it for display on the web page. However, today I looked at the actual prototype:

string money_format ( string $format , float $number )

I'm a little confused now. All I've been told is, avoid floats for money! But here it is, the fundamental formatting function (say that five times fast), casting the input to a float. number_format() does the same.

So my questions are:

  1. Unless I'm dealing with fractional cents or trillions of dollars (and I'm dealing with neither), should I be concerned at all about displaying and storing (but never doing math on) currency that's been cast to a float? Will I ever come close to the area of having floating point inaccuracies change my figures?

  2. If the answer to #1 is that I should indeed be concerned, then why is money_format() built this way?

mskfisher
  • 3,291
  • 4
  • 35
  • 48
Andrew
  • 5,095
  • 6
  • 42
  • 48
  • 5
    Most of the int->float conversion danger comes from then doing math with those floats. `number_format()` is simply doing a "pretty print" type conversion, so any oddball repeating decimals created by the float-ification process are highly unlikely to affect the results. – Marc B Jan 11 '11 at 20:18
  • 20
    PHP is hardly the epitome of "best practices". – Gabe Jan 11 '11 at 20:24
  • 1
    @OP i just noticed you said _storing_. dont store money as floats ever please. use fixed precision of some sort. – time4tea Jan 11 '11 at 20:35
  • 1
    I don't, I store them in a MySQL `DECIMAL` field, which is not a float field. My consideration was, let's say I have $i, and cast it to float (via manual casting or the output from `number_format()` or what not), and then store it in the database. It will be _stored_ as a `DECIMAL`, so I'm not worried about that, so my statement was a little weird, I admit. I was more concerned about what changes might have been made to it by casting it to a float on its way around the system. That is to say, I get it out, I cast it as float, I store it back... will it be different? – Andrew Jan 11 '11 at 20:51
  • 1
    [Why not use Double or Float to represent currency?](http://stackoverflow.com/q/3730019/995714) – phuclv Jul 28 '16 at 03:39

1 Answers1

26

Unless I'm dealing with fractional cents or trillions of dollars (and I'm dealing with neither), should I be concerned at all about displaying and storing (but never doing math on) currency that's been cast to a float? Will I ever come close to the area of having floating point inaccuracies change my figures?

For pure rounding/display purposes, you're safe as long as the absolute floating-point representation error is less than $0.005 (so that rounding to the nearest cent is correct).

With IEEE 754 single-precision, you're safe up to $131,072.00. ($131,072.01 is represented as 131072.015625, which incorrectly rounds up.)

Double precision (which PHP's float uses) doesn't fail until $70,368,744,177,664.01 (which also has .015625 for the cents). You have nothing to worry about.

If the answer to #1 is that I should indeed be concerned, then why is money_format() built this way?

What type should it take? PHP doesn't have a built-in decimal type. Nor do many other languages.

yivi
  • 42,438
  • 18
  • 116
  • 138
dan04
  • 87,747
  • 23
  • 163
  • 198
  • String sounds like as good an idea as any. Though it's starting to sound more and more like, for purely representational issues and not math, I should be perfectly comfortable with a float. Accepted because it allayed my fears, and +1ed for the educational link. :) – Andrew Jan 12 '11 at 19:56
  • 2
    You say "Doesn't fail until ..." but what about things like compounded interest? Small errors can add up. – rjmunro Jul 09 '13 at 10:32
  • 1
    The OP asked about displaying and storing, not math. – dan04 Jul 12 '13 at 02:15
  • The link is missing. – Nick Mar 31 '17 at 04:38
  • @Nick: The question was removed as “off-topic”. You can still see it if you have a sufficiently-high number of reputation points. – dan04 Mar 31 '17 at 13:50