Помогите решить проблемку, выполняю одинаковый скрипт на разных хостингах и получаю разный результат. Вот пример демонстрирующий проблему:
$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](http://phpforum.ru/html/emoticons/smile.gif)
P.S. А есть ли реальная необходимость работать с числами и в hex записи, и в decimal?
Спустя 13 минут, 51 секунда (30.12.2009 - 04:16) ToBad написал(а):
Проверил, на одном хостинге 4 байта, на другом 8.
А есть ли возможность повлиять на PHP_INT_SIZE? Или аппаратная зависимость?
А есть ли возможность повлиять на 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-х байтовые.
Может как-то пересмотреть логику? С трудом представляю приложение на 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 написал(а):
Не проверял, но как-то так можно
Если $n строго от 1 до 31, то проверки можно убрать
Распишу сложную строку, чтоб понятно было где искать ошибку, если что
P.S. Еще есть расширение GMP http://ru.php.net/manual/en/book.gmp.php но там сдвигов нет вроде как, только побитовые логические и арифметика
//циклический сдвиг влево 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](http://phpforum.ru/html/emoticons/sad.gif)
Спустя 1 час, 49 минут, 24 секунды (31.12.2009 - 02:30) ToBad написал(а):
Большое спасибо за пример и подробное описание сложной строки!
Функцию проверил, работает всё правильно кроме сдвига вправо на 1 бит.
Попробую исправить.
Функцию проверил, работает всё правильно кроме сдвига вправо на 1 бит.
function ROR($a, $n) {
return ROL($a,32-$n);
}
echo dechex(ROR(0x3A15E747,1)); // 0x80000000
echo dechex(ROR(0x3483038F,1)); // 0x80000000
Попробую исправить.