عوامل الأعداد الثنائية في PHP
تتيح عوامل الأعداد الثنائية تقدير ومعالجة بتات (bits) معينة ضمن العدد الصحيح.
مثال | الاسم | النتيجة |
---|---|---|
$a & $b
|
And و | يُعيد 1 مكان كل بت له القيمة 1 في كلٍّ من $a و $b .
|
$a | $b
|
Or أو (الضمنية) | يُعيد 1 مكان كل بت له القيمة 1 في $a أو $b أو كلاهما.
|
$a ^ $b
|
Xor أو (غير الضمنية) | يُعيد 1 مكان كل بت له القيمة 1 في $a أو $b وليس كلاهما.
|
~ $a
|
Not النفي | يعكس قيمة البتات في $a .
|
$a << $b
|
Shift left الإزاحة إلى اليسار | تزيح بتات $a بمقدار $b خطوة إلى اليسار (كل خطوة تعني الضرب بالعدد 2).
|
$a >> $b
|
Shift right الإزاحة إلى اليمين | تزيح بتات $a بمقدار $b خطوة إلى اليمين (كل خطوة تعني القسمة على 2).
|
عملية إزاحة البتات في PHP هي عملية حسابية. يتم تجاهل البتات المزاحة إلى كلا الطرفين. في الإزاحة اليسارية تزاح الأصفار إلى الداخل من جهة اليمين في حين يزاح بت الإشارة خارجًا من جهة اليسار، وهذا يعني أن إشارة المعامل (operand) لا تُحفظ. أما في الإزاحات اليمينية فتزاح نسخ من بت الإشارة من جهة اليسار، وهذا يعني أن إشارة العامل تكون محفوظة.
لضمان الحصول على الأولوية المطلوبة يمكن استخدام الأقواس. فعلى سبيل المثال: في التعبير $a & $b == true
تعالج المساواة أولًا ثم معامل البتات ثانيًا، أما في التعبير ($a & $b) == true
فيعالج معامل البتات أولًا ثم تليها المساواة.
إن كانت العوامل &
و |
و ^
مطبّقًة على السلاسل النصية، فستجري العملية على قيم ASCII الخاصّة بالحروف التي تكوّن السلسلة النصية، وستكون النتيجة سلسلة نصّية، وفيما عدا ذلك تُحوّل جميع الأنواع إلى أعداد صحيحة وتكون النتيجة عددًا صحيحًا.
إن كان العامل ~
مطبّقًا على سلسلة نصية، فستجري العملية على قيم ASCII الخاصة بالحروف المكوّنة للسلسلة النصية، وستكون النتيجة سلسلة نصيّة، وفيما عدا ذلك ستُعامل جميع الأنواع الأخرى على أنّها أعداد صحيحة.
تعامل جميع الأنواع على أنّها أعداد صحيحة في حال استخدام العاملين <<
و >>
.
تستخدم الإعدادات الخاصة بالتبليغ عن الأخطاء error_reporting قيمًا ثنائية، وتقدّم مثالًا واقعيًا عن طريقة تفعيل أو تعطيل البتات (أي ضبط قيمتها إلى 1 أو 0، وبالتالي ستُفعّل الراية [flag] المرتبطة بهذا البت). لعرض جميع الأخطاء باستثناء الملاحظات، تنصّ التعليمات الموجودة في ملف php.ini على استخدام:
E_ALL & ~E_NOTICE
تبدأ الشيفرة من E_ALL
00000000000000000111011111111111
ثم تأخذ قيمة E_NOTICE
00000000000000000000000000001000
ثم تقلبها إلى ~:
11111111111111111111111111110111
وفي النهاية، تستخدم الشيفرة العامل (&) للعثور على البتات المُفعّلة في كلا القيمتين
00000000000000000111011111110111
يمكن تحقيق النتيجة ذاتها باستخدام العامل XOR (^) للعثور على البتات المُفعّلة في القيمة الأولى أو الثانية
E_ALL ^ E_NOTICE
يمكن استخدام error_reporting لتوضيح آلية تشغيل البتات. فلعرض الأخطاء والأخطاء القابلة للاسترجاع يمكن استخدام الطريقة التالية
E_ERROR | E_RECOVERABLE_ERROR
تجمع العملية بين E_ERROR
00000000000000000000000000000001
و
00000000000000000001000000000000
باستخدام العامل OR ("|") للحصول على البتات المشغلة في إحدى القيمتين
00000000000000000001000000000001
المثال 1: تطبيق العوامل AND و OR و XOR على الأعداد الصحيحة
<?php
/*
* تجاهل القسم العلوي
* فالهدف منه تنسيق المخرجات لتظهر بشكل أوضح
*/
$format = '(%1$2d = %1$04b) = (%2$2d = %2$04b)'
. ' %3$s (%4$2d = %4$04b)' . "\n";
echo <<<EOH
--------- --------- -- ---------
result value op test
--------- --------- -- ---------
EOH;
/*
* هذه هي الأمثلة
*/
$values = array(0, 1, 2, 4, 8);
$test = 1 + 4;
echo "\n Bitwise AND \n";
foreach ($values as $value) {
$result = $value & $test;
printf($format, $result, $value, '&', $test);
}
echo "\n Bitwise Inclusive OR \n";
foreach ($values as $value) {
$result = $value | $test;
printf($format, $result, $value, '|', $test);
}
echo "\n Bitwise Exclusive OR (XOR) \n";
foreach ($values as $value) {
$result = $value ^ $test;
printf($format, $result, $value, '^', $test);
}
?>
تعطي الأمثلة السابقة المخرجات التالية:
--------- --------- -- ---------
result value op test
--------- --------- -- ---------
Bitwise AND
( 0 = 0000) = ( 0 = 0000) & ( 5 = 0101)
( 1 = 0001) = ( 1 = 0001) & ( 5 = 0101)
( 0 = 0000) = ( 2 = 0010) & ( 5 = 0101)
( 4 = 0100) = ( 4 = 0100) & ( 5 = 0101)
( 0 = 0000) = ( 8 = 1000) & ( 5 = 0101)
Bitwise Inclusive OR
( 5 = 0101) = ( 0 = 0000) | ( 5 = 0101)
( 5 = 0101) = ( 1 = 0001) | ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) | ( 5 = 0101)
( 5 = 0101) = ( 4 = 0100) | ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) | ( 5 = 0101)
Bitwise Exclusive OR (XOR)
( 5 = 0101) = ( 0 = 0000) ^ ( 5 = 0101)
( 4 = 0100) = ( 1 = 0001) ^ ( 5 = 0101)
( 7 = 0111) = ( 2 = 0010) ^ ( 5 = 0101)
( 1 = 0001) = ( 4 = 0100) ^ ( 5 = 0101)
(13 = 1101) = ( 8 = 1000) ^ ( 5 = 0101)
المثال 2: تطبيق XOR على السلاسل النصية
<?php
echo 12 ^ 9;
// النتيجة 5
echo "12" ^ "9";
// النتيجة هي محرّف الفراغ الخلفي
// backspace (ASCII 8)
// ('1' (ascii 49)) ^ ('9' (ascii 57)) = #8
echo "hallo" ^ "hello";
// النتيجة هي قيم ASCII
// #0 #4 #0 #0 #0
// 'a' ^ 'e' = #4
echo 2 ^ "3";
// النتيجة هي 1
// 2 ^ ((int)"3") == 1
echo "2" ^ 3;
// النتيجة 1
// ((int)"2") ^ 3 == 1
?>
المثال 3: إزاحة البتات في الأعداد الصحيحة
<?php
/*
* هذه هي الأمثلة
*/
echo "\n--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---\n";ق
$val = 4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copy of sign bit shifted into left side');
$val = 4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places);
$val = 4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'bits shift out right side');
$val = 4;
$places = 4;
$res = $val >> $places;
p($res, $val, '>>', $places, 'same result as above; can not shift beyond 0');
echo "\n--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---\n";
$val = -4;
$places = 1;
$res = $val >> $places;
p($res, $val, '>>', $places, 'copy of sign bit shifted into left side');
$val = -4;
$places = 2;
$res = $val >> $places;
p($res, $val, '>>', $places, 'bits shift out right side');
$val = -4;
$places = 3;
$res = $val >> $places;
p($res, $val, '>>', $places, 'same result as above; can not shift beyond -1');
echo "\n--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---\n";
$val = 4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'zeros fill in right side');
$val = 4;
$places = (PHP_INT_SIZE * 8) - 4;
$res = $val << $places;
p($res, $val, '<<', $places);
$val = 4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places, 'sign bits get shifted out');
$val = 4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'bits shift out left side');
echo "\n--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---\n";
$val = -4;
$places = 1;
$res = $val << $places;
p($res, $val, '<<', $places, 'zeros fill in right side');
$val = -4;
$places = (PHP_INT_SIZE * 8) - 3;
$res = $val << $places;
p($res, $val, '<<', $places);
$val = -4;
$places = (PHP_INT_SIZE * 8) - 2;
$res = $val << $places;
p($res, $val, '<<', $places, 'bits shift out left side, including sign bit');
/*
* تجاهل الجزء السفلي،
* فالهدف منه تنسيق المخرجات لتظهر بشكل أوضح
*/
function p($res, $val, $op, $places, $note = '') {
$format = '%0' . (PHP_INT_SIZE * 8) . "b\n";
printf("Expression: %d = %d %s %d\n", $res, $val, $op, $places);
echo " Decimal:\n";
printf(" val=%d\n", $val);
printf(" res=%d\n", $res);
echo " Binary:\n";
printf(' val=' . $format, $val);
printf(' res=' . $format, $res);
if ($note) {
echo " NOTE: $note\n";
}
echo "\n";
}
?>
تكون مخرجات المثال السابق في جهاز يعمل بنظام 32-بت بالشكل التالي:
--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
Expression: 2 = 4 >> 1
Decimal:
val=4
res=2
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000010
NOTE: copy of sign bit shifted into left side
Expression: 1 = 4 >> 2
Decimal:
val=4
res=1
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000001
Expression: 0 = 4 >> 3
Decimal:
val=4
res=0
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
NOTE: bits shift out right side
Expression: 0 = 4 >> 4
Decimal:
val=4
res=0
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
NOTE: same result as above; can not shift beyond 0
--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
Expression: -2 = -4 >> 1
Decimal:
val=-4
res=-2
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111110
NOTE: copy of sign bit shifted into left side
Expression: -1 = -4 >> 2
Decimal:
val=-4
res=-1
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
NOTE: bits shift out right side
Expression: -1 = -4 >> 3
Decimal:
val=-4
res=-1
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111111
NOTE: same result as above; can not shift beyond -1
--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
Expression: 8 = 4 << 1
Decimal:
val=4
res=8
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000001000
NOTE: zeros fill in right side
Expression: 1073741824 = 4 << 28
Decimal:
val=4
res=1073741824
Binary:
val=00000000000000000000000000000100
res=01000000000000000000000000000000
Expression: -2147483648 = 4 << 29
Decimal:
val=4
res=-2147483648
Binary:
val=00000000000000000000000000000100
res=10000000000000000000000000000000
NOTE: sign bits get shifted out
Expression: 0 = 4 << 30
Decimal:
val=4
res=0
Binary:
val=00000000000000000000000000000100
res=00000000000000000000000000000000
NOTE: bits shift out left side
--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
Expression: -8 = -4 << 1
Decimal:
val=-4
res=-8
Binary:
val=11111111111111111111111111111100
res=11111111111111111111111111111000
NOTE: zeros fill in right side
Expression: -2147483648 = -4 << 29
Decimal:
val=-4
res=-2147483648
Binary:
val=11111111111111111111111111111100
res=10000000000000000000000000000000
Expression: 0 = -4 << 30
Decimal:
val=-4
res=0
Binary:
val=11111111111111111111111111111100
res=00000000000000000000000000000000
NOTE: bits shift out left side, including sign bit
تكون مخرجات المثال السابق في جهاز يعمل بنظام 64-بت بالشكل التالي:
--- BIT SHIFT RIGHT ON POSITIVE INTEGERS ---
Expression: 2 = 4 >> 1
Decimal:
val=4
res=2
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000010
NOTE: copy of sign bit shifted into left side
Expression: 1 = 4 >> 2
Decimal:
val=4
res=1
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000001
Expression: 0 = 4 >> 3
Decimal:
val=4
res=0
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: bits shift out right side
Expression: 0 = 4 >> 4
Decimal:
val=4
res=0
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: same result as above; can not shift beyond 0
--- BIT SHIFT RIGHT ON NEGATIVE INTEGERS ---
Expression: -2 = -4 >> 1
Decimal:
val=-4
res=-2
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111110
NOTE: copy of sign bit shifted into left side
Expression: -1 = -4 >> 2
Decimal:
val=-4
res=-1
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
NOTE: bits shift out right side
Expression: -1 = -4 >> 3
Decimal:
val=-4
res=-1
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111111
NOTE: same result as above; can not shift beyond -1
--- BIT SHIFT LEFT ON POSITIVE INTEGERS ---
Expression: 8 = 4 << 1
Decimal:
val=4
res=8
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000001000
NOTE: zeros fill in right side
Expression: 4611686018427387904 = 4 << 60
Decimal:
val=4
res=4611686018427387904
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0100000000000000000000000000000000000000000000000000000000000000
Expression: -9223372036854775808 = 4 << 61
Decimal:
val=4
res=-9223372036854775808
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=1000000000000000000000000000000000000000000000000000000000000000
NOTE: sign bits get shifted out
Expression: 0 = 4 << 62
Decimal:
val=4
res=0
Binary:
val=0000000000000000000000000000000000000000000000000000000000000100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: bits shift out left side
--- BIT SHIFT LEFT ON NEGATIVE INTEGERS ---
Expression: -8 = -4 << 1
Decimal:
val=-4
res=-8
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1111111111111111111111111111111111111111111111111111111111111000
NOTE: zeros fill in right side
Expression: -9223372036854775808 = -4 << 61
Decimal:
val=-4
res=-9223372036854775808
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=1000000000000000000000000000000000000000000000000000000000000000
Expression: 0 = -4 << 62
Decimal:
val=-4
res=0
Binary:
val=1111111111111111111111111111111111111111111111111111111111111100
res=0000000000000000000000000000000000000000000000000000000000000000
NOTE: bits shift out left side, including sign bit
تنبيه: قبل الإصدار 7.0 من PHP، كانت إزاحة الأعداد الصحيحة بمقادير تفوق أو تساوي الحد الأقصى الذي يدعمه النظام للأعداد الصحيحة الطويلة long integer أو بأعداد سالبة تؤدي إلى الحصول على سلوك غير معروف. بعبارة أخرى، إن كنت تستخدم الإصدار PHP 5.x فلا تزح الأعداد الصحيحة أكثر من 31 بت في نظام 32-بت، ولا تزح الأعداد الصحيحة أكثر من 63-بت في نظام 64-بت.
لمعالجة الأعداد التي تتجاوز الحد الأقصى المحدد في PHP_INI_MAX استخدم الدوال التي تقدّمها الإضافة gmp.
انظر أيضًا
- الدالة
pack()
: تحزيم البيانات في سلسلة نصية ثنائية. - الدالة
unpack()
: فك تحزيم البيانات من السلسلة النصية الثنائية. - الدالة
gmp_and()
- الدالة
gmp_or()
- الدالة
gmp_xor()
- الدالة
gmp_testbit()
- الدالة
gmp_clrbit()
.