1.整型相加溢出問題
$a = 18446744073709551616; // 2的64次方
var_dump($a+1);
輸出結果:結果成double了

2.PHP源碼中對+的處理
ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
zval op1_copy, op2_copy;
int converted = 0;
while (1) { // TYPE_PAIR 會先判斷比較兩個參數的類型
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG):
fast_long_add_function(result, op1, op2);
return SUCCESS;
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
return SUCCESS;
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
if ((result == op1) && (result == op2)) {
/* $a += $a */
return SUCCESS;
}
if (result != op1) {
ZVAL_DUP(result, op1);
}
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
return SUCCESS;
default:
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
} else if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
} else if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function);
zendi_convert_scalar_to_number(op1, op1_copy, result, 0);
zendi_convert_scalar_to_number(op2, op2_copy, result, 0);
converted = 1;
} else {
zend_throw_error(NULL, "Unsupported operand types");
return FAILURE; /* unknown datatype */
}
}
}
}
// 兩個int型相加進入此,彙編溢出更換類型(ps彙編那段沒看懂)
static zend_always_inline void fast_long_add_function(zval *result, zval *op1, zval *op2)
{
#if defined(__GNUC__) && defined(__i386__) \
&& !(4 == __GNUC__ && 8 == __GNUC_MINOR__) \
&& !(4 == __GNUC__ && 9 == __GNUC_MINOR__ && (defined(__PIC__) || defined(__PIE__)))
/* Position-independent builds fail with gcc-4.9.x */
__asm__(
"movl (%1), %%eax\n\t"
"addl (%2), %%eax\n\t"
"jo 0f\n\t"
"movl %%eax, (%0)\n\t"
"movl %3, %c5(%0)\n\t"
"jmp 1f\n"
"0:\n\t"
"fildl (%1)\n\t"
"fildl (%2)\n\t"
"faddp %%st, %%st(1)\n\t"
"movl %4, %c5(%0)\n\t"
"fstpl (%0)\n"
"1:"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
"n"(IS_LONG),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
: "eax","cc", "memory");
#elif defined(__GNUC__) && defined(__x86_64__)
__asm__(
"movq (%1), %%rax\n\t"
"addq (%2), %%rax\n\t"
"jo 0f\n\t"
"movq %%rax, (%0)\n\t"
"movl %3, %c5(%0)\n\t"
"jmp 1f\n"
"0:\n\t"
"fildq (%1)\n\t"
"fildq (%2)\n\t"
"faddp %%st, %%st(1)\n\t"
"movl %4, %c5(%0)\n\t"
"fstpl (%0)\n"
"1:"
:
: "r"(&result->value),
"r"(&op1->value),
"r"(&op2->value),
"n"(IS_LONG),
"n"(IS_DOUBLE),
"n"(ZVAL_OFFSETOF_TYPE)
: "rax","cc", "memory");
#else
/*
* 'result' may alias with op1 or op2, so we need to
* ensure that 'result' is not updated until after we
* have read the values of op1 and op2.
*/
if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK)
&& (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) {
ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2));
} else {
ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2));
}
#endif
}
3.兩個數求平均值
(x&y)+ (x^y)>> 1
(x|y) - (x^y)>>1
簡單了解:
1.(A+B)/2用二進制辨別
((a1+b1)*2^1 + (a2+b2)*2^2 + (a3+b3)*2^3+ (a4+b4)*2^n)/2
2.即計算系數平均值相加即可,可簡化為計算(a1+b1)/2
3.對于二進制,隻有以下四種情況
a1 b1
1 1 // 相加除2為1,與運算和或運算均可滿足,但是2,3中情況或運算也會為1,是以需要減去
1 0 // 相加除2為0.5,先異或右移可以滿足
0 1 // 相加除2為0.5,先異或右移可以滿足
0 0 // 相加除2還是0,無需處理
4.筆記位址
d4 變量存儲