Я испытываю разные результаты в PHP-коде, работающем в Mac и Linux.
У меня есть 2 сервера, на которых запущен следующий код:
$ltt = ((ord($str[7]) << 24) | (ord($str[8]) << 16) | (ord($str[9]) << 8) | (ord($str[10]))) / 1000000;
Даже выходы ord(str[ ])
одинаковы:
[7] = 254 [8] = 26 [9] = 22 [10] = 216
Но в стеке MAMP (Mac), работающем под php 5.3.6, если изначально предполагается, что $ ltt является отрицательным числом, он возвращает 4263.12265
(неверно).
В стеке LAMP (Ubuntu), выполняющем ту же самую версию php, он вернет точное отрицательное значение -31.84465
.
Это происходит только с отрицательными номерами.
Обновить добавление. Информация:
þØçï_Kstring(25) "þØçï_K"
000e1b00000000fe1a16d806e707ef0000045f0000004b0000
Для того чтобы функция включала только числовые входы, выход по- прежнему отличается :
$ltt = (254 << 24 | 26 << 16 | 22 << 8 | 216)/ 1000000;
4263.12265
на MAMP и -31.84465
на -31.84465
Это 32-разрядная 64-разрядная проблема.
Поскольку ваш самый старший байт составляет> 127, на 32-битной платформе это интерпретируется как отрицательное значение из-за целочисленного переполнения – устанавливается самый старший бит. На 64-битной платформе это не так.
Решение состоит в том, чтобы использовать pack()
и unpack()
чтобы вы могли указать, что целое число должно быть подписано. EDIT Исправлен этот пример кода. См. Edit 2
$packed = pack('C*', ord($str[7]), ord($str[8]), ord($str[9]), ord($str[10])); $unpacked = unpack('l', $packed); $lat = current($unpacked);
… однако вы также должны осознавать, что это не будет работать на архитектуре little-endian, потому что порядок байтов будет неправильным. Вы можете просто отменить порядок упакованных байтов, чтобы обойти это, но я просто пытаюсь обернуть голову вокруг решения для всей работы.
EDIT 2
Хорошо, мне потребовалось некоторое время, чтобы обмануть голову, но мы пришли туда, в конце:
Вам нужно сделать, если установлен самый старший бит, ИЛИ результат с номером, где минимально значимые 32 бита не установлены, а остальные. Итак, следующее работает как на 32, так и на 64 бит:
<?php // The input bytes as ints $bytes = array(254, 26, 22, 216); // The operand to OR with at the end $op = $bytes[0] & 0x80 ? (~0 << 16) << 16 : 0; // Do the bitwise thang $lat = (($bytes[0] << 24) | ($bytes[1] << 16) | ($bytes[2] << 8) | $bytes[3]) | $op; // Convert to float for latitude $lat /= 1000000; echo $lat;