[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Проблема с числами на разных хостингах
ToBad
Здравствуйте!

Помогите решить проблемку, выполняю одинаковый скрипт на разных хостингах и получаю разный результат. Вот пример демонстрирующий проблему:

$a=0x57E1F7BC ^ 0x9502ACEA;
echo $a;

Результат у одного хостера -1025287338, у другого 3269679958. Если вывожу число через dechex, то результат одинаковый. Первый вариант с отрицательным числом для меня правильный, ибо переменная с этим числом далее не раз используется в расчётах, например складывается с другой, а соответственно общий результат получается разным.

В частном случае со сложением выкрутился так:

function sign($a) {
if ($a>0x7FFFFFFF) $a-=0x100000000;
return $a;}

$a=sign(0x57E1F7BC ^ 0x9502ACEA);
echo $a;

Складывает теперь правильно, но появилась проблема в следующем месте.
На этот раз результат работы функции ROR. Кстати, написал конечно очень коряво, как смог с нулевым знанием PHP, буду очень благодарен если кто подскажет короткий вариант с помощью логических операций. Цель соответствовать ассемблерному ror-у, то есть ушедший вправо бит появляется слева, соответственно сдвигать можно на указанное во втором параметре кол-во бит.

function ror($b,$a) {
$s=str_pad(decbin($b), 32, "0", STR_PAD_LEFT);
return bindec(substr($s,$a*(-1)).substr($s,0,32-$a));}

а вот и пример ошибки:

// Правильный хостер
$a=ror(96800817,3)
echo $a; // $a=548971014

$a=ror(-43374997,3)
echo $a; // $a=2142061773

// Проблемный хостер

$a=ror(96800817,3)
echo $a; // $a=548971014

$a=ror(-43374997,3)
echo $a; // $a=2147483647 <- ошибка

Это смог решить следующим образом (теперь ror правильный):

function sign2($a) {
$b=dechex($a);
if (strlen($b)==16) {$a=hexdec(substr($b,8,8));}
return $a;}

function ROR($b,$a) {$s=str_pad(decbin(sign2($b)), 32, "0", STR_PAD_LEFT);
return bindec(substr($s,$a*(-1)).substr($s,0,32-$a));}

Ну и как водится, уверен, что это не последняя проблема... Как бы найти решение не в переделки скриптов, а может какие переменные поменять в php.ini что бы работали одинаково скрипты. Может есть какие настройки или глобальные флаги?
PHP Version 5.2.6 на хорошем и 5.2.11 на проблемном.
Так же очень прошу прощения если спрашиваю глупости или стиль написания кода расстроит людей опытных, я пытался найти решение самостоятельно, к сожалению не смог. Заранее благодарю за помощь и подсказки!



Спустя 1 час, 7 минут, 40 секунд (30.12.2009 - 04:02) VolCh написал(а):
Скорее всего "хороший" на x86, а "плохой" на x86-64. В PHP в общем случае размер integer не определён
Цитата
The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). 64-bits platforms usually have the maximum value of about 9E18. PHP does not support unsigned integers. Integer size can be determined using the constant PHP_INT_SIZE, and maximum value using the constant PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.

Другими словами, на 32-бит - 4 байта, на 64-бит 8 байт. То есть смотри константу PHP_INT_SIZE и по ней вызывай или родные функции, или свои варианты с учетом в два, как правило, раза большей длины integer. Быстрее, кстати, наверное будет | 0xFFFFFFFF00000000 c отрицательными числами и вызывать родные операции, а не мудрить smile.gif

P.S. А есть ли реальная необходимость работать с числами и в hex записи, и в decimal?

Спустя 13 минут, 51 секунда (30.12.2009 - 04:16) ToBad написал(а):
Проверил, на одном хостинге 4 байта, на другом 8.
А есть ли возможность повлиять на PHP_INT_SIZE? Или аппаратная зависимость?

Цитата (VolCh @ 30.12.2009 - 01:02)
Быстрее, кстати, наверное будет | 0xFFFFFFFF c отрицательными числами и вызывать родные операции, а не мудрить


Не совсем понял, как должен выглядеть этот пример

$a=0x57E1F7BC ^ 0x9502ACEA;
echo $a;

у хостера с PHP_INT_SIZE=8 что бы получить число -1025287338?

Спустя 2 минуты, 32 секунды (30.12.2009 - 04:19) ToBad написал(а):
Цитата (VolCh @ 30.12.2009 - 01:02)
| 0xFFFFFFFF00000000


Ага, так понял.

Спустя 10 минут, 53 секунды (30.12.2009 - 04:30) VolCh написал(а):
Цитата (ToBad @ 30.12.2009 - 04:16)
Проверил, на одном хостинге 4 байта, на другом 8.
А есть ли возможность повлиять на PHP_INT_SIZE? Или аппаратная зависимость?

Скорее на уровне исходников/компилятора, в общем малой кровью не поменять наверняка, как минимум пересобирать PHP или пытаться запустить 32-PHP под 64-бит ос.

Спустя 1 час, 40 минут, 38 секунд (30.12.2009 - 06:10) ToBad написал(а):
Цитата (VolCh @ 30.12.2009 - 01:30)
в общем малой кровью не поменять наверняка


Как тогда лучше реализовать эмуляцию работы с 4-х байтным integer на 64-битной системе? Всё подвергать | 0xFFFFFFFF00000000? А как быть со сложением например?
Нашел вот такой код:

$y= ($y & (1<<31)) ? ($y | 0xFFFFFFFF00000000) : ($y & 0xFFFFFFFF);

Написано: надо делать после каждого вызова (int) в проге для 32 битных систем, чтобы на 64х обнулялись лишние разряды....
По другому выходит нет вариантов?

Спустя 4 часа, 8 минут, 51 секунда (30.12.2009 - 10:19) VolCh написал(а):
Может и есть, но, думаю, на том же уровне - костыли.

Может как-то пересмотреть логику? С трудом представляю приложение на PHP, которому нужно одновременно и hex значения, и decimal, да еще именно 4-х байтовые.

Спустя 9 часов, 51 минута, 20 секунд (30.12.2009 - 20:10) ToBad написал(а):
Цитата (VolCh @ 30.12.2009 - 07:19)
С трудом представляю приложение на PHP, которому нужно одновременно и hex значения, и decimal, да еще именно 4-х байтовые.


Я переделывал алгоритм кодирования/декодирования с ассемблерного варианта. Там много циклов, логических операций, работа с буфером по смещению и т.д.
Соответственно вся работа ведется с dword, отсюда и необходимость придерживаться такого формата... Так как программист на PHP я никакой, использовал много конвертаций в hex, dec, bin... Скажем так - делал как понимал и как умел....
В общем задачу я решил, а это было бы невозможно без понимания причины моих проблем. VolCh спасибо Вам за помощь и подсказки!
В некоторых местах использовал функцию сделанную из формулы приведенной в моём предпоследнем посте. Теперь работает!

Очень хотелось бы организовать с помощью логических операций, просто и красиво, побитный циклический сдвиг (например вправо) 32-х битного числа на указанное кол-во бит. Сейчас это выглядит так:

function ROR($b,$a) {$s=str_pad(decbin($b), 32, "0", STR_PAD_LEFT);
if (strlen($s)>32) $s=substr($s,-32);
return bindec(substr($s,$a*(-1)).substr($s,0,32-$a));}

Спустя 4 часа, 30 минут, 34 секунды (31.12.2009 - 00:41) VolCh написал(а):
Не проверял, но как-то так можно

//циклический сдвиг влево 32-х битного $a на $n бит
function rol($a, $n) {
if ($n == 0)
return 0;
$n = $n % 32;
if ($n < 0)
$n = 32 - $n;
$a = ($a << $n) | ((($a >> (32-$n)) & ((1 << $n) - 1));
return ($a & (1<<31)) ? ($a | 0xFFFFFFFF00000000) : $a; //для 64-бит
}

//циклический сдвиг вправо 32-х битного $a на $n бит
function ror($a, $n) {
return rol(32-$n);
}

Если $n строго от 1 до 31, то проверки можно убрать
Распишу сложную строку, чтоб понятно было где искать ошибку, если что


$temp1 = $a << $n; // обычный сдвиг влево, в младших разрядах 0, старшие $n теряются, если 32 бит, или мусор, если 64
$temp2 = $a >> (32 - $n); // старшие $n бит исходного $a в младших разрядах, в старших "мусор"
$temp3 = (1 << $n) - 1; // маска для выделения младших $n разрядов
$temp4 = $temp2 & temp3; // старшие $n бит исходного $a в младших разрядах, в старших 0
$a = $temp1 | $temp4; // результат в младших 32 бит, в старших 0


P.S. Еще есть расширение GMP http://ru.php.net/manual/en/book.gmp.php но там сдвигов нет вроде как, только побитовые логические и арифметика sad.gif

Спустя 1 час, 49 минут, 24 секунды (31.12.2009 - 02:30) ToBad написал(а):
Большое спасибо за пример и подробное описание сложной строки!
Функцию проверил, работает всё правильно кроме сдвига вправо на 1 бит.

function ROR($a, $n) {
return ROL($a,32-$n);
}

echo dechex(ROR(0x3A15E747,1)); // 0x80000000
echo dechex(ROR(0x3483038F,1)); // 0x80000000

Попробую исправить.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2025 Invision Power Services, Inc.