0

I ve got a strange php behaviour with floating value

$array_test["test"]= round($value,2); //first I round up a value
echo $array_test["test"]; //0,66
$s_array_test= serialize($array_test); //serializing the array
var_dump($s_array_test) // (...)s:4:"test";d:0.66000000000000003108624468950438313186168670654296875;}(...)

This is pretty annoying cause the serialized array is stored into a db a use more space...

How to fix this ?

thx

krifur
  • 870
  • 4
  • 16
  • 36
  • Why you don't store the values in the db, instead of a complex structure? (btw: you "loose" just 32byte. Its not that many, if you ask me) Also it seems you don't provide the real code you use. You _overwrite_ the value of `'test'`, _after_ `round()` with an invalid value (Should be `0.66`) – KingCrunch Jun 28 '11 at 08:57
  • if I straight store the values in the db that is going to make me a lot of fields which can be a little bit annoying to code and I just use all the values in a uniq calcul so...I just fix the code thx – krifur Jun 28 '11 at 08:59
  • see also: http://stackoverflow.com/questions/6503928/a-php-bug-very-simple-how-to-fix – kapa Jun 28 '11 at 10:00

2 Answers2

4

First of all read the section about floats in the manual http://php.net/manual/en/language.types.float.php

Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error progragation must be considered when several operations are compounded.

Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....

So never trust floating number results to the last digit, and never compare floating point numbers for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.

You may use sprintf() (instead of round()) to convert the float into a fixed-sized string

sprintf('%.2f', $float);

But I suggest you to create and use a real database schema. You don't need a database at all, if you just put unstructured strings in it. You can use simple flatfiles instead.

Community
  • 1
  • 1
KingCrunch
  • 128,817
  • 21
  • 151
  • 173
  • It still doesn't work, If I replace the round instruction by the sprintf,a bunch of figures appears just after serializing the array... – krifur Jun 29 '11 at 10:07
  • "bunch of figures"? Maybe you have another problem? Just tested it once more and works fine here `$float = 0.66342534675; var_dump(sprintf('%.2f', $float)); string(4) "0.66"` – KingCrunch Jun 29 '11 at 10:08
  • this is ok on my side as well, this is what I get after sprintf the $float value, but then once again, after I serialize the array I get a lof of figures after the coma exactly like in the first post, 0.66000000000000003108624468950438313186168670654296875 instead of 0.66 – krifur Jun 29 '11 at 10:15
  • Even once more: Cannot reproduce `$float = 0.6621342543; var_dump(serialize(sprintf('%.2f', $float))); string(11) "s:4:"0.66";"` You a serializing the right variable/value? Note, that the float is treated as string and not as double/float. – KingCrunch Jun 29 '11 at 10:16
  • print_r($ar_culture_details); $s_ar_culture_details = addslashes(serialize($ar_culture_details)); print_r($s_ar_culture_details); This is the code and here is a sample result for only one value//before serialize //Array ( [bt] => Array ( [surf] => 24.4 //after serialize //a:16:{s:2:\"bt\";a:8:{s:4:\"surf\";d:24.39999999999999857891452847979962825775146484375 – krifur Jun 29 '11 at 10:41
  • I need to look around a little bit more, but that s really strange, perhaps there's a php cache server side I'm still looking! – krifur Jun 29 '11 at 10:42
  • same problem here (http://stackoverflow.com/questions/1109545/php-serialize-floating-points) it looks like there's no solution, just to be sure I think there is no difference between sprintf() and round() cause both keep accuracy of floating result... – krifur Jun 30 '11 at 07:54
1

it may behave like this because data type in table is varchar or any non -numeric datatype. i don't say this is the only reason but it can be one of them ..

Rukmi Patel
  • 2,619
  • 9
  • 29
  • 41