Doc #76098 [Com]: Conversion from hex string to 64-bit int returns wrong value
Edit report at https://bugs.php.net/bug.php?id=76098&edit=1
ID: 76098
Comment by: marius dot buescher at gmx dot de
Reported by: mikael dot knutsson at gmail dot com
Summary: Conversion from hex string to 64-bit int returns
wrong value
Status: Open
Type: Documentation Problem
Package: Math related
Operating System: Linux 64-bit
PHP Version: 7.2.3
Block user comment: N
Private report: N
New Comment:
This should be documented though. I also ran into that problem.
Previous Comments:
------------------------------------------------------------------------
[2018-03-16 04:29:06] mikael dot knutsson at gmail dot com
Thank you for clarifying!
------------------------------------------------------------------------
[2018-03-15 11:24:59] cmb@php.net
> [â¦] 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>
------------------------------------------------------------------------
[2018-03-15 08:47:15] 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)
}
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=76098&edit=1
Thread (3 messages)