|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2018-03-15 08:47 UTC] mikael dot knutsson at gmail dot com
Description: ------------ We have a hex string like this: "eb3dd796efda2409" received from an upstream system. This is a big-nibble hex string containing this integer value: -1495802457948019703 This is a 64-bit signed integer. When converting this using hexdec this is converted to a float and returns the wrong value, when assigned to a variable as a hex string and converted using intval() it loses precision. When looking at the documentation: http://php.net/manual/en/function.hexdec.php it mentions this: > The function can convert numbers that are too large to fit into the platforms integer type, larger values are returned as float in that case. However, this happens on a 64-bit compiled PHP where this integer should fit into the platform's integer size. php --version PHP 7.2.3-1 (cli) (built: Mar 6 2018 11:15:04) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.2.3-1, Copyright (c) 1999-2018, by Zend Technologies php -a Interactive mode enabled php > echo PHP_INT_MAX; 9223372036854775807 php > echo PHP_INT_SIZE; 8 As a side note: We ended up using pack/unpack to avoid the interim float conversion, and we also had to use "J" as the unpack conversion type to get the right value which implies big-endianness in the packed value. I am not sure this is correct either as doing this conversion in other languages works just fine without specifying endianness. (tried in Python and Go) (I can file a separate bug if this is also not intended) Test script: --------------- $strhex = "eb3dd796efda2409"; $hex = 0xeb3dd796efda2409; echo hexdec($strhex); echo $hex; echo intval($hex); var_dump(unpack('J', pack("H*", $strhex))); Expected result: ---------------- -1495802457948019703 -1495802457948019703 -1495802457948019703 array(1) { [1]=> int(-1495802457948019703) } Actual result: -------------- 1.6950941615762E+19 1.6950941615762E+19 -1495802457948020736 array(1) { [1]=> int(-1495802457948019703) } PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Dec 13 09:00:01 2025 UTC |
> […] which implies big-endianness in the packed value. That is to be expected. `pack("H*", $strhex)` returns "\xeb\x3d\xd7\x96\xef\xda\x24\x09", which is big-endian (the highest byte is to the left). > However, this happens on a 64-bit compiled PHP where this > integer should fit into the platform's integer size. No, it does not, since "PHP does not support unsigned integers"[1]. > when assigned to a variable as a hex string and converted using > intval() it loses precision. Hexadecimal number literals are regarded as non-negative numbers, but this number exceeds PHP_INT_MAX, so it is stored as float. Since the float value exceeds PHP_INT_MAX the result of the conversion to integer is actually undefined[2]. So yes, if you want to convert unsigned 64bit values represented as hexadecimal strings, you have to work-around the signed integer limitations. Your (un)pack() solution appears to be appropriate. Changing to doc-bug, since this info could be added to the hexdec() man page. [1] <http://www.php.net/manual/en/language.types.integer.php#language.types.integer.syntax> [2] <http://www.php.net/manual/en/language.types.integer.php#language.types.integer.casting.from-float>