Current File : /home/pacjaorg/public_html/km/libraries/vendor/phpseclib/bcmath_compat/src/BCMath.php |
<?php
/**
* BCMath Emulation Class
*
* PHP version 5 and 7
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2019 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace bcmath_compat;
use phpseclib3\Math\BigInteger;
/**
* BCMath Emulation Class
*
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class BCMath
{
/**
* Default scale parameter for all bc math functions
*/
private static $scale;
/**
* Set or get default scale parameter for all bc math functions
*
* Uses the PHP 7.3+ behavior
*
* @var int $scale optional
*/
private static function scale($scale = null)
{
if (isset($scale)) {
self::$scale = (int) $scale;
}
return self::$scale;
}
/**
* Formats numbers
*
* Places the decimal place at the appropriate place, adds trailing 0's as appropriate, etc
*
* @var string $x
* @var int $scale
* @var int $pad
* @var boolean $trim
*/
private static function format($x, $scale, $pad)
{
$sign = self::isNegative($x) ? '-' : '';
$x = str_replace('-', '', $x);
if (strlen($x) != $pad) {
$x = str_pad($x, $pad, '0', STR_PAD_LEFT);
}
$temp = $pad ? substr_replace($x, '.', -$pad, 0) : $x;
$temp = explode('.', $temp);
if ($temp[0] == '') {
$temp[0] = '0';
}
if (isset($temp[1])) {
$temp[1] = substr($temp[1], 0, $scale);
$temp[1] = str_pad($temp[1], $scale, '0');
} elseif ($scale) {
$temp[1] = str_repeat('0', $scale);
}
$result = rtrim(implode('.', $temp), '.');
if ($sign == '-' && preg_match('#^0\.?0*$#', $result)) {
$sign = '';
}
return $sign . $result;
}
/**
* Negativity Test
*
* @var BigInteger $x
*/
private static function isNegative($x)
{
return $x->compare(new BigInteger()) < 0;
}
/**
* Add two arbitrary precision numbers
*
* @var string $x
* @var string $y
* @var int $scale
* @var int $pad
*/
private static function add($x, $y, $scale, $pad)
{
$z = $x->add($y);
return self::format($z, $scale, $pad);
}
/**
* Subtract one arbitrary precision number from another
*
* @var string $x
* @var string $y
* @var int $scale
* @var int $pad
*/
private static function sub($x, $y, $scale, $pad)
{
$z = $x->subtract($y);
return self::format($z, $scale, $pad);
}
/**
* Multiply two arbitrary precision numbers
*
* @var string $x
* @var string $y
* @var int $scale
* @var int $pad
*/
private static function mul($x, $y, $scale, $pad)
{
if ($x == '0' || $y == '0') {
$r = '0';
if ($scale) {
$r.= '.' . str_repeat('0', $scale);
}
return $r;
}
$z = $x->abs()->multiply($y->abs());
$result = self::format($z, $scale, 2 * $pad);
$sign = (self::isNegative($x) ^ self::isNegative($y)) && !preg_match('#^0\.?0*$#', $result) ? '-' : '';
return $sign . $result;
}
/**
* Divide two arbitrary precision numbers
*
* @var string $x
* @var string $y
* @var int $scale
* @var int $pad
*/
private static function div($x, $y, $scale, $pad)
{
if ($y == '0') {
// < PHP 8.0 triggered a warning
// >= PHP 8.0 throws an exception
throw new \DivisionByZeroError('Division by zero');
}
$temp = '1' . str_repeat('0', $scale);
$temp = new BigInteger($temp);
list($q) = $x->multiply($temp)->divide($y);
return self::format($q, $scale, $scale);
}
/**
* Get modulus of an arbitrary precision number
*
* Uses the PHP 7.2+ behavior
*
* @var string $x
* @var string $y
* @var int $scale
* @var int $pad
*/
private static function mod($x, $y, $scale, $pad)
{
if ($y == '0') {
// < PHP 8.0 triggered a warning
// >= PHP 8.0 throws an exception
throw new \DivisionByZeroError('Division by zero');
}
list($q) = $x->divide($y);
$z = $y->multiply($q);
$z = $x->subtract($z);
return self::format($z, $scale, $pad);
}
/**
* Compare two arbitrary precision numbers
*
* @var string $x
* @var string $y
* @var int $scale
* @var int $pad
*/
private static function comp($x, $y, $scale, $pad)
{
$x = new BigInteger($x[0] . substr($x[1], 0, $scale));
$y = new BigInteger($y[0] . substr($y[1], 0, $scale));
return $x->compare($y);
}
/**
* Raise an arbitrary precision number to another
*
* Uses the PHP 7.2+ behavior
*
* @var string $x
* @var string $y
* @var int $scale
* @var int $pad
*/
private static function pow($x, $y, $scale, $pad)
{
if ($y == '0') {
$r = '1';
if ($scale) {
$r.= '.' . str_repeat('0', $scale);
}
return $r;
}
$min = defined('PHP_INT_MIN') ? PHP_INT_MIN : ~PHP_INT_MAX;
if (bccomp($y, PHP_INT_MAX) > 0 || bccomp($y, $min) <= 0) {
throw new \ValueError('bcpow(): Argument #2 ($exponent) is too large');
}
$sign = self::isNegative($x) ? '-' : '';
$x = $x->abs();
$r = new BigInteger(1);
for ($i = 0; $i < abs($y); $i++) {
$r = $r->multiply($x);
}
if ($y < 0) {
$temp = '1' . str_repeat('0', $scale + $pad * abs($y));
$temp = new BigInteger($temp);
list($r) = $temp->divide($r);
$pad = $scale;
} else {
$pad*= abs($y);
}
return $sign . self::format($r, $scale, $pad);
}
/**
* Raise an arbitrary precision number to another, reduced by a specified modulus
*
* @var string $x
* @var string $e
* @var string $n
* @var int $scale
* @var int $pad
*/
private static function powmod($x, $e, $n, $scale, $pad)
{
if ($e[0] == '-' || $n == '0') {
// < PHP 8.0 returned false
// >= PHP 8.0 throws an exception
throw new \ValueError('bcpowmod(): Argument #2 ($exponent) must be greater than or equal to 0');
}
if ($n[0] == '-') {
$n = substr($n, 1);
}
if ($e == '0') {
return $scale ?
'1.' . str_repeat('0', $scale) :
'1';
}
$x = new BigInteger($x);
$e = new BigInteger($e);
$n = new BigInteger($n);
$z = $x->powMod($e, $n);
return $scale ?
"$z." . str_repeat('0', $scale) :
"$z";
}
/**
* Get the square root of an arbitrary precision number
*
* @var string $n
* @var int $scale
* @var int $pad
*/
private static function sqrt($n, $scale, $pad)
{
// the following is based off of the following URL:
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Decimal_(base_10)
if (!is_numeric($n)) {
return '0';
}
$temp = explode('.', $n);
$decStart = ceil(strlen($temp[0]) / 2);
$n = implode('', $temp);
if (strlen($n) % 2) {
$n = "0$n";
}
$parts = str_split($n, 2);
$parts = array_map('intval', $parts);
$i = 0;
$p = 0; // for the first step, p = 0
$c = $parts[$i];
$result = '';
while (true) {
// determine the greatest digit x such that x(20p+x) <= c
for ($x = 1; $x <= 10; $x++) {
if ($x * (20 * $p + $x) > $c) {
$x--;
break;
}
}
$result.= $x;
$y = $x * (20 * $p + $x);
$p = 10 * $p + $x;
$c = 100 * ($c - $y);
if (isset($parts[++$i])) {
$c+= $parts[$i];
}
if ((!$c && $i >= $decStart) || $i - $decStart == $scale) {
break;
}
if ($decStart == $i) {
$result.= '.';
}
}
$result = explode('.', $result);
if (isset($result[1])) {
$result[1] = str_pad($result[1], $scale, '0');
} elseif ($scale) {
$result[1] = str_repeat('0', $scale);
}
return implode('.', $result);
}
/**
* __callStatic Magic Method
*
* @var string $name
* @var array $arguments
*/
public static function __callStatic($name, $arguments)
{
static $params = [
'add' => 3,
'comp' => 3,
'div' => 3,
'mod' => 3,
'mul' => 3,
'pow' => 3,
'powmod' => 4,
'scale' => 1,
'sqrt' => 2,
'sub' => 3
];
if (count($arguments) < $params[$name] - 1) {
$min = $params[$name] - 1;
throw new \ArgumentCountError("bc$name() expects at least $min parameters, " . func_num_args() . " given");
}
if (count($arguments) > $params[$name]) {
$str = "bc$name() expects at most {$params[$name]} parameters, " . func_num_args() . " given";
throw new \ArgumentCountError($str);
}
$numbers = array_slice($arguments, 0, $params[$name] - 1);
$ints = [];
switch ($name) {
case 'pow':
$ints = array_slice($numbers, count($numbers) - 1);
$numbers = array_slice($numbers, 0, count($numbers) - 1);
$names = ['exponent'];
break;
case 'powmod':
$ints = $numbers;
$numbers = [];
$names = ['base', 'exponent', 'modulus'];
break;
case 'sqrt':
$names = ['num'];
break;
default:
$names = ['num1', 'num2'];
}
foreach ($ints as $i => &$int) {
if (!is_numeric($int)) {
$int = '0';
}
$pos = strpos($int, '.');
if ($pos !== false) {
$int = substr($int, 0, $pos);
throw new \ValueError("bc$name(): Argument #2 (\$$names[$i]) cannot have a fractional part");
}
}
foreach ($numbers as $i => $arg) {
$num = $i + 1;
switch (true) {
case is_bool($arg):
case is_numeric($arg):
case is_string($arg):
case is_object($arg) && method_exists($arg, '__toString'):
if (!is_bool($arg) && !is_numeric("$arg")) {
throw new \ValueError("bc$name: bcmath function argument is not well-formed");
}
break;
// PHP >= 8.1 has deprecated the passing of nulls to string parameters
case is_null($arg):
$error = "bc$name(): Passing null to parameter #$num (\$$names[$i]) of type string is deprecated";
trigger_error($error, E_USER_DEPRECATED);
break;
default:
$type = is_object($arg) ? get_class($arg) : gettype($arg);
$error = "bc$name(): Argument #$num (\$$names[$i]) must be of type string, $type given";
throw new \TypeError($error);
}
}
if (!isset(self::$scale)) {
$scale = ini_get('bcmath.scale');
self::$scale = $scale !== false ? max(intval($scale), 0) : 0;
}
$scale = isset($arguments[$params[$name] - 1]) ? $arguments[$params[$name] - 1] : self::$scale;
switch (true) {
case is_bool($scale):
case is_numeric($scale):
case is_string($scale) && preg_match('#0-9\.#', $scale[0]):
break;
default:
$type = is_object($arg) ? get_class($arg) : gettype($arg);
$str = "bc$name(): Argument #$params[$name] (\$scale) must be of type ?int, string given";
throw new \TypeError($str);
}
$scale = (int) $scale;
if ($scale < 0) {
throw new \ValueError("bc$name(): Argument #$params[$name] (\$scale) must be between 0 and 2147483647");
}
$pad = 0;
foreach ($numbers as &$num) {
if (is_bool($num)) {
$num = $num ? '1' : '0';
} elseif (!is_numeric($num)) {
$num = '0';
}
$num = explode('.', $num);
if (isset($num[1])) {
$pad = max($pad, strlen($num[1]));
}
}
switch ($name) {
case 'add':
case 'sub':
case 'mul':
case 'div':
case 'mod':
case 'pow':
foreach ($numbers as &$num) {
if (!isset($num[1])) {
$num[1] = '';
}
$num[1] = str_pad($num[1], $pad, '0');
$num = new BigInteger($num[0] . $num[1]);
}
break;
case 'comp':
foreach ($numbers as &$num) {
if (!isset($num[1])) {
$num[1] = '';
}
$num[1] = str_pad($num[1], $pad, '0');
}
break;
case 'sqrt':
$numbers = [$arguments[0]];
}
$arguments = array_merge($numbers, $ints, [$scale, $pad]);
return call_user_func_array('self::' . $name, $arguments);
}
}