В замаскированной форме для любой платформы (32-битной, 64-битной ... будущей, если определено PHP_INT_MAX
), которая, возможно, обеспечит выигрыш в производительности (без ветвления):
function uintRShift($uint,$shift)
{
//if ($shift===0) return $uint;
//PHP_INT_MAX on 32 =7FFFFFFF, or zero & 32 ones
$mask=PHP_INT_MAX>>($shift-1);
return $uint>>$shift&$mask;
}
В настройке маски все нули установлены для самых левых $shift
битов $uint
. Примечание: Раскомментируйте первую строку, если вы хотите, чтобы можно было / допускало смещение нуля отрицательного / большого числа (поскольку маска будет изменять отрицательное / большое число даже при $shift=0
).
Код модульного тестирования, показывающий, что он работает в 32-битном режиме:
class UintRShiftTest extends PHPUnit_Framework_TestCase {
public function provide_shifts() {
return array(
/* start shift end*/
array(0, 4, 0)
,array(0xf, 4, 0)
,array(0xff, 4, 0xf)
,array(0xfffffff, 4, 0xffffff)
,array(0xffffffff, 4, 0xfffffff)
,array(-1, 4, 0xfffffff)//Same as above
,array(0, 1, 0)
,array(0xf, 1, 0x7)
,array(-1, 1, 0x7fffffff)
);
}
/**
* @dataProvider provide_shifts
*/
function test_uintRShift($start,$shift,$end) {
$this->assertEquals($end,uintRShift($start,$shift));
}
}
Для чего стоит упомянутая выше функция:
function uintRShift_branch($uint,$shift)
{
if ($uint<0) {
return ($uint>>$shift)+(2<<~$shift);
} else {
return $uint>>$shift;
}
}
Сбой автоматического теста:
# 4 Отчеты -1
. Это может быть оправдано тем, что PHP сообщает 0xffffffff
как большое положительное число (документация предполагает, что большие целые числа автоматически переключаются на числа с плавающей запятой, хотя битовый сдвиг, похоже, все еще рассматривает его как обычное целое число)
# 8 В результате получается -2147483649
, что на самом деле правильно (аналогично 0x7fffffff
), но ниже минимального значения int для PHP: -2147483648