Я пытаюсь напечатать 40-битное число в php. Но при использовании компьютера с Windows он допускает только 32-разрядные целые числа, что приводит к тому, что мой код отображает неверный результат. Пример кода ниже:
function decoded_microchip_id($coded_string) {
$manufacturer = substr($coded_string, 0, 3);
$manufacturer = hexdec($manufacturer);
$manufacturer = $manufacturer / 4;
$device_id = substr($coded_string, 2, 11);
$device_id = hexdec($device_id);
$device_id = $device_id & 0x3fffffffff;
echo $manufacturer.'.'.$device_id;
};
decoded_microchip_id('f58e29a43c67');
Правильный вывод для кода выше: 982.60828171367
Но в моей 32-битной среде Windows я получаю: 982.698629223
При тестировании кода в различных песочницах PHP выходные данные также различаются.
Вот пример среды песочницы, дающей мне правильный вывод:
http://sandbox.onlinephpfunctions.com/code/83cc28fd5314557e7a9d86d8061e1c8dfae4d1b7
И вот пример среды, которая производит неправильный вывод:
http://codepad.org/m2ygOgC6
Кто-нибудь знает способ обойти эту проблему или решение.
Благодарю.
Функция PHP hexdec()
отлично работает на 32-битной тоже. Документация говорит, что это производит float
числа, когда результат не помещается в 32 бита.
Интересно что 0x3fffffffff
также хранится как float
число.
Виновником является побитовый оператор (&
), который, кажется, производит целое число. Преобразование его результата в float не помогает, урон уже нанесен.
Такое поведение документированный:
оба операнда будут преобразованы в целые числа, а результатом будет целое число.
Вы можете попытаться разбить входную строку на части, которые умещаются в 32 бита, и использовать для них побитовые операторы, а затем использовать сложение и умножение для генерации конечного значения (сложение и умножение преобразуют результат в число с плавающей точкой, если он не может уместиться в 32 бита).
Более простое решение для этой ситуации — преобразовать шестнадцатеричную строку в двоичное представление числа, которое она кодирует, извлечь биты, необходимые для каждого компонента, а затем преобразовать значения в десятичное число. В этом случае никакие битовые операции не выполняются (за исключением преобразований, которые, кажется, работают правильно).
function decoded_microchip_id($coded_string)
{
// Convert to binary
$bin = base_convert($coded_string, 16, 2);
// Split to 10/38 bits
$manufacturer = substr($bin, 0, 10);
$device_id = substr($bin, 10, 38);
// Convert to decimal
$manufacturer = bindec($manufacturer);
$device_id = bindec($device_id);
// Put pieces back
return $manufacturer.'.'.$device_id;
}
Других решений пока нет …