ibelousov / math-exec
使用变量精度数字从字符串中评估表达式
2.0.0
2020-04-15 18:54 UTC
Requires
- php: >=7.2
- ext-bcmath: >=7.2
Requires (Dev)
- phpunit/phpunit: 6.*
This package is auto-updated.
Last update: 2024-09-07 20:52:57 UTC
README
MathExec 是一个用于解析和评估类似这样的数学表达式的 php 库
echo Evaluator::mathExec("5 ^ 2 + 36 / 2 - 2 * 0.5");
或者您可以准备一个表达式模板,然后在需要时通过提供所需的变量以指定的精度执行它
$evaluator = Evaluator::mathPrepare("a + 5 / 3 * b - c"); foreach([[1,2,3,4],[4,5,6,4],[7,8,9,0]] as $values) { $evaluator->exec(['a' => $values[0], 'b' => $values[1], 'c' => $values[2]], $values[3]); }
或者像这样
$a = 1.5E+2; $b = 18; return Evaluator::mathExec("$a * 4 + 30 * 2 + $b / 3");
这同样也是正确的
var_dump(Evaluator::mathExec("floor((0.7+0.1)*10)") == 8); // boolean true var_dump([floor((0.7+0.1)*10) == 8]); // boolean false
它利用 Pratt 解析器,并使用 ext-bcmath 扩展来评估操作。例如这个表达式
$a = 4; $b = 4; $c = 4; Evaluator::mathExec("$a + $b / $c", 40);
在内部转换为这样
bcadd($a, bcdiv($b, $c, 40), 40);
这样自然地编写表达式非常方便,无需使用 bcadd、bcdiv 等。
安装
使用包管理器 composer 安装它
composer install ibelousov/math-exec
用法
首先导入类 Evaluator
use \Ibelousov\MathExec\Evaluator\Evaluator;
支持的事物
// Root Evaluator::mathExec("\\2"); // "1.1892071150027210667174999705604759152929"
(您可以设置内部精度,例如这样
Evaluator::mathExec("\\2", 1000); // "1.1892071150027210667174999705604759152929720924638174130190022 // 2471946666822691715987078134453813767371603739477476921318606372 // 6361789847756785360862538017775070151511403557092273162342868889 // 9241754460719087105038499725591050098371044920154845735674580904 // 8399409309000349779590803848965884300504119871700937907982098462 // 5235373981281740818113780828552014842210060958932412445931035057 // 5191963029413832634742802798244080228008217292720586153666393704 // 0023820730854565306744771485988873345762718678381165470458727612 // 7111269988678434930175861424970170054131455143891998743766762178 // 5161783177987307048236318734734842180537156986842636482761056228 // 4779958628963329392816878747586560347379199645940075615444371574 // 1890303986971294306248625351734129153597531121544674615908647760 // 6517445957055930979119465756398917686972170262497475333629918606 // 5311570834936807698049481706074376847467855865282550141846497924 // 8909951563378299859508764353239662147789654791045418693466186139 // 614521856391702634160435422985610854932687"
默认情况下小数点后有 40 位)
// 乘法
Evaluator::mathExec("2 * 2", 0); // "4"
// 除法
Evaluator::mathExec("2 / 2", 0); // "1"
// Power Evaluator::mathExec("2 ^ 3", 0); // "8" (left and right should be whole numbers)
// Modul Evaluator::mathExec("7 % 2", 0); // "1"
// Whole division Evaluator::mathExec("3.1415 // 2", 0); // "1"
// Associativity Evaluator::mathExec("2 + 2 * 2", 0); // "6"
// Parenthesis Evaluator::mathExec("(2 + 2) * 2", 0); // "8"
// Float to string convertion number formats $a = 0.1415E-10; $b = 0.1415E-10; Evaluator::mathExec("$a * $b"); // "0.0000000000000000000002002225000000000000"
// comparison Evaluator::mathExec("4 ^ 128 > 4 ^ 64"); // "1"
Evaluator::mathExec("4 ^ 128 < 4 ^ 64"); // "0"
Evaluator::mathExec("4 ^ 64 + 1 >= 4 ^ 64"); // "1"
Evaluator::mathExec("4 ^ 64 <= 4 ^ 64"); // "1"
Evaluator::mathExec("4 == 4"); // "1"
Evaluator::mathExec("4 != 4"); // "0"
函数
Evaluator::mathExec("floor(3.1415)"); // "3"
Evaluator::mathExec("ceil(3.1415)"); // "4"
Evaluator::mathExec("format(ceil(3.1415) + floor(3.1415), 2)"); // "7.00"
您还可以添加自己的函数,例如这样
\Ibelousov\MathExec\Evaluator\BuiltinCollection::addBuiltin('inc', function($args) { $number_parts = explode('.', $args[0]->value); $precision = isset($number_parts[1]) ? strlen($number_parts[1]) : 0; return new \Ibelousov\MathExec\Evaluator\NumberObj(bcadd($args[0]->value, '1', $precision)); }); echo Evaluator::mathExec('inc(inc(2))',40);
请谨慎使用
数字的内部表示
例如,如果您调用这个
Evaluator::mathExec("4/4 == 6/5", 0);
它评估为 1,因为在这种情况下内部表示是 0,并且当您进行 6/5 的除法时,您得到 1 而不是 1.2
为了准确比较数字,您应该适当地设置精度。在上面的例子中,您应该这样做,以正确比较数字
Evaluator::mathExec("4/4 == 6/5", 1);
转换为原生 PHP 数字格式
(int)Evaluator::mathExec((string)PHP_INT_MAX); // Evaluates to PHP_INT_MAX number
(int)Evaluator::mathExec((string)PHP_INT_MIN); // Evaluates to PHP_INT_MIN number
(float)Evaluator::mathExec('\\2 + \\2', 30); // cuts result 2.8284271247461900976033774484193961571392 to 2.8284271247462
(float)Evaluator::mathExec((string)PHP_FLOAT_MIN); // Evaluates to PHP_FLOAT_MIN number
(float)Evaluator::mathExec('1.7976931348623157E+308'); // Evaluates to PHP_FLOAT_MAX. Today i have no time to figure out, why is // (float)\Ibelousov\MathExec\Evaluator\Evaluator::mathExec((string)PHP_FLOAT_MAX) // doesnt return correct value, but it is a fact
其他转换,例如这样
(int)Evaluator::mathExec((string)PHP_INT_MIN . ' - 1');
是不可预测的
为了以高精度和/或大数字评估和比较数字,您应该更喜欢将值存储在字符串中而不是将它们转换为 float 或 int。
REPL
您可以使用 REPL 测试表达式评估
$ ./vendor/ibelousov/math-exec/src/REPL.php >> 4+4*4 20 Executed in 0.0025420188903809s.
贡献
欢迎拉取请求。对于重大更改,请首先打开一个问题来讨论您想要更改的内容。
请确保适当地更新测试。