请注意不要在字符串中使用/包含空格。我花了一些时间才找到某些高级计算中的错误!
<?php
echo bcadd("1", "2"); // 3
echo bcadd("1", "2 "); // 1
echo bcadd("1", " 2"); // 1
?>
请注意不要在字符串中使用/包含空格。我花了一些时间才找到某些高级计算中的错误!
<?php
echo bcadd("1", "2"); // 3
echo bcadd("1", "2 "); // 1
echo bcadd("1", " 2"); // 1
?>
以下是一些将大十六进制数从大十进制数转换为大十进制数的有用函数
<?php
public static function bchexdec($hex) {
if(strlen($hex) == 1) {
return hexdec($hex);
} else {
$remain = substr($hex, 0, -1);
$last = substr($hex, -1);
return bcadd(bcmul(16, bchexdec($remain)), hexdec($last));
}
}
public static function bcdechex($dec) {
$last = bcmod($dec, 16);
$remain = bcdiv(bcsub($dec, $last), 16);
if($remain == 0) {
return dechex($last);
} else {
return bcdechex($remain).dechex($last);
}
}
如果你也被像这样的难以理解的代码搞糊涂了
<?php
$a = "3";
$b = "5";
bcadd(bcmod(bcadd(bcdiv(bcsqrt(bcadd(7, bcpow($a, 2))), 4), $b), "4"), "0.5"); // 我可能在某处犯了一个错误
?>
你可以考虑使用我的函数,它使上面的例子看起来像
<?php
bc("(sqrt(7 + $1^2) / 4 + $2) % 4 + 0.5", "3", "5");
?>
代码
<?php
function bc() {
$functions = 'sqrt';
// 以 | 分隔的函数列表
// sqrt 指的是 bcsqrt 等
// 函数必须正好接受一个参数
$argv = func_get_args();
$string = str_replace(' ', '', '('.$argv[0].')');
$string = preg_replace('/\$([0-9\.]+)/e', '$argv[$1]', $string);
while (preg_match('/(('.$functions.')?)\(([^\)\(]*)\)/', $string, $match)) {
while (
preg_match('/([0-9\.]+)(\^)([0-9\.]+)/', $match[3], $m) ||
preg_match('/([0-9\.]+)([\*\/\%])([0-9\.]+)/', $match[3], $m) ||
preg_match('/([0-9\.]+)([\+\-])([0-9\.]+)/', $match[3], $m)
) {
switch($m[2]) {
case '+': $result = bcadd($m[1], $m[3]); break;
case '-': $result = bcsub($m[1], $m[3]); break;
case '*': $result = bcmul($m[1], $m[3]); break;
case '/': $result = bcdiv($m[1], $m[3]); break;
case '%': $result = bcmod($m[1], $m[3]); break;
case '^': $result = bcpow($m[1], $m[3]); break;
}
$match[3] = str_replace($m[0], $result, $match[3]);
}
if (!empty($match[1]) && function_exists($func = 'bc'.$match[1])) {
$match[3] = $func($match[3]);
}
$string = str_replace($match[0], $match[3], $string);
}
return $string;
}
?>
请注意,您必须使用 bcscale() 定义比例。
我修改了这些泰勒级数展开式,以便为一些物理作业制作图表。我不认为您会想用 PHP 做任何真正的科学工作……但为什么不呢?我计划在不久的将来实现一个 spigot 算法或类似算法来生成圆周率。
<?
// 任意精度正弦和余弦函数
// 作者:tom boothby
// 免费供任何用途使用
function bcfact($n) {
$r = $n--;
while($n>1) $r=bcmul($r,$n--);
return $r;
}
function bcsin($a) {
$or= $a;
$r = bcsub($a,bcdiv(bcpow($a,3),6));
$i = 2;
while(bccomp($or,$r)) {
$or=$r;
switch($i%2) {
case 0: $r = bcadd($r,bcdiv(bcpow($a,$i*2+1),bcfact($i*2+1))); break;
default: $r = bcsub($r,bcdiv(bcpow($a,$i*2+1),bcfact($i*2+1))); break;
}
$i++;
}
return $r;
}
function bccos($a) {
$or= $a;
$r = bcsub(1,bcdiv(bcpow($a,2),2));
$i = 2;
while(bccomp($or,$r)) {
$or=$r;
switch($i%2) {
case 0: $r = bcadd($r,bcdiv(bcpow($a,$i*2),bcfact($i*2))); break;
default: $r = bcsub($r,bcdiv(bcpow($a,$i*2),bcfact($i*2))); break;
}
$i++;
}
return $r;
}
?>
上面脚本的简化版本
function dec2base($dec, $digits) {
$value = "";
$base = strlen($digits);
while($dec>$base-1) {
$rest = $dec % $base;
$dec = $dec / $base;
$value = $digits[$rest].$value;
}
$value = $digits[intval($dec)].$value;
return (string) $value;
}
function base2dec($value, $digits) {
$value = strtoupper($value);
$base = strlen($digits);
$size = strlen($value);
$dec = '0';
for ($loop = 0; $loop<$size; $loop++) {
$element = strpos($digits,$value[$loop]);
$power = pow($base,$size-$loop-1);
$dec += $element * $power;
}
return (string) $dec;
}
$digits = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
echo dec2base('1000', $digits);
/*
* 即使在高分辨率下也能非常快速地计算 ln(x)
* 使用标准 log() 函数来优化
* ln(1+x) = x - x*x/2 + x*x*x/3 - ... 的收敛性
*
* 例子
* bcscale(1000);
* $x = bcln("1000000");
*
* 结果
* $x = 13.81551055796427410410794872810618524560660893...
* 在 0.9 秒内,进行了 80 次迭代
*
* @author Klaus Meissen,德国
* @license 公共领域
*/
function bcln($value) // value > 0
{
$m = (string)log($value);
$x = bcsub(bcdiv($value,bcexp($m)),"1");
$res = "0";
$xpow = "1";
$i=0;
do
{
$i++;
$xpow = bcmul($xpow,$x);
$sum = bcdiv($xpow, $i);
if ($i%2==1)
{
$res = bcadd($res, $sum);
}else{
$res = bcsub($res, $sum);
}
}
while (bccomp($sum, '0'));
return bcadd($res,$m);
}
我发现我的 base2dec() 函数里有一个小错误
如果您想为您的进制转换指定其他数字,则应删除行“if($base<37) $value=strtolower($value);”。将其更改为以下方式
if(!$digits) {
$digits=digits($base);
if($base<37) {
$value=strtolower($value);
}
}
另一个使用这些函数的例子是生成一个会话密钥,为临时文件命名或其他操作
srand((double) microtime()*1000000);
$id=uniqid(rand(10,999));
$mykey=dec2base(base2dec($id,16),64);
$mykey 是一个 base64 值,它适合通过 URL 传递,而且比 MD5 字符串更短(它将始终为 11 个字符长)。如果您需要更安全的东西,只需在 digits() 函数中将 64 个数字打乱即可。
希望您喜欢它。
致敬,
Edemilson Lima
我花了一些时间寻找如何生成一个大的随机数,最后我决定直接从 /dev/urandom 读取
我知道这只是一个 *nix 解决方案,但我认为它可能对其他人有用。
值 $size 是以位为单位的大小,如果您想以字节为单位的大小,可以对其进行大幅简化,但位对我需要的东西更有用。
<?php
function bcrand($size)
{
$filename = "/dev/urandom";
$handle = fopen($filename, "r");
$bin_urand = fread($handle, ceil($size/8.0));
fclose($handle);
$mask = (($size % 8 < 5) ? '0' : '') . dechex(bindec(str_repeat('1', $size % 8))) . str_repeat('FF', floor($size/8));
$binmask = pack("H*", $mask);
$binrand = $binmask & $bin_urand;
$hexnumber = unpack("H*", $binrand);
$hexnumber = $hexnumber[''];
$numlength = strlen($hexnumber);
$decnumber = 0;
for($x = 1; $x <= $numlength; $x++)
{
$place = $numlength - $x;
$operand = hexdec(substr($hexnumber,$place,1));
$exponent = bcpow(16,$x-1);
$decValue = bcmul($operand, $exponent);
$decnumber = bcadd($decValue, $decnumber);
}
return $decnumber;
}
?>
如果您的计算涉及用户输入,请不要忘记设置输入范围和/或长度的限制,因为非常大的数字需要密集的处理,您可能会达到服务器无法再进行处理的程度。
与其他 bc 函数一样,您无法信任最后几位数字,但其他一切似乎都已检查。如果您想将此用于任何重要事项,您可能需要在使用前根据其他来源验证 pi。此函数在 329 次迭代中计算了 pi 的 100 位小数 - 速度并不快(每次迭代都会调用下面的阶乘函数两次),因此我尽量避免多次调用它。
<?
// 高精度 pi 近似值
// 作者 tom boothby
// 免费用于任何用途
function bcpi() {
$r=2;
$i=0;
$or=0;
while(bccomp($or,$r)) {
$i++;
$or=$r;
$r = bcadd($r,bcdiv(bcmul(bcpow(bcfact($i),2),
bcpow(2,$i+1)),bcfact(2*$i+1)));
}
return $r;
}
?>
上面简化示例的一点说明:您可以仅使用数学运算符来执行基数转换而不使用 BCMath 函数,但您将无法管理非常大的值或使用字符串来压缩或混淆数据。如果您的系统中安装了 BCMath,那么使用它来做这件事是值得的。
BCMath 函数的良好用途
以下函数可以将任何基数(从 2 到 256)的数字转换为其十进制值,反之亦然。
// 将十进制值转换为任何其他基数值
function dec2base($dec,$base,$digits=FALSE) {
if($base<2 or $base>256) die("Invalid Base: ".$base);
bcscale(0);
$value="";
if(!$digits) $digits=digits($base);
while($dec>$base-1) {
$rest=bcmod($dec,$base);
$dec=bcdiv($dec,$base);
$value=$digits[$rest].$value;
}
$value=$digits[intval($dec)].$value;
return (string) $value;
}
// 将另一个基数值转换为其十进制值
function base2dec($value,$base,$digits=FALSE) {
if($base<2 or $base>256) die("Invalid Base: ".$base);
bcscale(0);
if($base<37) $value=strtolower($value);
if(!$digits) $digits=digits($base);
$size=strlen($value);
$dec="0";
for($loop=0;$loop<$size;$loop++) {
$element=strpos($digits,$value[$loop]);
$power=bcpow($base,$size-$loop-1);
$dec=bcadd($dec,bcmul($element,$power));
}
return (string) $dec;
}
function digits($base) {
if($base>64) {
$digits="";
for($loop=0;$loop<256;$loop++) {
$digits.=chr($loop);
}
} else {
$digits ="0123456789abcdefghijklmnopqrstuvwxyz";
$digits.="ABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
}
$digits=substr($digits,0,$base);
return (string) $digits;
}
上面 digits() 函数的目的是提供将用作您想要的基数的数字的字符。注意:您可以使用任何字符来进行基数转换,但是当您再次转换为十进制基数时,您需要使用相同的字符,否则您将得到另一个意外的结果。
正如“benjcarson at digitaljunkies dot ca”(https://php.net/ref.bc.php#23038)在前两条评论中提到的,bcmath 不接受指数表示法。
此外,如果您直接将浮点数提供给 bcmath 函数,您可能会遇到其他问题。
请考虑以下示例
<?php
bcscale(1);
$a = 0.8;
$b = 0.7;
var_dump((string) $a); // string(3) "0.8"
var_dump((string) $b); // string(3) "0.a"
var_dump(bcadd($a, $b)); // string(3) "1.5"
setLocale(LC_ALL, 'fr_BE.UTF-8');
var_dump((string) $a); // string(3) "0,8" --> 注意逗号
var_dump((string) $b); // string(3) "0,7" --> 注意逗号
var_dump(bcadd($a, $b)); // string(3) "0.0"
?>
传递给 bcadd() 函数的浮点数会使用本地化的小数分隔符自动转换为字符串。但是,bcmath 函数始终使用句点,这会导致最后一个结果不正确。
下面是一个将浮点数正确转换为字符串的函数。它处理小数分隔符和指数表示法。它还保留精度而不漂移(例如 1.0 不会变成 0.99999...)。
<?php
/**
* 将数字转换为不带 E 表示法且不丢失精度的与区域设置无关的字符串
*
* @param int/float/double $fNumber 要转换的数字。
* @return string 与区域设置无关的转换后的数字。
*/
function bcconv($fNumber)
{
$sAppend = '';
$iDecimals = ini_get('precision') - floor(log10(abs($fNumber)));
if (0 > $iDecimals)
{
$fNumber *= pow(10, $iDecimals);
$sAppend = str_repeat('0', -$iDecimals);
$iDecimals = 0;
}
return number_format($fNumber, $iDecimals, '.', '').$sAppend;
}
?>
示例
<?php
setLocale(LC_ALL, 'fr_BE.UTF-8'); // 小数分隔符现在是逗号
$precision = ini_get('precision') + 2; // 应该给出 16
bcscale($precision);
$big = pow(10, $precision);
$small = 1 / $big;
var_dump(bcconv($big + $small)); // string(17) "10000000000000000"
var_dump(bcadd($big, $small)); // string(18) "0.0000000000000000"
var_dump(bcadd(bcconv($big), bcconv($small))); // string(34) "10000000000000000.0000000000000001"
?>
第一个结果的精度损失是由于 PHP 内部浮点数的表示方式。
第二个结果是错误的,因为本地化的小数分隔符。
最后,最后一个结果是正确的。
我用很多 BCMath 函数写了这个函数。它应该是 PHP 中速度最快的函数,可以将圆周率计算到任意精度,我的测试是在 8 秒内生成小数点后的 2000 位数字。我认为你不需要比这更多了。
<?php
// 使用高斯-勒让德算法的 bcpi 函数
// 作者:徐超 (Mgccl)
function bcpi($precision){
$limit = ceil(log($precision)/log(2))-1;
bcscale($precision+6);
$a = 1;
$b = bcdiv(1,bcsqrt(2));
$t = 1/4;
$p = 1;
while($n < $limit){
$x = bcdiv(bcadd($a,$b),2);
$y = bcsqrt(bcmul($a, $b));
$t = bcsub($t, bcmul($p,bcpow(bcsub($a,$x),2)));
$a = $x;
$b = $y;
$p = bcmul(2,$p);
++$n;
}
return bcdiv(bcpow(bcadd($a, $b),2),bcmul(4,$t),$precision);
}
?>
受 dawidgarus 实现的启发,这里是我的一个简单的 bc 数学助手,它不支持函数调用,但支持布尔比较,并且速度大约快了 40%。
<?php
function bc() {
$argv = func_get_args();
$string = str_replace(' ', '', "({$argv[0]})");
$operations = array();
if (strpos($string, '^') !== false) $operations[] = '\^';
if (strpbrk($string, '*/%') !== false) $operations[] = '[\*\/\%]';
if (strpbrk($string, '+-') !== false) $operations[] = '[\+\-]';
if (strpbrk($string, '<>!=') !== false) $operations[] = '<|>|=|<=|==|>=|!=|<>';
$string = preg_replace('/\$([0-9\.]+)/e', '$argv[$1]', $string);
while (preg_match('/\(([^\)\(]*)\)/', $string, $match)) {
foreach ($operations as $operation) {
if (preg_match("/([+-]{0,1}[0-9\.]+)($operation)([+-]{0,1}[0-9\.]+)/", $match[1], $m)) {
switch($m[2]) {
case '+': $result = bcadd($m[1], $m[3]); break;
case '-': $result = bcsub($m[1], $m[3]); break;
case '*': $result = bcmul($m[1], $m[3]); break;
case '/': $result = bcdiv($m[1], $m[3]); break;
case '%': $result = bcmod($m[1], $m[3]); break;
case '^': $result = bcpow($m[1], $m[3]); break;
case '==':
case '=': $result = bccomp($m[1], $m[3]) == 0; break;
case '>': $result = bccomp($m[1], $m[3]) == 1; break;
case '<': $result = bccomp($m[1], $m[3]) ==-1; break;
case '>=': $result = bccomp($m[1], $m[3]) >= 0; break;
case '<=': $result = bccomp($m[1], $m[3]) <= 0; break;
case '<>':
case '!=': $result = bccomp($m[1], $m[3]) != 0; break;
}
$match[1] = str_replace($m[0], $result, $match[1]);
}
}
$string = str_replace($match[0], $match[1], $string);
}
return $string;
}
?>
一些有用的 bcmath 函数
<?php
/*
* Computes the factoral (x!).
* @author Thomas Oldbury.
* @license Public domain.
*/
function bcfact($fact, $scale = 100)
{
if($fact == 1) return 1;
return bcmul($fact, bcfact(bcsub($fact, '1'), $scale), $scale);
}
/*
* Computes e^x, where e is Euler's constant, or approximately 2.71828.
* @author Thomas Oldbury.
* @license Public domain.
*/
function bcexp($x, $iters = 7, $scale = 100)
{
/* Compute e^x. */
$res = bcadd('1.0', $x, $scale);
for($i = 0; $i < $iters; $i++)
{
$res += bcdiv(bcpow($x, bcadd($i, '2'), $scale), bcfact(bcadd($i, '2'), $scale), $scale);
}
return $res;
}
/*
* Computes ln(x).
* @author Thomas Oldbury.
* @license Public domain.
*/
function bcln($a, $iters = 10, $scale = 100)
{
$result = "0.0";
for($i = 0; $i < $iters; $i++)
{
$pow = bcadd("1.0", bcmul($i, "2.0", $scale), $scale);
//$pow = 1 + ($i * 2);
$mul = bcdiv("1.0", $pow, $scale);
$fraction = bcmul($mul, bcpow(bcdiv(bcsub($a, "1.0", $scale), bcadd($a, "1.0", $scale), $scale), $pow, $scale), $scale);
$result = bcadd($fraction, $result, $scale);
}
$res = bcmul("2.0", $result, $scale);
return $res;
}
/*
* Computes a^b, where a and b can have decimal digits, be negative and/or very large.
* Also works for 0^0. Only able to calculate up to 10 digits. Quite slow.
* @author Thomas Oldbury.
* @license Public domain.
*/
function bcpowx($a, $b, $iters = 25, $scale = 100)
{
$ln = bcln($a, $iters, $scale);
return bcexp(bcmul($ln, $b, $scale), $iters, $scale);
}
$precision = 35;
echo "3^4.5, precision 15, iters 25 = " . bcpowx('3', '4.5', 25, $precision) . "\n";
echo "4.5^3, precision 15, iters 25 = " . bcpowx('4.5', '3', 25, $precision) . "\n";
echo "8^1/2, precision 15, iters 25 = " . bcpowx('8', '0.5', 25, $precision) . "\n";
echo "28^-1, precision 15, iters 25 = " . bcpowx('28', '-1', 25, $precision) . "\n";
echo "432^0, precision 15, iters 25 = " . bcpowx('432', '0', 25, $precision) . "\n";
echo "0^0, precision 15, iters 25 = " . bcpowx('0.0', '0', 25, $precision) . "\n";
echo "9^999, precision 15, iters 25 = " . bcpowx('9', '999', 25, $precision) . "\n";
echo "9^9999, precision 15, iters 25 = " . bcpowx('9', '9999', 25, $precision) . "\n";
echo "9^99999, precision 15, iters 25 = " . bcpowx('9', '99999', 25, $precision) . "\n";
echo "9^999999, precision 15, iters 25 = " . bcpowx('9', '999999', 25, $precision) . "\n";
echo "9^9999999, precision 15, iters 25 = " . bcpowx('9', '9999999', 25, $precision) . "\n";
echo "9^99999999, precision 15, iters 25 = " . bcpowx('9', '99999999', 25, $precision) . "\n";
echo "9^999999999, precision 15, iters 25 = " . bcpowx('9', '999999999', 25, $precision) . "\n";
echo "9^9999999999, precision 15, iters 25 = " . bcpowx('9', '9999999999', 25, $precision) . "\n";
echo "9^99999999999, precision 15, iters 25 = " . bcpowx('9', '99999999999', 25, $precision) . "\n";
echo "9^999999999999, precision 15, iters 25 = " . bcpowx('9', '999999999999', 25, $precision) . "\n";
?>
用于对 bc 字符串进行舍入的函数
<?php
function bcround($strval, $precision = 0) {
if (false !== ($pos = strpos($strval, '.')) && (strlen($strval) - $pos - 1) > $precision) {
$zeros = str_repeat("0", $precision);
return bcadd($strval, "0.{$zeros}5", $precision);
} else {
return $strval;
}
}
?>
以下是一个使用基本 bcMath 算术运算来计算任意精度的自然指数函数的函数。
示例
要计算 1.7 的指数函数,精确到小数点后 36 位
$y = bcExp("1.7", 36);
结果
4.331733759839529271053448625299468628
将返回变量 $y 中
注意
实际上,最后几位数字可能不准确,因为存在微小的舍入误差。如果您需要特定精度的结果,请始终计算比所需精度多 3-4 位小数。
自然指数函数的程序代码是
******************************************
函数 bcExp($xArg, $NumDecimals)
{
$x = Trim($xArg);
$PrevSum = $x - 1;
$CurrTerm = 1;
$CurrSum = bcAdd("1", $x, $NumDecimals);
$n = 1;
当 (bcComp($CurrSum, $PrevSum, $NumDecimals))
{
$PrevSum = $CurrSum;
$CurrTerm = bcDiv(bcMul($CurrTerm, $x, $NumDecimals), $n + 1, $NumDecimals);
$CurrSum = bcAdd($CurrSum, $CurrTerm, $NumDecimals);
$n++;
}
返回 $CurrSum;
}
下面的代码实现了标准舍入,即 5 或更高舍入,否则不舍入。BC 函数没有舍入函数,因此这里有一个简单的函数,它可以正常工作。与 round 的参数相同,除了它接受字符串并返回字符串以进行更多 BC 操作。
----------------
函数 roundbc($x, $p) {
$x = trim($x);
$data = explode(".",$x);
如果(substr($data[1],$p,1) >= "5") {
//生成加字符串。
$i=0;
$addString = "5";
当($i < $p) {
$addString = "0" . $addString;
$i++;
}//结束 while。
$addString = "." . $addString;
//现在将 addString 加到原始分数中。
$sum = bcadd($data[0] . "." . $data [1],$addString,$p+1);
//拆分结果。
$sumData = explode(".",$sum);
//现在,返回舍入后的数字的正确精度。
返回 $sumData[0] . "." . substr($sumData[1],0,$p);
} else {
//不要舍入值,并将原始值返回到所需的
//精度或更低。
返回 $data[0] . "." . substr($data[1],0,$p);
}//结束 if/else。
}//结束 roundbc。
糟糕,第一次发布的代码有误......抱歉。
对 pulstar at mail dot com 的条目进行修改 - digits() 函数可以更快地实现(从大字符串中删除换行符,并确保您没有遗漏任何字符!)
函数 digits2($base) {
如果($base < 64) {
返回 substr('0123456789abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ-_', 0, $base);
} else {
返回 substr("\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd
\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d
\x1e\x1f\x20!\x22#\x24%&'()*+,-./0123456789:;<=>
\x3f@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]
^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85
\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95
\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5
\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5
\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5
\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5
\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5
\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6
\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", 0, $base);
}
}
在我的基准测试中,对于 256 位数字,这大约快了 150 倍