/** * Parses a string containing an integer in an arbitrary base. * * The string can optionally be prefixed with the `+` or `-` sign. * * @param string $number The number to parse. * @param int $base The base of the number, between 2 and 36. * * @return BigInteger * * @throws \InvalidArgumentException If the number is invalid or the base is out of range. */ public static function parse($number, $base = 10) { $number = (string) $number; $base = (int) $base; $dictionary = '0123456789abcdefghijklmnopqrstuvwxyz'; if ($number === '') { throw new \InvalidArgumentException('The value cannot be empty.'); } if ($base < 2 || $base > 36) { throw new \InvalidArgumentException(sprintf('Base %d is not in range 2 to 36.', $base)); } if ($number[0] === '-') { $sign = '-'; $number = substr($number, 1); } elseif ($number[0] === '+') { $sign = ''; $number = substr($number, 1); } else { $sign = ''; } if ($number === false || $number === '') { throw new \InvalidArgumentException('The value cannot be empty.'); } $number = ltrim($number, '0'); if ($number === '') { // The result will be the same in any base, avoid further calculation. return BigInteger::zero(); } if ($number === '1') { // The result will be the same in any base, avoid further calculation. return new BigInteger($sign . '1'); } if ($base === 10 && ctype_digit($number)) { // The number is usable as is, avoid further calculation. return new BigInteger($sign . $number); } $calc = Calculator::get(); $number = strtolower($number); $result = '0'; $power = '1'; for ($i = strlen($number) - 1; $i >= 0; $i--) { $char = $number[$i]; $index = strpos($dictionary, $char); if ($index === false || $index >= $base) { throw new \InvalidArgumentException(sprintf('"%s" is not a valid character in base %d.', $char, $base)); } if ($index !== 0) { $add = $index === 1 ? $power : $calc->mul($power, (string) $index); $result = $calc->add($result, $add); } $power = $calc->mul($power, (string) $base); } return new BigInteger($sign . $result); }
/** * Returns file size by reading whole files and counting read bites * @link http://stackoverflow.com/questions/5501451/php-x86-how-to-get-filesize-of-2gb-file-without-external-program/5504829#5504829 * @inheritdoc */ public function getFileSize($path) { $fp = fopen($path, "rb"); if (!$fp) { throw new Exception("Cannot read from file."); } flock($fp, LOCK_SH); rewind($fp); $fileSize = BigInteger::zero(); $chunkSize = 1024 * 1024; while (!feof($fp)) { $readBytes = strlen(fread($fp, $chunkSize)); $fileSize = $fileSize->plus($readBytes); } flock($fp, LOCK_UN); fclose($fp); return $fileSize; }
/** * Returns a BigRational representing zero. * * @return BigRational */ public static function zero() { static $zero; if ($zero === null) { $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false); } return $zero; }
/** * @expectedException \LogicException */ public function testDirectCallToUnserialize() { BigInteger::zero()->unserialize('123'); }