You are here

PHP vs. BIGINT vs. float conversion caveat

MySQL Performance Blog - Thu, 10/01/2008 - 11:59pm

Sometimes you need to work with big numbers in PHP (gulp). For example, sometimes 32-bit identifiers are not enough and you have to use BIGINT 64-bit ids; e.g. if you are encoding additional information like the server ID into high bits of the ID.

I had already written about the mess that 64-bit integers are in PHP. But if the numbers you use do not cover 64-bit range fully, floats might save the day. The trick is that PHP floats are in fact doubles, i.e. double-precision 64-bit numbers. They have 52 bits for mantissa, and integer values up to 2^53-1 can be stored exactly. So if you're using up to 53 bits, you're OK with floats.

However, there's a conversion caveat you should be aware of.

On different systems, float is converted to string differently. (I spent a bit of time fighting with it today.) Consider the following script:

  1. <?php
  3. $f = 65536*65536*65536*4; // 2^52
  4. $f += 1; // 2^52+1
  5. $s1 = "$f"; // the usual way
  6. $s2 = sprintf ( "%.0f", $f ); // the "right" way
  7. print "s1=$s1 s2=$s2\n";
  9. ?>

It prints the following (normally expected) output on x64 box running Linux with PHP 5.1.6 or 5.2.2, and also with PHP 4.4.2 on SPARC64 under NetBSD 3.0:

  1. s1=1125899906842625 s2=1125899906842625

However 32-bit FreeBSD with PHP 4.4.7 produces different results:

  1. s1=1.1258999068426E+15 s2=1125899906842625

The same 32-bit FreeBSD box with PHP 5.2.5 starts to emit all digits but still incorrectly:

  1. s1=1125899906842600 s2=1125899906842625

And PHP 5.2.2 on Windows produces yet another variant:

  1. s1=1125899906840000 s2=1125899906842625

As you can see float to string conversion is not portable across systems and PHP versions. So if you're handling large numbers stored as float (especially on 32-bit systems where 32-bit int overflow will implicitly convert to float) and getting strange bugs, remember that string conversion might let you down. sprintf(), on the other hand, is always a friend when it comes to fixing PHP "subtleties" in numeric value handling: it can be used to workaround signed vs. unsigned int issues; it helps with float formatting; always a saviour.

Entry posted by shodan | 2 comments

Add to: delicious | digg | reddit | netscape | Google Bookmarks