[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/phpseclib/bcmath_compat/src/ -> BCMath.php (source)

   1  <?php
   2  
   3  /**
   4   * BCMath Emulation Class
   5   *
   6   * PHP version 5 and 7
   7   *
   8   * @author    Jim Wigginton <[email protected]>
   9   * @copyright 2019 Jim Wigginton
  10   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  11   */
  12  
  13  namespace bcmath_compat;
  14  
  15  use phpseclib3\Math\BigInteger;
  16  
  17  /**
  18   * BCMath Emulation Class
  19   *
  20   * @author  Jim Wigginton <[email protected]>
  21   * @access  public
  22   */
  23  abstract class BCMath
  24  {
  25      /**
  26       * Default scale parameter for all bc math functions
  27       */
  28      private static $scale;
  29  
  30      /**
  31       * Set or get default scale parameter for all bc math functions
  32       *
  33       * Uses the PHP 7.3+ behavior
  34       *
  35       * @var int $scale optional
  36       */
  37      private static function scale($scale = null)
  38      {
  39          if (isset($scale)) {
  40              self::$scale = (int) $scale;
  41          }
  42          return self::$scale;
  43      }
  44  
  45      /**
  46       * Formats numbers
  47       *
  48       * Places the decimal place at the appropriate place, adds trailing 0's as appropriate, etc
  49       *
  50       * @var string $x
  51       * @var int $scale
  52       * @var int $pad
  53       * @var boolean $trim
  54       */
  55      private static function format($x, $scale, $pad)
  56      {
  57          $sign = self::isNegative($x) ? '-' : '';
  58          $x = str_replace('-', '', $x);
  59  
  60          if (strlen($x) != $pad) {
  61              $x = str_pad($x, $pad, '0', STR_PAD_LEFT);
  62          }
  63          $temp = $pad ? substr_replace($x, '.', -$pad, 0) : $x;
  64          $temp = explode('.', $temp);
  65          if ($temp[0] == '') {
  66              $temp[0] = '0';
  67          }
  68          if (isset($temp[1])) {
  69              $temp[1] = substr($temp[1], 0, $scale);
  70              $temp[1] = str_pad($temp[1], $scale, '0');
  71          } elseif ($scale) {
  72              $temp[1] = str_repeat('0', $scale);
  73          }
  74          $result = rtrim(implode('.', $temp), '.');
  75          if ($sign == '-' && preg_match('#^0\.?0*$#', $result)) {
  76              $sign = '';
  77          }
  78          return $sign . $result;
  79      }
  80  
  81      /**
  82       * Negativity Test
  83       *
  84       * @var BigInteger $x
  85       */
  86      private static function isNegative($x)
  87      {
  88          return $x->compare(new BigInteger()) < 0;
  89      }
  90  
  91      /**
  92       * Add two arbitrary precision numbers
  93       *
  94       * @var string $x
  95       * @var string $y
  96       * @var int $scale
  97       * @var int $pad
  98       */
  99      private static function add($x, $y, $scale, $pad)
 100      {
 101          $z = $x->add($y);
 102  
 103          return self::format($z, $scale, $pad);
 104      }
 105  
 106      /**
 107       * Subtract one arbitrary precision number from another
 108       *
 109       * @var string $x
 110       * @var string $y
 111       * @var int $scale
 112       * @var int $pad
 113       */
 114      private static function sub($x, $y, $scale, $pad)
 115      {
 116          $z = $x->subtract($y);
 117  
 118          return self::format($z, $scale, $pad);
 119      }
 120  
 121      /**
 122       * Multiply two arbitrary precision numbers
 123       *
 124       * @var string $x
 125       * @var string $y
 126       * @var int $scale
 127       * @var int $pad
 128       */
 129      private static function mul($x, $y, $scale, $pad)
 130      {
 131          if ($x == '0' || $y == '0') {
 132              $r = '0';
 133              if ($scale) {
 134                  $r.= '.' . str_repeat('0', $scale);
 135              }
 136              return $r;
 137          }
 138  
 139          $z = $x->abs()->multiply($y->abs());
 140          $result = self::format($z, $scale, 2 * $pad);
 141  
 142          $sign = (self::isNegative($x) ^ self::isNegative($y)) && !preg_match('#^0\.?0*$#', $result) ? '-' : '';
 143  
 144          return $sign . $result;
 145      }
 146  
 147      /**
 148       * Divide two arbitrary precision numbers
 149       *
 150       * @var string $x
 151       * @var string $y
 152       * @var int $scale
 153       * @var int $pad
 154       */
 155      private static function div($x, $y, $scale, $pad)
 156      {
 157          if ($y == '0') {
 158              // < PHP 8.0 triggered a warning
 159              // >= PHP 8.0 throws an exception
 160              throw new \DivisionByZeroError('Division by zero');
 161          }
 162  
 163          $temp = '1' . str_repeat('0', $scale);
 164          $temp = new BigInteger($temp);
 165          list($q) = $x->multiply($temp)->divide($y);
 166  
 167          return self::format($q, $scale, $scale);
 168      }
 169  
 170      /**
 171       * Get modulus of an arbitrary precision number
 172       *
 173       * Uses the PHP 7.2+ behavior
 174       *
 175       * @var string $x
 176       * @var string $y
 177       * @var int $scale
 178       * @var int $pad
 179       */
 180      private static function mod($x, $y, $scale, $pad)
 181      {
 182          if ($y == '0') {
 183              // < PHP 8.0 triggered a warning
 184              // >= PHP 8.0 throws an exception
 185              throw new \DivisionByZeroError('Division by zero');
 186          }
 187  
 188          list($q) = $x->divide($y);
 189          $z = $y->multiply($q);
 190          $z = $x->subtract($z);
 191  
 192          return self::format($z, $scale, $pad);
 193      }
 194  
 195      /**
 196       * Compare two arbitrary precision numbers
 197       *
 198       * @var string $x
 199       * @var string $y
 200       * @var int $scale
 201       * @var int $pad
 202       */
 203      private static function comp($x, $y, $scale, $pad)
 204      {
 205          $x = new BigInteger($x[0] . substr($x[1], 0, $scale));
 206          $y = new BigInteger($y[0] . substr($y[1], 0, $scale));
 207  
 208          return $x->compare($y);
 209      }
 210  
 211      /**
 212       * Raise an arbitrary precision number to another
 213       *
 214       * Uses the PHP 7.2+ behavior
 215       *
 216       * @var string $x
 217       * @var string $y
 218       * @var int $scale
 219       * @var int $pad
 220       */
 221      private static function pow($x, $y, $scale, $pad)
 222      {
 223          if ($y == '0') {
 224              $r = '1';
 225              if ($scale) {
 226                  $r.= '.' . str_repeat('0', $scale);
 227              }
 228              return $r;
 229          }
 230  
 231          $min = defined('PHP_INT_MIN') ? PHP_INT_MIN : ~PHP_INT_MAX;
 232          if (bccomp($y, PHP_INT_MAX) > 0 || bccomp($y, $min) <= 0) {
 233              throw new \ValueError('bcpow(): Argument #2 ($exponent) is too large');
 234          }
 235  
 236          $sign = self::isNegative($x) ? '-' : '';
 237          $x = $x->abs();
 238  
 239          $r = new BigInteger(1);
 240  
 241          for ($i = 0; $i < abs($y); $i++) {
 242              $r = $r->multiply($x);
 243          }
 244  
 245          if ($y < 0) {
 246              $temp = '1' . str_repeat('0', $scale + $pad * abs($y));
 247              $temp = new BigInteger($temp);
 248              list($r) = $temp->divide($r);
 249              $pad = $scale;
 250          } else {
 251              $pad*= abs($y);
 252          }
 253  
 254          return $sign . self::format($r, $scale, $pad);
 255      }
 256  
 257      /**
 258       * Raise an arbitrary precision number to another, reduced by a specified modulus
 259       *
 260       * @var string $x
 261       * @var string $e
 262       * @var string $n
 263       * @var int $scale
 264       * @var int $pad
 265       */
 266      private static function powmod($x, $e, $n, $scale, $pad)
 267      {
 268          if ($e[0] == '-' || $n == '0') {
 269              // < PHP 8.0 returned false
 270              // >= PHP 8.0 throws an exception
 271              throw new \ValueError('bcpowmod(): Argument #2 ($exponent) must be greater than or equal to 0');
 272          }
 273          if ($n[0] == '-') {
 274              $n = substr($n, 1);
 275          }
 276          if ($e == '0') {
 277              return $scale ?
 278                  '1.' . str_repeat('0', $scale) :
 279                  '1';
 280          }
 281  
 282          $x = new BigInteger($x);
 283          $e = new BigInteger($e);
 284          $n = new BigInteger($n);
 285  
 286          $z = $x->powMod($e, $n);
 287  
 288          return $scale ?
 289              "$z." . str_repeat('0', $scale) :
 290              "$z";
 291      }
 292  
 293      /**
 294       * Get the square root of an arbitrary precision number
 295       *
 296       * @var string $n
 297       * @var int $scale
 298       * @var int $pad
 299       */
 300      private static function sqrt($n, $scale, $pad)
 301      {
 302          // the following is based off of the following URL:
 303          // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Decimal_(base_10)
 304  
 305          if (!is_numeric($n)) {
 306              return '0';
 307          }
 308          $temp = explode('.', $n);
 309          $decStart = ceil(strlen($temp[0]) / 2);
 310          $n = implode('', $temp);
 311          if (strlen($n) % 2) {
 312              $n = "0$n";
 313          }
 314          $parts = str_split($n, 2);
 315          $parts = array_map('intval', $parts);
 316          $i = 0;
 317          $p = 0; // for the first step, p = 0
 318          $c = $parts[$i];
 319          $result = '';
 320          while (true) {
 321              // determine the greatest digit x such that x(20p+x) <= c
 322              for ($x = 1; $x <= 10; $x++) {
 323                  if ($x * (20 * $p + $x) > $c) {
 324                      $x--;
 325                      break;
 326                  }
 327              }
 328              $result.= $x;
 329              $y = $x * (20 * $p + $x);
 330              $p = 10 * $p + $x;
 331              $c = 100 * ($c - $y);
 332              if (isset($parts[++$i])) {
 333                  $c+= $parts[$i];
 334              }
 335              if ((!$c && $i >= $decStart)  || $i - $decStart == $scale) {
 336                  break;
 337              }
 338              if ($decStart == $i) {
 339                  $result.= '.';
 340              }
 341          }
 342  
 343          $result = explode('.', $result);
 344          if (isset($result[1])) {
 345              $result[1] = str_pad($result[1], $scale, '0');
 346          } elseif ($scale) {
 347              $result[1] = str_repeat('0', $scale);
 348          }
 349          return implode('.', $result);
 350      }
 351  
 352      /**
 353       * __callStatic Magic Method
 354       *
 355       * @var string $name
 356       * @var array $arguments
 357       */
 358      public static function __callStatic($name, $arguments)
 359      {
 360          static $params = [
 361              'add' => 3,
 362              'comp' => 3,
 363              'div' => 3,
 364              'mod' => 3,
 365              'mul' => 3,
 366              'pow' => 3,
 367              'powmod' => 4,
 368              'scale' => 1,
 369              'sqrt' => 2,
 370              'sub' => 3
 371          ];
 372          if (count($arguments) < $params[$name] - 1) {
 373              $min = $params[$name] - 1;
 374              throw new \ArgumentCountError("bc$name() expects at least $min parameters, " . func_num_args() . " given");
 375          }
 376          if (count($arguments) > $params[$name]) {
 377              $str = "bc$name() expects at most {$params[$name]} parameters, " . func_num_args() . " given";
 378              throw new \ArgumentCountError($str);
 379          }
 380          $numbers = array_slice($arguments, 0, $params[$name] - 1);
 381  
 382          $ints = [];
 383          switch ($name) {
 384              case 'pow':
 385                  $ints = array_slice($numbers, count($numbers) - 1);
 386                  $numbers = array_slice($numbers, 0, count($numbers) - 1);
 387                  $names = ['exponent'];
 388                  break;
 389              case 'powmod':
 390                  $ints = $numbers;
 391                  $numbers = [];
 392                  $names = ['base', 'exponent', 'modulus'];
 393                  break;
 394              case 'sqrt':
 395                  $names = ['num'];
 396                  break;
 397              default:
 398                  $names = ['num1', 'num2'];
 399          }
 400          foreach ($ints as $i => &$int) {
 401              if (!is_numeric($int)) {
 402                  $int = '0';
 403              }
 404              $pos = strpos($int, '.');
 405              if ($pos !== false) {
 406                  $int = substr($int, 0, $pos);
 407                  throw new \ValueError("bc$name(): Argument #2 (\$$names[$i]) cannot have a fractional part");
 408              }
 409          }
 410          foreach ($numbers as $i => $arg) {
 411              $num = $i + 1;
 412              switch (true) {
 413                  case is_bool($arg):
 414                  case is_numeric($arg):
 415                  case is_string($arg):
 416                  case is_object($arg) && method_exists($arg, '__toString'):
 417                      if (!is_bool($arg) && !is_numeric("$arg")) {
 418                          throw new \ValueError("bc$name: bcmath function argument is not well-formed");
 419                      }
 420                      break;
 421                  // PHP >= 8.1 has deprecated the passing of nulls to string parameters
 422                  case is_null($arg):
 423                      $error = "bc$name(): Passing null to parameter #$num (\$$names[$i]) of type string is deprecated";
 424                      trigger_error($error, E_USER_DEPRECATED);
 425                      break;
 426                  default:
 427                      $type = is_object($arg) ? get_class($arg) : gettype($arg);
 428                      $error = "bc$name(): Argument #$num (\$$names[$i]) must be of type string, $type given";
 429                      throw new \TypeError($error);
 430              }
 431          }
 432          if (!isset(self::$scale)) {
 433              $scale = ini_get('bcmath.scale');
 434              self::$scale = $scale !== false ? max(intval($scale), 0) : 0;
 435          }
 436          $scale = isset($arguments[$params[$name] - 1]) ? $arguments[$params[$name] - 1] : self::$scale;
 437          switch (true) {
 438              case is_bool($scale):
 439              case is_numeric($scale):
 440              case is_string($scale) && preg_match('#0-9\.#', $scale[0]):
 441                  break;
 442              default:
 443                  $type = is_object($arg) ? get_class($arg) : gettype($arg);
 444                  $str = "bc$name(): Argument #$params[$name] (\$scale) must be of type ?int, string given";
 445                  throw new \TypeError($str);
 446          }
 447          $scale = (int) $scale;
 448          if ($scale < 0) {
 449              throw new \ValueError("bc$name(): Argument #$params[$name] (\$scale) must be between 0 and 2147483647");
 450          }
 451  
 452          $pad = 0;
 453          foreach ($numbers as &$num) {
 454              if (is_bool($num)) {
 455                  $num = $num ? '1' : '0';
 456              } elseif (!is_numeric($num)) {
 457                  $num = '0';
 458              }
 459              $num = explode('.', $num);
 460              if (isset($num[1])) {
 461                  $pad = max($pad, strlen($num[1]));
 462              }
 463          }
 464          switch ($name) {
 465              case 'add':
 466              case 'sub':
 467              case 'mul':
 468              case 'div':
 469              case 'mod':
 470              case 'pow':
 471                  foreach ($numbers as &$num) {
 472                      if (!isset($num[1])) {
 473                          $num[1] = '';
 474                      }
 475                      $num[1] = str_pad($num[1], $pad, '0');
 476                      $num = new BigInteger($num[0] . $num[1]);
 477                  }
 478                  break;
 479              case 'comp':
 480                  foreach ($numbers as &$num) {
 481                      if (!isset($num[1])) {
 482                          $num[1] = '';
 483                      }
 484                      $num[1] = str_pad($num[1], $pad, '0');
 485                  }
 486                  break;
 487              case 'sqrt':
 488                  $numbers = [$arguments[0]];
 489          }
 490  
 491          $arguments = array_merge($numbers, $ints, [$scale, $pad]);
 492          return call_user_func_array('self::' . $name, $arguments);
 493      }
 494  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer