开发者

PHP serialize() output for number is whack

I am calculating the size of a file开发者_如何学C upload in PHP, to format in MB with one decimal place like so:

$metadata['upload_data'] = intval($_FILES['Filedata']['size'] / 104857.6) / 10;

When I echo $metadata['upload_data'] the output is 1.7 as I would expect. But when I serialize the array with serialize($metadata) and save it to a file, the output is:

a:2:{s:7:"uploads";i:11;s:11:"upload_data";d:1.6999999999999999555910790149937383830547332763671875;}

I'm trying to be efficient by storing file sizes in MB not bytes, but this seems worse! Why would PHP store it that way? And am I going about this the right way? Thanks


From the manual: http://php.net/manual/en/language.types.float.php

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....

I would suggest using json_encode and json_decode if you want to see "1.7" in a serialized version of your array. These functions also end up being quicker than serialize and unserialize and are also easier to read (by easier to read, I mean a person reading them, rather than the machine).


You're making assumptions of the way serialize works.

The obvious way to store a double (and a "float" in most languages other than C will be a double) is as the underlying 8 bytes. As far as I know, most sane binary-serialization will do this.

(Yes, I'm slightly abusing "double" to mean IEEE 754 64-bit binary floating point.)

Instead, PHP is trying to store a decimal representation, which is hampered by the fact that there is no way to represent 1.7 exactly in binary. It turns out that the closest representation is exactly 1.6999999999999999555910790149937383830547332763671875.

I don't know why PHP chooses to give an exact representation instead of the shortest representation that converts back to the same double (you provably do not need more than 17 digits or so, and there are better algorithms to give you shorter numbers). One possibility is that it wants to preserve exact semantics in case the target system uses a different floating point representation (e.g. if your target system uses 128-bit "double-doubles", 1.7 is a different number).

All that said, 1700 is only one more byte than 1.7 but offers much more precision.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜