class Math {
public static function base62_encode ($num, $code= 0) {
if ($num === '' || !is_bigint($num))
return FALSE;
$code= $code < 0 ? -$code : $code;
$ni= intval($num);
if ($ni < PHP_INT_MAX)
return self::base62_encode_int($ni, $code);
$spliter= 916132832; // 62 ^ 5
$parts= self::divide_int($num, $spliter);
$res= '';
while ($parts[0] > 0) {
$cur= self::base62_encode_int(intval($parts[1]), $code);
while (strlen($cur) < 5)
$cur= self::base62_encode_int(0, $code).$cur;
$res= $cur.$res;
$parts= self::divide_int($parts[0], $spliter);
}
return self::base62_encode_int(intval($parts[1]), $code).$res;
}
public static function base62_decode ($str, $code= 0) {
$code= $code < 0 ? -$code : $code;
$code= $code % 62;
$ret= 0;
for ($i= 0, $l= strlen($str); $i < $l; $i++) {
$cval= ord($str[$i]);
if (ctype_digit($str[$i]))
$cval-= ord('0');
elseif (ctype_upper($str[$i]))
$cval-= ord('A') - 10;
elseif (ctype_lower($str[$i]))
$cval-= ord('a') - 36;
else
return -1;
$val= ($cval >= $code ? 0 : 62) + $cval - $code;
$ret= self::add62digit($ret, $val);
}
return $ret;
}
public static function base36_encode ($num, $code= 0) {
if ($num === '' || !is_bigint($num))
return FALSE;
$code= $code < 0 ? -$code : $code;
$ni= intval($num);
if ($ni < PHP_INT_MAX)
return self::base36_encode_int($ni, $code);
$spliter= 60466176; // 36 ^ 5
$parts= self::divide_int($num, $spliter);
$res= '';
while ($parts[0] > 0) {
$cur= self::base36_encode_int(intval($parts[1]), $code);
while (strlen($cur) < 5)
$cur= self::base36_encode_int(0, $code).$cur;
$res= $cur.$res;
$parts= self::divide_int($parts[0], $spliter);
}
return self::base36_encode_int(intval($parts[1]), $code).$res;
}
public static function base36_decode ($str, $code= 0) {
$code= $code < 0 ? -$code : $code;
$code= $code % 36;
$ret= 0;
for ($i= 0, $l= strlen($str); $i < $l; $i++) {
$cval= ord(strtoupper($str[$i]));
if (ctype_digit($str[$i]))
$cval-= ord('0');
elseif (ctype_upper($str[$i]))
$cval-= ord('A') - 10;
else
return -1;
$val= ($cval >= $code ? 0 : 36) + $cval - $code;
$ret= self::add36digit($ret, $val);
}
return $ret;
}
public static function compare_int($a, $b) {
if ($a === '' || $b === '' || !is_bigint($a) || !is_bigint($b))
return FALSE;
$ai= intval($a);
$bi= intval($b);
if ($ai < PHP_INT_MAX && $bi < PHP_INT_MAX)
return $ai < $bi ? -1 : ($ai > $bi ? 1 : 0);
$a= ltrim(trim($a, " \t\n\r"), '0');
$b= ltrim(trim($b, " \t\n\r"), '0');
$al= strlen($a);
$bl= strlen($b);
if ($al < $bl)
return -1;
else if ($al > $bl)
return 1;
for ($i= 0; $i < $al; $i++) {
$ai= intval($a[$i]);
$bi= intval($b[$i]);
if ($ai < $bi)
return -1;
else if ($ai > $bi)
return 1;
}
return 0;
}
public static function divide_int ($dividend, $divisor) {
if ($dividend === '' || $divisor === '' || !is_bigint($dividend) || !is_bigint($divisor))
return FALSE;
$dividend= ltrim(trim($dividend, " \t\n\r"), '0');
$divisor= ltrim(trim($divisor, " \t\n\r"), '0');
$c= self::compare_int($dividend, $divisor);
if ($c < 0)
return array ('0', $dividend);
else if (!$c)
return array ('1', '0');
$res= '';
$dl= strlen($divisor);
$cur= substr($dividend, 0, $dl);
if (intval('9'.$divisor) < PHP_INT_MAX) {
$divisor= intval($divisor);
for ($i= 0, $l= strlen($dividend); $i + $dl <= $l; $i++) {
$d= 0;
if (intval($cur) >= $divisor) {
$res.= (string)((int)($cur / $divisor));
$cur= (string)($cur % $divisor);
} else
$res.= '0';
if ($i + $dl < $l)
$cur.= $dividend[$i + $dl];
}
} else {
for ($i= 0, $l= strlen($dividend); $i + $dl <= $l; $i++) {
$d= 0;
$c= self::compare_int($cur, $divisor);
while ($c >= 0) {
for ($j= 0; $j < $dl; $j++) {
$cl= strlen($cur);
if ($cur[$cl - $j - 1] >= $divisor[$dl - $j - 1])
$cur[$cl - $j - 1]= $cur[$cl - $j - 1] - $divisor[$dl - $j - 1];
else {
for ($k= $j + 1; $k < $cl; $k++)
if ($cur[$cl - $k - 1] !== '0') {
$cur[$cl - $k - 1]= $cur[$cl - $k - 1] - 1;
break;
} else
$cur[$cl - $k - 1]= '9';
$cur[$cl - $j - 1]= 10 + $cur[$cl - $j - 1] - $divisor[$dl - $j - 1];
}
}
$d++;
$c= self::compare_int($cur, $divisor);
}
$res.= (string)$d;
if ($i + $dl < $l)
$cur.= $dividend[$i + $dl];
}
}
$res= ltrim($res, '0');
$cur= ltrim($cur, '0');
return array ($res ? $res : '0', $cur ? $cur : '0');
}
private static function base62_encode_int ($num, $code= 0) {
$code= $code < 0 ? -$code : $code;
$ret= '';
while ($num >= 0) {
$val= $num % 62;
$cval= ($val + $code) % 62;
if ($cval < 10)
$ret.= chr(ord('0') + $cval);
elseif ($cval < 36)
$ret.= chr(ord('A') + $cval - 10);
else
$ret.= chr(ord('a') + $cval - 36);
if ($num < 62)
return strrev($ret);
else
$num= ($num - $val) / 62;
}
return $ret;
}
private static function add62digit($num, $val) {
if (intval($num) <= ((PHP_INT_MAX - 62) / 62))
return (string)(intval($num) * 62 + intval($val));
$ret= '';
$num= (string)$num;
$val= (string)$val;
for ($i= 0, $cur= 0, $nl= strlen($num), $vl= strlen($val); $i <= $nl; $i++) {
if ($i < $nl)
$cur+= $num[$nl - $i - 1] * 2;
if ($i < $vl)
$cur+= $val[$vl - $i - 1];
if ($i)
$cur+= $num[$nl - $i] * 6;
$ret= ($cur % 10).$ret;
$cur= (int)($cur / 10);
}
if ($cur)
$ret= $cur.$ret;
return $ret;
}
private static function base36_encode_int ($num, $code= 0) {
$code= $code < 0 ? -$code : $code;
$ret= '';
while ($num >= 0) {
$val= $num % 36;
$cval= ($val + $code) % 36;
if ($cval < 10)
$ret.= chr(ord('0') + $cval);
else
$ret.= chr(ord('A') + $cval - 10);
if ($num < 36)
return strrev($ret);
else
$num= ($num - $val) / 36;
}
return $ret;
}
private static function add36digit($num, $val) {
if (intval($num) <= ((PHP_INT_MAX - 36) / 36))
return (string)(intval($num) * 36 + intval($val));
$ret= '';
$num= (string)$num;
$val= (string)$val;
for ($i= 0, $cur= 0, $nl= strlen($num), $vl= strlen($val); $i <= $nl; $i++) {
if ($i < $nl)
$cur+= $num[$nl - $i - 1] * 6;
if ($i < $vl)
$cur+= $val[$vl - $i - 1];
if ($i)
$cur+= $num[$nl - $i] * 3;
$ret= ($cur % 10).$ret;
$cur= (int)($cur / 10);
}
if ($cur)
$ret= $cur.$ret;
return $ret;
}
}