[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/brick/math/src/ -> BigNumber.php (source)

   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  namespace Brick\Math;
   6  
   7  use Brick\Math\Exception\DivisionByZeroException;
   8  use Brick\Math\Exception\MathException;
   9  use Brick\Math\Exception\NumberFormatException;
  10  use Brick\Math\Exception\RoundingNecessaryException;
  11  
  12  /**
  13   * Common interface for arbitrary-precision rational numbers.
  14   *
  15   * @psalm-immutable
  16   */
  17  abstract class BigNumber implements \Serializable, \JsonSerializable
  18  {
  19      /**
  20       * The regular expression used to parse integer, decimal and rational numbers.
  21       *
  22       * @var string
  23       */
  24      private const PARSE_REGEXP =
  25          '/^' .
  26          '(?<integral>[\-\+]?[0-9]+)' .
  27          '(?:' .
  28              '(?:' .
  29                  '(?:\.(?<fractional>[0-9]+))?' .
  30                  '(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .
  31              ')' . '|' . '(?:' .
  32                  '(?:\/(?<denominator>[0-9]+))?' .
  33              ')' .
  34          ')?' .
  35          '$/';
  36  
  37      /**
  38       * Creates a BigNumber of the given value.
  39       *
  40       * The concrete return type is dependent on the given value, with the following rules:
  41       *
  42       * - BigNumber instances are returned as is
  43       * - integer numbers are returned as BigInteger
  44       * - floating point numbers are converted to a string then parsed as such
  45       * - strings containing a `/` character are returned as BigRational
  46       * - strings containing a `.` character or using an exponential notation are returned as BigDecimal
  47       * - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger
  48       *
  49       * @param BigNumber|int|float|string $value
  50       *
  51       * @return BigNumber
  52       *
  53       * @throws NumberFormatException   If the format of the number is not valid.
  54       * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.
  55       *
  56       * @psalm-pure
  57       */
  58      public static function of($value) : BigNumber
  59      {
  60          if ($value instanceof BigNumber) {
  61              return $value;
  62          }
  63  
  64          if (\is_int($value)) {
  65              return new BigInteger((string) $value);
  66          }
  67  
  68          if (\is_float($value)) {
  69              $value = self::floatToString($value);
  70          } else {
  71              $value = (string) $value;
  72          }
  73  
  74          if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) {
  75              throw new NumberFormatException(\sprintf('The given value "%s" does not represent a valid number.', $value));
  76          }
  77  
  78          if (isset($matches['denominator'])) {
  79              $numerator   = self::cleanUp($matches['integral']);
  80              $denominator = \ltrim($matches['denominator'], '0');
  81  
  82              if ($denominator === '') {
  83                  throw DivisionByZeroException::denominatorMustNotBeZero();
  84              }
  85  
  86              return new BigRational(new BigInteger($numerator), new BigInteger($denominator), false);
  87          }
  88  
  89          if (isset($matches['fractional']) || isset($matches['exponent'])) {
  90              $fractional = isset($matches['fractional']) ? $matches['fractional'] : '';
  91              $exponent = isset($matches['exponent']) ? (int) $matches['exponent'] : 0;
  92  
  93              $unscaledValue = self::cleanUp($matches['integral'] . $fractional);
  94  
  95              $scale = \strlen($fractional) - $exponent;
  96  
  97              if ($scale < 0) {
  98                  if ($unscaledValue !== '0') {
  99                      $unscaledValue .= \str_repeat('0', - $scale);
 100                  }
 101                  $scale = 0;
 102              }
 103  
 104              return new BigDecimal($unscaledValue, $scale);
 105          }
 106  
 107          $integral = self::cleanUp($matches['integral']);
 108  
 109          return new BigInteger($integral);
 110      }
 111  
 112      /**
 113       * Safely converts float to string, avoiding locale-dependent issues.
 114       *
 115       * @see https://github.com/brick/math/pull/20
 116       *
 117       * @param float $float
 118       *
 119       * @return string
 120       *
 121       * @psalm-pure
 122       * @psalm-suppress ImpureFunctionCall
 123       */
 124      private static function floatToString(float $float) : string
 125      {
 126          $currentLocale = \setlocale(LC_NUMERIC, '0');
 127          \setlocale(LC_NUMERIC, 'C');
 128  
 129          $result = (string) $float;
 130  
 131          \setlocale(LC_NUMERIC, $currentLocale);
 132  
 133          return $result;
 134      }
 135  
 136      /**
 137       * Proxy method to access protected constructors from sibling classes.
 138       *
 139       * @internal
 140       *
 141       * @param mixed ...$args The arguments to the constructor.
 142       *
 143       * @return static
 144       *
 145       * @psalm-pure
 146       */
 147      protected static function create(... $args) : BigNumber
 148      {
 149          /** @psalm-suppress TooManyArguments */
 150          return new static(... $args);
 151      }
 152  
 153      /**
 154       * Returns the minimum of the given values.
 155       *
 156       * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
 157       *                                              to an instance of the class this method is called on.
 158       *
 159       * @return static The minimum value.
 160       *
 161       * @throws \InvalidArgumentException If no values are given.
 162       * @throws MathException             If an argument is not valid.
 163       *
 164       * @psalm-pure
 165       */
 166      public static function min(...$values) : BigNumber
 167      {
 168          $min = null;
 169  
 170          foreach ($values as $value) {
 171              $value = static::of($value);
 172  
 173              if ($min === null || $value->isLessThan($min)) {
 174                  $min = $value;
 175              }
 176          }
 177  
 178          if ($min === null) {
 179              throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
 180          }
 181  
 182          return $min;
 183      }
 184  
 185      /**
 186       * Returns the maximum of the given values.
 187       *
 188       * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
 189       *                                              to an instance of the class this method is called on.
 190       *
 191       * @return static The maximum value.
 192       *
 193       * @throws \InvalidArgumentException If no values are given.
 194       * @throws MathException             If an argument is not valid.
 195       *
 196       * @psalm-pure
 197       */
 198      public static function max(...$values) : BigNumber
 199      {
 200          $max = null;
 201  
 202          foreach ($values as $value) {
 203              $value = static::of($value);
 204  
 205              if ($max === null || $value->isGreaterThan($max)) {
 206                  $max = $value;
 207              }
 208          }
 209  
 210          if ($max === null) {
 211              throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
 212          }
 213  
 214          return $max;
 215      }
 216  
 217      /**
 218       * Returns the sum of the given values.
 219       *
 220       * @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible
 221       *                                              to an instance of the class this method is called on.
 222       *
 223       * @return static The sum.
 224       *
 225       * @throws \InvalidArgumentException If no values are given.
 226       * @throws MathException             If an argument is not valid.
 227       *
 228       * @psalm-pure
 229       */
 230      public static function sum(...$values) : BigNumber
 231      {
 232          /** @var BigNumber|null $sum */
 233          $sum = null;
 234  
 235          foreach ($values as $value) {
 236              $value = static::of($value);
 237  
 238              if ($sum === null) {
 239                  $sum = $value;
 240              } else {
 241                  $sum = self::add($sum, $value);
 242              }
 243          }
 244  
 245          if ($sum === null) {
 246              throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
 247          }
 248  
 249          return $sum;
 250      }
 251  
 252      /**
 253       * Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException.
 254       *
 255       * @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to
 256       *       concrete classes the responsibility to perform the addition themselves or delegate it to the given number,
 257       *       depending on their ability to perform the operation. This will also require a version bump because we're
 258       *       potentially breaking custom BigNumber implementations (if any...)
 259       *
 260       * @param BigNumber $a
 261       * @param BigNumber $b
 262       *
 263       * @return BigNumber
 264       *
 265       * @psalm-pure
 266       */
 267      private static function add(BigNumber $a, BigNumber $b) : BigNumber
 268      {
 269          if ($a instanceof BigRational) {
 270              return $a->plus($b);
 271          }
 272  
 273          if ($b instanceof BigRational) {
 274              return $b->plus($a);
 275          }
 276  
 277          if ($a instanceof BigDecimal) {
 278              return $a->plus($b);
 279          }
 280  
 281          if ($b instanceof BigDecimal) {
 282              return $b->plus($a);
 283          }
 284  
 285          /** @var BigInteger $a */
 286  
 287          return $a->plus($b);
 288      }
 289  
 290      /**
 291       * Removes optional leading zeros and + sign from the given number.
 292       *
 293       * @param string $number The number, validated as a non-empty string of digits with optional sign.
 294       *
 295       * @return string
 296       *
 297       * @psalm-pure
 298       */
 299      private static function cleanUp(string $number) : string
 300      {
 301          $firstChar = $number[0];
 302  
 303          if ($firstChar === '+' || $firstChar === '-') {
 304              $number = \substr($number, 1);
 305          }
 306  
 307          $number = \ltrim($number, '0');
 308  
 309          if ($number === '') {
 310              return '0';
 311          }
 312  
 313          if ($firstChar === '-') {
 314              return '-' . $number;
 315          }
 316  
 317          return $number;
 318      }
 319  
 320      /**
 321       * Checks if this number is equal to the given one.
 322       *
 323       * @param BigNumber|int|float|string $that
 324       *
 325       * @return bool
 326       */
 327      public function isEqualTo($that) : bool
 328      {
 329          return $this->compareTo($that) === 0;
 330      }
 331  
 332      /**
 333       * Checks if this number is strictly lower than the given one.
 334       *
 335       * @param BigNumber|int|float|string $that
 336       *
 337       * @return bool
 338       */
 339      public function isLessThan($that) : bool
 340      {
 341          return $this->compareTo($that) < 0;
 342      }
 343  
 344      /**
 345       * Checks if this number is lower than or equal to the given one.
 346       *
 347       * @param BigNumber|int|float|string $that
 348       *
 349       * @return bool
 350       */
 351      public function isLessThanOrEqualTo($that) : bool
 352      {
 353          return $this->compareTo($that) <= 0;
 354      }
 355  
 356      /**
 357       * Checks if this number is strictly greater than the given one.
 358       *
 359       * @param BigNumber|int|float|string $that
 360       *
 361       * @return bool
 362       */
 363      public function isGreaterThan($that) : bool
 364      {
 365          return $this->compareTo($that) > 0;
 366      }
 367  
 368      /**
 369       * Checks if this number is greater than or equal to the given one.
 370       *
 371       * @param BigNumber|int|float|string $that
 372       *
 373       * @return bool
 374       */
 375      public function isGreaterThanOrEqualTo($that) : bool
 376      {
 377          return $this->compareTo($that) >= 0;
 378      }
 379  
 380      /**
 381       * Checks if this number equals zero.
 382       *
 383       * @return bool
 384       */
 385      public function isZero() : bool
 386      {
 387          return $this->getSign() === 0;
 388      }
 389  
 390      /**
 391       * Checks if this number is strictly negative.
 392       *
 393       * @return bool
 394       */
 395      public function isNegative() : bool
 396      {
 397          return $this->getSign() < 0;
 398      }
 399  
 400      /**
 401       * Checks if this number is negative or zero.
 402       *
 403       * @return bool
 404       */
 405      public function isNegativeOrZero() : bool
 406      {
 407          return $this->getSign() <= 0;
 408      }
 409  
 410      /**
 411       * Checks if this number is strictly positive.
 412       *
 413       * @return bool
 414       */
 415      public function isPositive() : bool
 416      {
 417          return $this->getSign() > 0;
 418      }
 419  
 420      /**
 421       * Checks if this number is positive or zero.
 422       *
 423       * @return bool
 424       */
 425      public function isPositiveOrZero() : bool
 426      {
 427          return $this->getSign() >= 0;
 428      }
 429  
 430      /**
 431       * Returns the sign of this number.
 432       *
 433       * @return int -1 if the number is negative, 0 if zero, 1 if positive.
 434       */
 435      abstract public function getSign() : int;
 436  
 437      /**
 438       * Compares this number to the given one.
 439       *
 440       * @param BigNumber|int|float|string $that
 441       *
 442       * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`.
 443       *
 444       * @throws MathException If the number is not valid.
 445       */
 446      abstract public function compareTo($that) : int;
 447  
 448      /**
 449       * Converts this number to a BigInteger.
 450       *
 451       * @return BigInteger The converted number.
 452       *
 453       * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding.
 454       */
 455      abstract public function toBigInteger() : BigInteger;
 456  
 457      /**
 458       * Converts this number to a BigDecimal.
 459       *
 460       * @return BigDecimal The converted number.
 461       *
 462       * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding.
 463       */
 464      abstract public function toBigDecimal() : BigDecimal;
 465  
 466      /**
 467       * Converts this number to a BigRational.
 468       *
 469       * @return BigRational The converted number.
 470       */
 471      abstract public function toBigRational() : BigRational;
 472  
 473      /**
 474       * Converts this number to a BigDecimal with the given scale, using rounding if necessary.
 475       *
 476       * @param int $scale        The scale of the resulting `BigDecimal`.
 477       * @param int $roundingMode A `RoundingMode` constant.
 478       *
 479       * @return BigDecimal
 480       *
 481       * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding.
 482       *                                    This only applies when RoundingMode::UNNECESSARY is used.
 483       */
 484      abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
 485  
 486      /**
 487       * Returns the exact value of this number as a native integer.
 488       *
 489       * If this number cannot be converted to a native integer without losing precision, an exception is thrown.
 490       * Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit.
 491       *
 492       * @return int The converted value.
 493       *
 494       * @throws MathException If this number cannot be exactly converted to a native integer.
 495       */
 496      abstract public function toInt() : int;
 497  
 498      /**
 499       * Returns an approximation of this number as a floating-point value.
 500       *
 501       * Note that this method can discard information as the precision of a floating-point value
 502       * is inherently limited.
 503       *
 504       * If the number is greater than the largest representable floating point number, positive infinity is returned.
 505       * If the number is less than the smallest representable floating point number, negative infinity is returned.
 506       *
 507       * @return float The converted value.
 508       */
 509      abstract public function toFloat() : float;
 510  
 511      /**
 512       * Returns a string representation of this number.
 513       *
 514       * The output of this method can be parsed by the `of()` factory method;
 515       * this will yield an object equal to this one, without any information loss.
 516       *
 517       * @return string
 518       */
 519      abstract public function __toString() : string;
 520  
 521      /**
 522       * {@inheritdoc}
 523       */
 524      public function jsonSerialize() : string
 525      {
 526          return $this->__toString();
 527      }
 528  }


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