作者 刘锟

'删除非必要文件'

要显示太多修改。

为保证性能只显示 29 of 29+ 个文件。

1 -APP_NAME=Laravel  
2 -APP_ENV=local  
3 -APP_KEY=base64:/auyqKGh43iaRgeb1sFk3QO/3Ay43fEB3mxEh7XmmlQ=  
4 -APP_DEBUG=true  
5 -APP_URL=http://localhost  
6 -  
7 -LOG_CHANNEL=daily  
8 -LOG_DEPRECATIONS_CHANNEL=null  
9 -LOG_LEVEL=debug  
10 -  
11 -DB_CONNECTION=mysql  
12 -DB_HOST=127.0.0.1  
13 -DB_PORT=3306  
14 -DB_DATABASE=forget  
15 -DB_USERNAME=forget  
16 -DB_PASSWORD=forget  
17 -  
18 -BROADCAST_DRIVER=log  
19 -CACHE_DRIVER=file  
20 -FILESYSTEM_DRIVER=local  
21 -QUEUE_CONNECTION=redis  
22 -SESSION_DRIVER=file  
23 -SESSION_LIFETIME=120  
24 -  
25 -MEMCACHED_HOST=127.0.0.1  
26 -REDIS_HOST=127.0.0.1  
27 -REDIS_PASSWORD=null  
28 -REDIS_PORT=6379  
29 -  
30 -MAIL_MAILER=smtp  
31 -MAIL_HOST=mailhog  
32 -MAIL_PORT=1025  
33 -MAIL_USERNAME=null  
34 -MAIL_PASSWORD=null  
35 -MAIL_ENCRYPTION=null  
36 -MAIL_FROM_ADDRESS=null  
37 -MAIL_FROM_NAME="${APP_NAME}"  
38 -  
39 -AWS_ACCESS_KEY_ID=  
40 -AWS_SECRET_ACCESS_KEY=  
41 -AWS_DEFAULT_REGION=us-east-1  
42 -AWS_BUCKET=  
43 -AWS_USE_PATH_STYLE_ENDPOINT=false  
44 -  
45 -PUSHER_APP_ID=  
46 -PUSHER_APP_KEY=  
47 -PUSHER_APP_SECRET=  
48 -PUSHER_APP_CLUSTER=mt1  
49 -  
50 -MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"  
51 -MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"  
52 -  
53 -API_URL=https://sitefile.globalso.com/  
54 -TRANSMIT_URL=https://hub.globalso.com/  
55 -MERCHANT_NUMBER=1288  
56 -SECRET_TOKEN=ni4w5ba983c5a805fd54655d015354e6c3bc  
此 diff 太大无法显示。
1 -Copyright (c) 2013-2017 Alexander <iam.asm89@gmail.com>  
2 -  
3 -Permission is hereby granted, free of charge, to any person obtaining a copy  
4 -of this software and associated documentation files (the "Software"), to deal  
5 -in the Software without restriction, including without limitation the rights  
6 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
7 -copies of the Software, and to permit persons to whom the Software is furnished  
8 -to do so, subject to the following conditions:  
9 -  
10 -The above copyright notice and this permission notice shall be included in all  
11 -copies or substantial portions of the Software.  
12 -  
13 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
14 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
15 -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
16 -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
17 -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
18 -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN  
19 -THE SOFTWARE.  
1 -# Stack/Cors  
2 -  
3 -Library and middleware enabling cross-origin resource sharing for your  
4 -http-{foundation,kernel} using application. It attempts to implement the  
5 -[W3C Recommendation] for cross-origin resource sharing.  
6 -  
7 -[W3C Recommendation]: http://www.w3.org/TR/cors/  
8 -  
9 -Build status: ![.github/workflows/run-tests.yml](https://github.com/asm89/stack-cors/workflows/.github/workflows/run-tests.yml/badge.svg)  
10 -  
11 -## Installation  
12 -  
13 -Require `asm89/stack-cors` using composer.  
14 -  
15 -## Usage  
16 -  
17 -This package can be used as a library or as [stack middleware].  
18 -  
19 -[stack middleware]: http://stackphp.com/  
20 -  
21 -### Options  
22 -  
23 -| Option | Description | Default value |  
24 -|------------------------|------------------------------------------------------------|---------------|  
25 -| `allowedMethods` | Matches the request method. | `[]` |  
26 -| `allowedOrigins` | Matches the request origin. | `[]` |  
27 -| `allowedOriginsPatterns` | Matches the request origin with `preg_match`. | `[]` |  
28 -| `allowedHeaders` | Sets the Access-Control-Allow-Headers response header. | `[]` |  
29 -| `exposedHeaders` | Sets the Access-Control-Expose-Headers response header. | `false` |  
30 -| `maxAge` | Sets the Access-Control-Max-Age response header.<br/>Set to `null` to omit the header/use browser default. | `0` |  
31 -| `supportsCredentials` | Sets the Access-Control-Allow-Credentials header. | `false` |  
32 -  
33 -The _allowedMethods_ and _allowedHeaders_ options are case-insensitive.  
34 -  
35 -You don't need to provide both _allowedOrigins_ and _allowedOriginsPatterns_. If one of the strings passed matches, it is considered a valid origin.  
36 -  
37 -If `['*']` is provided to _allowedMethods_, _allowedOrigins_ or _allowedHeaders_ all methods / origins / headers are allowed.  
38 -  
39 -If _supportsCredentials_ is `true`, you must [explicitly set](https://fetch.spec.whatwg.org/#cors-protocol-and-credentials) `allowedHeaders` for any headers which are not CORS safelisted.  
40 -  
41 -### Example: using the library  
42 -  
43 -```php  
44 -<?php  
45 -  
46 -use Asm89\Stack\CorsService;  
47 -  
48 -$cors = new CorsService([  
49 - 'allowedHeaders' => ['x-allowed-header', 'x-other-allowed-header'],  
50 - 'allowedMethods' => ['DELETE', 'GET', 'POST', 'PUT'],  
51 - 'allowedOrigins' => ['http://localhost'],  
52 - 'allowedOriginsPatterns' => ['/localhost:\d/'],  
53 - 'exposedHeaders' => false,  
54 - 'maxAge' => 600,  
55 - 'supportsCredentials' => true,  
56 -]);  
57 -  
58 -$cors->addActualRequestHeaders(Response $response, $origin);  
59 -$cors->handlePreflightRequest(Request $request);  
60 -$cors->isActualRequestAllowed(Request $request);  
61 -$cors->isCorsRequest(Request $request);  
62 -$cors->isPreflightRequest(Request $request);  
63 -```  
64 -  
65 -## Example: using the stack middleware  
66 -  
67 -```php  
68 -<?php  
69 -  
70 -use Asm89\Stack\Cors;  
71 -  
72 -$app = new Cors($app, [  
73 - // you can use ['*'] to allow any headers  
74 - 'allowedHeaders' => ['x-allowed-header', 'x-other-allowed-header'],  
75 - // you can use ['*'] to allow any methods  
76 - 'allowedMethods' => ['DELETE', 'GET', 'POST', 'PUT'],  
77 - // you can use ['*'] to allow requests from any origin  
78 - 'allowedOrigins' => ['localhost'],  
79 - // you can enter regexes that are matched to the origin request header  
80 - 'allowedOriginsPatterns' => ['/localhost:\d/'],  
81 - 'exposedHeaders' => false,  
82 - 'maxAge' => 600,  
83 - 'supportsCredentials' => false,  
84 -]);  
85 -```  
1 -{  
2 - "name": "asm89/stack-cors",  
3 - "description": "Cross-origin resource sharing library and stack middleware",  
4 - "keywords": ["stack", "cors"],  
5 - "homepage": "https://github.com/asm89/stack-cors",  
6 - "type": "library",  
7 - "license": "MIT",  
8 - "authors": [  
9 - {  
10 - "name": "Alexander",  
11 - "email": "iam.asm89@gmail.com"  
12 - }  
13 - ],  
14 - "require": {  
15 - "php": "^7.3|^8.0",  
16 - "symfony/http-foundation": "^5.3|^6|^7",  
17 - "symfony/http-kernel": "^5.3|^6|^7"  
18 - },  
19 - "require-dev": {  
20 - "phpunit/phpunit": "^9",  
21 - "squizlabs/php_codesniffer": "^3.5"  
22 - },  
23 - "autoload": {  
24 - "psr-4": {  
25 - "Asm89\\Stack\\": "src/"  
26 - }  
27 - },  
28 - "autoload-dev": {  
29 - "psr-4": {  
30 - "Asm89\\Stack\\Tests\\": "tests/"  
31 - }  
32 - },  
33 - "scripts": {  
34 - "test": "phpunit",  
35 - "check-style": "phpcs -p --standard=PSR12 --exclude=Generic.Files.LineLength --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src",  
36 - "fix-style": "phpcbf -p --standard=PSR12 --exclude=Generic.Files.LineLength --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src"  
37 - },  
38 - "extra": {  
39 - "branch-alias": {  
40 - "dev-master": "2.2-dev"  
41 - }  
42 - },  
43 - "minimum-stability": "beta",  
44 - "prefer-stable": true  
45 -}  
1 -<?php  
2 -  
3 -/*  
4 - * This file is part of asm89/stack-cors.  
5 - *  
6 - * (c) Alexander <iam.asm89@gmail.com>  
7 - *  
8 - * For the full copyright and license information, please view the LICENSE  
9 - * file that was distributed with this source code.  
10 - */  
11 -  
12 -namespace Asm89\Stack;  
13 -  
14 -use Symfony\Component\HttpFoundation\Response;  
15 -use Symfony\Component\HttpKernel\HttpKernelInterface;  
16 -use Symfony\Component\HttpFoundation\Request;  
17 -  
18 -class Cors implements HttpKernelInterface  
19 -{  
20 - /**  
21 - * @var \Symfony\Component\HttpKernel\HttpKernelInterface  
22 - */  
23 - private $app;  
24 -  
25 - /**  
26 - * @var \Asm89\Stack\CorsService  
27 - */  
28 - private $cors;  
29 -  
30 - private $defaultOptions = [  
31 - 'allowedHeaders' => [],  
32 - 'allowedMethods' => [],  
33 - 'allowedOrigins' => [],  
34 - 'allowedOriginsPatterns' => [],  
35 - 'exposedHeaders' => [],  
36 - 'maxAge' => 0,  
37 - 'supportsCredentials' => false,  
38 - ];  
39 -  
40 - public function __construct(HttpKernelInterface $app, array $options = [])  
41 - {  
42 - $this->app = $app;  
43 - $this->cors = new CorsService(array_merge($this->defaultOptions, $options));  
44 - }  
45 -  
46 - public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response  
47 - {  
48 - if ($this->cors->isPreflightRequest($request)) {  
49 - $response = $this->cors->handlePreflightRequest($request);  
50 - return $this->cors->varyHeader($response, 'Access-Control-Request-Method');  
51 - }  
52 -  
53 - $response = $this->app->handle($request, $type, $catch);  
54 -  
55 - if ($request->getMethod() === 'OPTIONS') {  
56 - $this->cors->varyHeader($response, 'Access-Control-Request-Method');  
57 - }  
58 -  
59 - return $this->cors->addActualRequestHeaders($response, $request);  
60 - }  
61 -}  
1 -<?php  
2 -  
3 -/*  
4 - * This file is part of asm89/stack-cors.  
5 - *  
6 - * (c) Alexander <iam.asm89@gmail.com>  
7 - *  
8 - * For the full copyright and license information, please view the LICENSE  
9 - * file that was distributed with this source code.  
10 - */  
11 -  
12 -namespace Asm89\Stack;  
13 -  
14 -use Symfony\Component\HttpFoundation\Request;  
15 -use Symfony\Component\HttpFoundation\Response;  
16 -  
17 -class CorsService  
18 -{  
19 - private $options;  
20 -  
21 - public function __construct(array $options = [])  
22 - {  
23 - $this->options = $this->normalizeOptions($options);  
24 - }  
25 -  
26 - private function normalizeOptions(array $options = []): array  
27 - {  
28 - $options += [  
29 - 'allowedOrigins' => [],  
30 - 'allowedOriginsPatterns' => [],  
31 - 'supportsCredentials' => false,  
32 - 'allowedHeaders' => [],  
33 - 'exposedHeaders' => [],  
34 - 'allowedMethods' => [],  
35 - 'maxAge' => 0,  
36 - ];  
37 -  
38 - // normalize array('*') to true  
39 - if (in_array('*', $options['allowedOrigins'])) {  
40 - $options['allowedOrigins'] = true;  
41 - }  
42 - if (in_array('*', $options['allowedHeaders'])) {  
43 - $options['allowedHeaders'] = true;  
44 - } else {  
45 - $options['allowedHeaders'] = array_map('strtolower', $options['allowedHeaders']);  
46 - }  
47 -  
48 - if (in_array('*', $options['allowedMethods'])) {  
49 - $options['allowedMethods'] = true;  
50 - } else {  
51 - $options['allowedMethods'] = array_map('strtoupper', $options['allowedMethods']);  
52 - }  
53 -  
54 - return $options;  
55 - }  
56 -  
57 - /**  
58 - * @deprecated use isOriginAllowed  
59 - */  
60 - public function isActualRequestAllowed(Request $request): bool  
61 - {  
62 - return $this->isOriginAllowed($request);  
63 - }  
64 -  
65 - public function isCorsRequest(Request $request): bool  
66 - {  
67 - return $request->headers->has('Origin');  
68 - }  
69 -  
70 - public function isPreflightRequest(Request $request): bool  
71 - {  
72 - return $request->getMethod() === 'OPTIONS' && $request->headers->has('Access-Control-Request-Method');  
73 - }  
74 -  
75 - public function handlePreflightRequest(Request $request): Response  
76 - {  
77 - $response = new Response();  
78 -  
79 - $response->setStatusCode(204);  
80 -  
81 - return $this->addPreflightRequestHeaders($response, $request);  
82 - }  
83 -  
84 - public function addPreflightRequestHeaders(Response $response, Request $request): Response  
85 - {  
86 - $this->configureAllowedOrigin($response, $request);  
87 -  
88 - if ($response->headers->has('Access-Control-Allow-Origin')) {  
89 - $this->configureAllowCredentials($response, $request);  
90 -  
91 - $this->configureAllowedMethods($response, $request);  
92 -  
93 - $this->configureAllowedHeaders($response, $request);  
94 -  
95 - $this->configureMaxAge($response, $request);  
96 - }  
97 -  
98 - return $response;  
99 - }  
100 -  
101 - public function isOriginAllowed(Request $request): bool  
102 - {  
103 - if ($this->options['allowedOrigins'] === true) {  
104 - return true;  
105 - }  
106 -  
107 - if (!$request->headers->has('Origin')) {  
108 - return false;  
109 - }  
110 -  
111 - $origin = $request->headers->get('Origin');  
112 -  
113 - if (in_array($origin, $this->options['allowedOrigins'])) {  
114 - return true;  
115 - }  
116 -  
117 - foreach ($this->options['allowedOriginsPatterns'] as $pattern) {  
118 - if (preg_match($pattern, $origin)) {  
119 - return true;  
120 - }  
121 - }  
122 -  
123 - return false;  
124 - }  
125 -  
126 - public function addActualRequestHeaders(Response $response, Request $request): Response  
127 - {  
128 - $this->configureAllowedOrigin($response, $request);  
129 -  
130 - if ($response->headers->has('Access-Control-Allow-Origin')) {  
131 - $this->configureAllowCredentials($response, $request);  
132 -  
133 - $this->configureExposedHeaders($response, $request);  
134 - }  
135 -  
136 - return $response;  
137 - }  
138 -  
139 - private function configureAllowedOrigin(Response $response, Request $request)  
140 - {  
141 - if ($this->options['allowedOrigins'] === true && !$this->options['supportsCredentials']) {  
142 - // Safe+cacheable, allow everything  
143 - $response->headers->set('Access-Control-Allow-Origin', '*');  
144 - } elseif ($this->isSingleOriginAllowed()) {  
145 - // Single origins can be safely set  
146 - $response->headers->set('Access-Control-Allow-Origin', array_values($this->options['allowedOrigins'])[0]);  
147 - } else {  
148 - // For dynamic headers, set the requested Origin header when set and allowed  
149 - if ($this->isCorsRequest($request) && $this->isOriginAllowed($request)) {  
150 - $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));  
151 - }  
152 -  
153 - $this->varyHeader($response, 'Origin');  
154 - }  
155 - }  
156 -  
157 - private function isSingleOriginAllowed(): bool  
158 - {  
159 - if ($this->options['allowedOrigins'] === true || !empty($this->options['allowedOriginsPatterns'])) {  
160 - return false;  
161 - }  
162 -  
163 - return count($this->options['allowedOrigins']) === 1;  
164 - }  
165 -  
166 - private function configureAllowedMethods(Response $response, Request $request)  
167 - {  
168 - if ($this->options['allowedMethods'] === true) {  
169 - $allowMethods = strtoupper($request->headers->get('Access-Control-Request-Method'));  
170 - $this->varyHeader($response, 'Access-Control-Request-Method');  
171 - } else {  
172 - $allowMethods = implode(', ', $this->options['allowedMethods']);  
173 - }  
174 -  
175 - $response->headers->set('Access-Control-Allow-Methods', $allowMethods);  
176 - }  
177 -  
178 - private function configureAllowedHeaders(Response $response, Request $request)  
179 - {  
180 - if ($this->options['allowedHeaders'] === true) {  
181 - $allowHeaders = $request->headers->get('Access-Control-Request-Headers');  
182 - $this->varyHeader($response, 'Access-Control-Request-Headers');  
183 - } else {  
184 - $allowHeaders = implode(', ', $this->options['allowedHeaders']);  
185 - }  
186 - $response->headers->set('Access-Control-Allow-Headers', $allowHeaders);  
187 - }  
188 -  
189 - private function configureAllowCredentials(Response $response, Request $request)  
190 - {  
191 - if ($this->options['supportsCredentials']) {  
192 - $response->headers->set('Access-Control-Allow-Credentials', 'true');  
193 - }  
194 - }  
195 -  
196 - private function configureExposedHeaders(Response $response, Request $request)  
197 - {  
198 - if ($this->options['exposedHeaders']) {  
199 - $response->headers->set('Access-Control-Expose-Headers', implode(', ', $this->options['exposedHeaders']));  
200 - }  
201 - }  
202 -  
203 - private function configureMaxAge(Response $response, Request $request)  
204 - {  
205 - if ($this->options['maxAge'] !== null) {  
206 - $response->headers->set('Access-Control-Max-Age', (int) $this->options['maxAge']);  
207 - }  
208 - }  
209 -  
210 - public function varyHeader(Response $response, $header): Response  
211 - {  
212 - if (!$response->headers->has('Vary')) {  
213 - $response->headers->set('Vary', $header);  
214 - } elseif (!in_array($header, explode(', ', $response->headers->get('Vary')))) {  
215 - $response->headers->set('Vary', $response->headers->get('Vary') . ', ' . $header);  
216 - }  
217 -  
218 - return $response;  
219 - }  
220 -  
221 - private function isSameHost(Request $request): bool  
222 - {  
223 - return $request->headers->get('Origin') === $request->getSchemeAndHttpHost();  
224 - }  
225 -}  
1 -<?php  
2 -  
3 -// autoload.php @generated by Composer  
4 -  
5 -require_once __DIR__ . '/composer/autoload_real.php';  
6 -  
7 -return ComposerAutoloaderInitf0f55c3019081348437d7ad8517c7f84::getLoader();  
1 -../nesbot/carbon/bin/carbon  
1 -../symfony/error-handler/Resources/bin/patch-type-declarations  
1 -../nikic/php-parser/bin/php-parse  
1 -../phpunit/phpunit/phpunit  
1 -../psy/psysh/bin/psysh  
1 -../laravel/sail/bin/sail  
1 -../symfony/var-dumper/Resources/bin/var-dump-server  
1 -# Changelog  
2 -  
3 -All notable changes to this project will be documented in this file.  
4 -  
5 -## [0.9.3](https://github.com/brick/math/releases/tag/0.9.3) - 2021-08-15  
6 -  
7 -🚀 **Compatibility with PHP 8.1**  
8 -  
9 -- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (thanks @TRowbotham)  
10 -  
11 -## [0.9.2](https://github.com/brick/math/releases/tag/0.9.2) - 2021-01-20  
12 -  
13 -🐛 **Bug fix**  
14 -  
15 -- Incorrect results could be returned when using the BCMath calculator, with a default scale set with `bcscale()`, on PHP >= 7.2 (#55).  
16 -  
17 -## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19  
18 -  
19 -✨ New features  
20 -  
21 -- `BigInteger::not()` returns the bitwise `NOT` value  
22 -  
23 -🐛 **Bug fixes**  
24 -  
25 -- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers  
26 -- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available  
27 -  
28 -## [0.9.0](https://github.com/brick/math/releases/tag/0.9.0) - 2020-08-18  
29 -  
30 -👌 **Improvements**  
31 -  
32 -- `BigNumber::of()` now accepts `.123` and `123.` formats, both of which return a `BigDecimal`  
33 -  
34 -💥 **Breaking changes**  
35 -  
36 -- Deprecated method `BigInteger::powerMod()` has been removed - use `modPow()` instead  
37 -- Deprecated method `BigInteger::parse()` has been removed - use `fromBase()` instead  
38 -  
39 -## [0.8.17](https://github.com/brick/math/releases/tag/0.8.17) - 2020-08-19  
40 -  
41 -🐛 **Bug fix**  
42 -  
43 -- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers  
44 -- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available  
45 -  
46 -## [0.8.16](https://github.com/brick/math/releases/tag/0.8.16) - 2020-08-18  
47 -  
48 -🚑 **Critical fix**  
49 -  
50 -- This version reintroduces the deprecated `BigInteger::parse()` method, that has been removed by mistake in version `0.8.9` and should have lasted for the whole `0.8` release cycle.  
51 -  
52 -**New features**  
53 -  
54 -- `BigInteger::modInverse()` calculates a modular multiplicative inverse  
55 -- `BigInteger::fromBytes()` creates a `BigInteger` from a byte string  
56 -- `BigInteger::toBytes()` converts a `BigInteger` to a byte string  
57 -- `BigInteger::randomBits()` creates a pseudo-random `BigInteger` of a given bit length  
58 -- `BigInteger::randomRange()` creates a pseudo-random `BigInteger` between two bounds  
59 -  
60 -💩 **Deprecations**  
61 -  
62 -- `BigInteger::powerMod()` is now deprecated in favour of `modPow()`  
63 -  
64 -## [0.8.15](https://github.com/brick/math/releases/tag/0.8.15) - 2020-04-15  
65 -  
66 -🐛 **Fixes**  
67 -  
68 -- added missing `ext-json` requirement, due to `BigNumber` implementing `JsonSerializable`  
69 -  
70 -⚡️ **Optimizations**  
71 -  
72 -- additional optimization in `BigInteger::remainder()`  
73 -  
74 -## [0.8.14](https://github.com/brick/math/releases/tag/0.8.14) - 2020-02-18  
75 -  
76 -**New features**  
77 -  
78 -- `BigInteger::getLowestSetBit()` returns the index of the rightmost one bit  
79 -  
80 -## [0.8.13](https://github.com/brick/math/releases/tag/0.8.13) - 2020-02-16  
81 -  
82 -**New features**  
83 -  
84 -- `BigInteger::isEven()` tests whether the number is even  
85 -- `BigInteger::isOdd()` tests whether the number is odd  
86 -- `BigInteger::testBit()` tests if a bit is set  
87 -- `BigInteger::getBitLength()` returns the number of bits in the minimal representation of the number  
88 -  
89 -## [0.8.12](https://github.com/brick/math/releases/tag/0.8.12) - 2020-02-03  
90 -  
91 -🛠️ **Maintenance release**  
92 -  
93 -Classes are now annotated for better static analysis with [psalm](https://psalm.dev/).  
94 -  
95 -This is a maintenance release: no bug fixes, no new features, no breaking changes.  
96 -  
97 -## [0.8.11](https://github.com/brick/math/releases/tag/0.8.11) - 2020-01-23  
98 -  
99 -**New feature**  
100 -  
101 -`BigInteger::powerMod()` performs a power-with-modulo operation. Useful for crypto.  
102 -  
103 -## [0.8.10](https://github.com/brick/math/releases/tag/0.8.10) - 2020-01-21  
104 -  
105 -**New feature**  
106 -  
107 -`BigInteger::mod()` returns the **modulo** of two numbers. The *modulo* differs from the *remainder* when the signs of the operands are different.  
108 -  
109 -## [0.8.9](https://github.com/brick/math/releases/tag/0.8.9) - 2020-01-08  
110 -  
111 -⚡️ **Performance improvements**  
112 -  
113 -A few additional optimizations in `BigInteger` and `BigDecimal` when one of the operands can be returned as is. Thanks to @tomtomsen in #24.  
114 -  
115 -## [0.8.8](https://github.com/brick/math/releases/tag/0.8.8) - 2019-04-25  
116 -  
117 -🐛 **Bug fixes**  
118 -  
119 -- `BigInteger::toBase()` could return an empty string for zero values (BCMath & Native calculators only, GMP calculator unaffected)  
120 -  
121 -**New features**  
122 -  
123 -- `BigInteger::toArbitraryBase()` converts a number to an arbitrary base, using a custom alphabet  
124 -- `BigInteger::fromArbitraryBase()` converts a string in an arbitrary base, using a custom alphabet, back to a number  
125 -  
126 -These methods can be used as the foundation to convert strings between different bases/alphabets, using BigInteger as an intermediate representation.  
127 -  
128 -💩 **Deprecations**  
129 -  
130 -- `BigInteger::parse()` is now deprecated in favour of `fromBase()`  
131 -  
132 -`BigInteger::fromBase()` works the same way as `parse()`, with 2 minor differences:  
133 -  
134 -- the `$base` parameter is required, it does not default to `10`  
135 -- it throws a `NumberFormatException` instead of an `InvalidArgumentException` when the number is malformed  
136 -  
137 -## [0.8.7](https://github.com/brick/math/releases/tag/0.8.7) - 2019-04-20  
138 -  
139 -**Improvements**  
140 -  
141 -- Safer conversion from `float` when using custom locales  
142 -- **Much faster** `NativeCalculator` implementation 🚀  
143 -  
144 -You can expect **at least a 3x performance improvement** for common arithmetic operations when using the library on systems without GMP or BCMath; it gets exponentially faster on multiplications with a high number of digits. This is due to calculations now being performed on whole blocks of digits (the block size depending on the platform, 32-bit or 64-bit) instead of digit-by-digit as before.  
145 -  
146 -## [0.8.6](https://github.com/brick/math/releases/tag/0.8.6) - 2019-04-11  
147 -  
148 -**New method**  
149 -  
150 -`BigNumber::sum()` returns the sum of one or more numbers.  
151 -  
152 -## [0.8.5](https://github.com/brick/math/releases/tag/0.8.5) - 2019-02-12  
153 -  
154 -**Bug fix**: `of()` factory methods could fail when passing a `float` in environments using a `LC_NUMERIC` locale with a decimal separator other than `'.'` (#20).  
155 -  
156 -Thanks @manowark 👍  
157 -  
158 -## [0.8.4](https://github.com/brick/math/releases/tag/0.8.4) - 2018-12-07  
159 -  
160 -**New method**  
161 -  
162 -`BigDecimal::sqrt()` calculates the square root of a decimal number, to a given scale.  
163 -  
164 -## [0.8.3](https://github.com/brick/math/releases/tag/0.8.3) - 2018-12-06  
165 -  
166 -**New method**  
167 -  
168 -`BigInteger::sqrt()` calculates the square root of a number (thanks @peter279k).  
169 -  
170 -**New exception**  
171 -  
172 -`NegativeNumberException` is thrown when calling `sqrt()` on a negative number.  
173 -  
174 -## [0.8.2](https://github.com/brick/math/releases/tag/0.8.2) - 2018-11-08  
175 -  
176 -**Performance update**  
177 -  
178 -- Further improvement of `toInt()` performance  
179 -- `NativeCalculator` can now perform some multiplications more efficiently  
180 -  
181 -## [0.8.1](https://github.com/brick/math/releases/tag/0.8.1) - 2018-11-07  
182 -  
183 -Performance optimization of `toInt()` methods.  
184 -  
185 -## [0.8.0](https://github.com/brick/math/releases/tag/0.8.0) - 2018-10-13  
186 -  
187 -**Breaking changes**  
188 -  
189 -The following deprecated methods have been removed. Use the new method name instead:  
190 -  
191 -| Method removed | Replacement method |  
192 -| --- | --- |  
193 -| `BigDecimal::getIntegral()` | `BigDecimal::getIntegralPart()` |  
194 -| `BigDecimal::getFraction()` | `BigDecimal::getFractionalPart()` |  
195 -  
196 ----  
197 -  
198 -**New features**  
199 -  
200 -`BigInteger` has been augmented with 5 new methods for bitwise operations:  
201 -  
202 -| New method | Description |  
203 -| --- | --- |  
204 -| `and()` | performs a bitwise `AND` operation on two numbers |  
205 -| `or()` | performs a bitwise `OR` operation on two numbers |  
206 -| `xor()` | performs a bitwise `XOR` operation on two numbers |  
207 -| `shiftedLeft()` | returns the number shifted left by a number of bits |  
208 -| `shiftedRight()` | returns the number shifted right by a number of bits |  
209 -  
210 -Thanks to @DASPRiD 👍  
211 -  
212 -## [0.7.3](https://github.com/brick/math/releases/tag/0.7.3) - 2018-08-20  
213 -  
214 -**New method:** `BigDecimal::hasNonZeroFractionalPart()`  
215 -  
216 -**Renamed/deprecated methods:**  
217 -  
218 -- `BigDecimal::getIntegral()` has been renamed to `getIntegralPart()` and is now deprecated  
219 -- `BigDecimal::getFraction()` has been renamed to `getFractionalPart()` and is now deprecated  
220 -  
221 -## [0.7.2](https://github.com/brick/math/releases/tag/0.7.2) - 2018-07-21  
222 -  
223 -**Performance update**  
224 -  
225 -`BigInteger::parse()` and `toBase()` now use GMP's built-in base conversion features when available.  
226 -  
227 -## [0.7.1](https://github.com/brick/math/releases/tag/0.7.1) - 2018-03-01  
228 -  
229 -This is a maintenance release, no code has been changed.  
230 -  
231 -- When installed with `--no-dev`, the autoloader does not autoload tests anymore  
232 -- Tests and other files unnecessary for production are excluded from the dist package  
233 -  
234 -This will help make installations more compact.  
235 -  
236 -## [0.7.0](https://github.com/brick/math/releases/tag/0.7.0) - 2017-10-02  
237 -  
238 -Methods renamed:  
239 -  
240 -- `BigNumber:sign()` has been renamed to `getSign()`  
241 -- `BigDecimal::unscaledValue()` has been renamed to `getUnscaledValue()`  
242 -- `BigDecimal::scale()` has been renamed to `getScale()`  
243 -- `BigDecimal::integral()` has been renamed to `getIntegral()`  
244 -- `BigDecimal::fraction()` has been renamed to `getFraction()`  
245 -- `BigRational::numerator()` has been renamed to `getNumerator()`  
246 -- `BigRational::denominator()` has been renamed to `getDenominator()`  
247 -  
248 -Classes renamed:  
249 -  
250 -- `ArithmeticException` has been renamed to `MathException`  
251 -  
252 -## [0.6.2](https://github.com/brick/math/releases/tag/0.6.2) - 2017-10-02  
253 -  
254 -The base class for all exceptions is now `MathException`.  
255 -`ArithmeticException` has been deprecated, and will be removed in 0.7.0.  
256 -  
257 -## [0.6.1](https://github.com/brick/math/releases/tag/0.6.1) - 2017-10-02  
258 -  
259 -A number of methods have been renamed:  
260 -  
261 -- `BigNumber:sign()` is deprecated; use `getSign()` instead  
262 -- `BigDecimal::unscaledValue()` is deprecated; use `getUnscaledValue()` instead  
263 -- `BigDecimal::scale()` is deprecated; use `getScale()` instead  
264 -- `BigDecimal::integral()` is deprecated; use `getIntegral()` instead  
265 -- `BigDecimal::fraction()` is deprecated; use `getFraction()` instead  
266 -- `BigRational::numerator()` is deprecated; use `getNumerator()` instead  
267 -- `BigRational::denominator()` is deprecated; use `getDenominator()` instead  
268 -  
269 -The old methods will be removed in version 0.7.0.  
270 -  
271 -## [0.6.0](https://github.com/brick/math/releases/tag/0.6.0) - 2017-08-25  
272 -  
273 -- Minimum PHP version is now [7.1](https://gophp71.org/); for PHP 5.6 and PHP 7.0 support, use version `0.5`  
274 -- Deprecated method `BigDecimal::withScale()` has been removed; use `toScale()` instead  
275 -- Method `BigNumber::toInteger()` has been renamed to `toInt()`  
276 -  
277 -## [0.5.4](https://github.com/brick/math/releases/tag/0.5.4) - 2016-10-17  
278 -  
279 -`BigNumber` classes now implement [JsonSerializable](http://php.net/manual/en/class.jsonserializable.php).  
280 -The JSON output is always a string.  
281 -  
282 -## [0.5.3](https://github.com/brick/math/releases/tag/0.5.3) - 2016-03-31  
283 -  
284 -This is a bugfix release. Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.  
285 -  
286 -## [0.5.2](https://github.com/brick/math/releases/tag/0.5.2) - 2015-08-06  
287 -  
288 -The `$scale` parameter of `BigDecimal::dividedBy()` is now optional again.  
289 -  
290 -## [0.5.1](https://github.com/brick/math/releases/tag/0.5.1) - 2015-07-05  
291 -  
292 -**New method: `BigNumber::toScale()`**  
293 -  
294 -This allows to convert any `BigNumber` to a `BigDecimal` with a given scale, using rounding if necessary.  
295 -  
296 -## [0.5.0](https://github.com/brick/math/releases/tag/0.5.0) - 2015-07-04  
297 -  
298 -**New features**  
299 -- Common `BigNumber` interface for all classes, with the following methods:  
300 - - `sign()` and derived methods (`isZero()`, `isPositive()`, ...)  
301 - - `compareTo()` and derived methods (`isEqualTo()`, `isGreaterThan()`, ...) that work across different `BigNumber` types  
302 - - `toBigInteger()`, `toBigDecimal()`, `toBigRational`() conversion methods  
303 - - `toInteger()` and `toFloat()` conversion methods to native types  
304 -- Unified `of()` behaviour: every class now accepts any type of number, provided that it can be safely converted to the current type  
305 -- New method: `BigDecimal::exactlyDividedBy()`; this method automatically computes the scale of the result, provided that the division yields a finite number of digits  
306 -- New methods: `BigRational::quotient()` and `remainder()`  
307 -- Fine-grained exceptions: `DivisionByZeroException`, `RoundingNecessaryException`, `NumberFormatException`  
308 -- Factory methods `zero()`, `one()` and `ten()` available in all classes  
309 -- Rounding mode reintroduced in `BigInteger::dividedBy()`  
310 -  
311 -This release also comes with many performance improvements.  
312 -  
313 ----  
314 -  
315 -**Breaking changes**  
316 -- `BigInteger`:  
317 - - `getSign()` is renamed to `sign()`  
318 - - `toString()` is renamed to `toBase()`  
319 - - `BigInteger::dividedBy()` now throws an exception by default if the remainder is not zero; use `quotient()` to get the previous behaviour  
320 -- `BigDecimal`:  
321 - - `getSign()` is renamed to `sign()`  
322 - - `getUnscaledValue()` is renamed to `unscaledValue()`  
323 - - `getScale()` is renamed to `scale()`  
324 - - `getIntegral()` is renamed to `integral()`  
325 - - `getFraction()` is renamed to `fraction()`  
326 - - `divideAndRemainder()` is renamed to `quotientAndRemainder()`  
327 - - `dividedBy()` now takes a **mandatory** `$scale` parameter **before** the rounding mode  
328 - - `toBigInteger()` does not accept a `$roundingMode` parameter any more  
329 - - `toBigRational()` does not simplify the fraction any more; explicitly add `->simplified()` to get the previous behaviour  
330 -- `BigRational`:  
331 - - `getSign()` is renamed to `sign()`  
332 - - `getNumerator()` is renamed to `numerator()`  
333 - - `getDenominator()` is renamed to `denominator()`  
334 - - `of()` is renamed to `nd()`, while `parse()` is renamed to `of()`  
335 -- Miscellaneous:  
336 - - `ArithmeticException` is moved to an `Exception\` sub-namespace  
337 - - `of()` factory methods now throw `NumberFormatException` instead of `InvalidArgumentException`  
338 -  
339 -## [0.4.3](https://github.com/brick/math/releases/tag/0.4.3) - 2016-03-31  
340 -  
341 -Backport of two bug fixes from the 0.5 branch:  
342 -- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected  
343 -- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.  
344 -  
345 -## [0.4.2](https://github.com/brick/math/releases/tag/0.4.2) - 2015-06-16  
346 -  
347 -New method: `BigDecimal::stripTrailingZeros()`  
348 -  
349 -## [0.4.1](https://github.com/brick/math/releases/tag/0.4.1) - 2015-06-12  
350 -  
351 -Introducing a `BigRational` class, to perform calculations on fractions of any size.  
352 -  
353 -## [0.4.0](https://github.com/brick/math/releases/tag/0.4.0) - 2015-06-12  
354 -  
355 -Rounding modes have been removed from `BigInteger`, and are now a concept specific to `BigDecimal`.  
356 -  
357 -`BigInteger::dividedBy()` now always returns the quotient of the division.  
358 -  
359 -## [0.3.5](https://github.com/brick/math/releases/tag/0.3.5) - 2016-03-31  
360 -  
361 -Backport of two bug fixes from the 0.5 branch:  
362 -  
363 -- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected  
364 -- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.  
365 -  
366 -## [0.3.4](https://github.com/brick/math/releases/tag/0.3.4) - 2015-06-11  
367 -  
368 -New methods:  
369 -- `BigInteger::remainder()` returns the remainder of a division only  
370 -- `BigInteger::gcd()` returns the greatest common divisor of two numbers  
371 -  
372 -## [0.3.3](https://github.com/brick/math/releases/tag/0.3.3) - 2015-06-07  
373 -  
374 -Fix `toString()` not handling negative numbers.  
375 -  
376 -## [0.3.2](https://github.com/brick/math/releases/tag/0.3.2) - 2015-06-07  
377 -  
378 -`BigInteger` and `BigDecimal` now have a `getSign()` method that returns:  
379 -- `-1` if the number is negative  
380 -- `0` if the number is zero  
381 -- `1` if the number is positive  
382 -  
383 -## [0.3.1](https://github.com/brick/math/releases/tag/0.3.1) - 2015-06-05  
384 -  
385 -Minor performance improvements  
386 -  
387 -## [0.3.0](https://github.com/brick/math/releases/tag/0.3.0) - 2015-06-04  
388 -  
389 -The `$roundingMode` and `$scale` parameters have been swapped in `BigDecimal::dividedBy()`.  
390 -  
391 -## [0.2.2](https://github.com/brick/math/releases/tag/0.2.2) - 2015-06-04  
392 -  
393 -Stronger immutability guarantee for `BigInteger` and `BigDecimal`.  
394 -  
395 -So far, it would have been possible to break immutability of these classes by calling the `unserialize()` internal function. This release fixes that.  
396 -  
397 -## [0.2.1](https://github.com/brick/math/releases/tag/0.2.1) - 2015-06-02  
398 -  
399 -Added `BigDecimal::divideAndRemainder()`  
400 -  
401 -## [0.2.0](https://github.com/brick/math/releases/tag/0.2.0) - 2015-05-22  
402 -  
403 -- `min()` and `max()` do not accept an `array` any more, but a variable number of parameters  
404 -- **minimum PHP version is now 5.6**  
405 -- continuous integration with PHP 7  
406 -  
407 -## [0.1.1](https://github.com/brick/math/releases/tag/0.1.1) - 2014-09-01  
408 -  
409 -- Added `BigInteger::power()`  
410 -- Added HHVM support  
411 -  
412 -## [0.1.0](https://github.com/brick/math/releases/tag/0.1.0) - 2014-08-31  
413 -  
414 -First beta release.  
415 -  
1 -The MIT License (MIT)  
2 -  
3 -Copyright (c) 2013-present Benjamin Morel  
4 -  
5 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
6 -this software and associated documentation files (the "Software"), to deal in  
7 -the Software without restriction, including without limitation the rights to  
8 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
9 -the Software, and to permit persons to whom the Software is furnished to do so,  
10 -subject to the following conditions:  
11 -  
12 -The above copyright notice and this permission notice shall be included in all  
13 -copies or substantial portions of the Software.  
14 -  
15 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
16 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
17 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
18 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
19 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
20 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
1 -# Security Policy  
2 -  
3 -## Supported Versions  
4 -  
5 -Only the last two release streams are supported.  
6 -  
7 -| Version | Supported |  
8 -| ------- | ------------------ |  
9 -| 0.9.x | :white_check_mark: |  
10 -| 0.8.x | :white_check_mark: |  
11 -| < 0.8 | :x: |  
12 -  
13 -## Reporting a Vulnerability  
14 -  
15 -To report a security vulnerability, please use the  
16 -[Tidelift security contact](https://tidelift.com/security).  
17 -Tidelift will coordinate the fix and disclosure.  
1 -{  
2 - "name": "brick/math",  
3 - "description": "Arbitrary-precision arithmetic library",  
4 - "type": "library",  
5 - "keywords": [  
6 - "Brick",  
7 - "Math",  
8 - "Arbitrary-precision",  
9 - "Arithmetic",  
10 - "BigInteger",  
11 - "BigDecimal",  
12 - "BigRational",  
13 - "Bignum"  
14 - ],  
15 - "license": "MIT",  
16 - "require": {  
17 - "php": "^7.1 || ^8.0",  
18 - "ext-json": "*"  
19 - },  
20 - "require-dev": {  
21 - "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",  
22 - "php-coveralls/php-coveralls": "^2.2",  
23 - "vimeo/psalm": "4.9.2"  
24 - },  
25 - "autoload": {  
26 - "psr-4": {  
27 - "Brick\\Math\\": "src/"  
28 - }  
29 - },  
30 - "autoload-dev": {  
31 - "psr-4": {  
32 - "Brick\\Math\\Tests\\": "tests/"  
33 - }  
34 - }  
35 -}  
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\NegativeNumberException;  
10 -use Brick\Math\Internal\Calculator;  
11 -  
12 -/**  
13 - * Immutable, arbitrary-precision signed decimal numbers.  
14 - *  
15 - * @psalm-immutable  
16 - */  
17 -final class BigDecimal extends BigNumber  
18 -{  
19 - /**  
20 - * The unscaled value of this decimal number.  
21 - *  
22 - * This is a string of digits with an optional leading minus sign.  
23 - * No leading zero must be present.  
24 - * No leading minus sign must be present if the value is 0.  
25 - *  
26 - * @var string  
27 - */  
28 - private $value;  
29 -  
30 - /**  
31 - * The scale (number of digits after the decimal point) of this decimal number.  
32 - *  
33 - * This must be zero or more.  
34 - *  
35 - * @var int  
36 - */  
37 - private $scale;  
38 -  
39 - /**  
40 - * Protected constructor. Use a factory method to obtain an instance.  
41 - *  
42 - * @param string $value The unscaled value, validated.  
43 - * @param int $scale The scale, validated.  
44 - */  
45 - protected function __construct(string $value, int $scale = 0)  
46 - {  
47 - $this->value = $value;  
48 - $this->scale = $scale;  
49 - }  
50 -  
51 - /**  
52 - * Creates a BigDecimal of the given value.  
53 - *  
54 - * @param BigNumber|int|float|string $value  
55 - *  
56 - * @return BigDecimal  
57 - *  
58 - * @throws MathException If the value cannot be converted to a BigDecimal.  
59 - *  
60 - * @psalm-pure  
61 - */  
62 - public static function of($value) : BigNumber  
63 - {  
64 - return parent::of($value)->toBigDecimal();  
65 - }  
66 -  
67 - /**  
68 - * Creates a BigDecimal from an unscaled value and a scale.  
69 - *  
70 - * Example: `(12345, 3)` will result in the BigDecimal `12.345`.  
71 - *  
72 - * @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger.  
73 - * @param int $scale The scale of the number, positive or zero.  
74 - *  
75 - * @return BigDecimal  
76 - *  
77 - * @throws \InvalidArgumentException If the scale is negative.  
78 - *  
79 - * @psalm-pure  
80 - */  
81 - public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal  
82 - {  
83 - if ($scale < 0) {  
84 - throw new \InvalidArgumentException('The scale cannot be negative.');  
85 - }  
86 -  
87 - return new BigDecimal((string) BigInteger::of($value), $scale);  
88 - }  
89 -  
90 - /**  
91 - * Returns a BigDecimal representing zero, with a scale of zero.  
92 - *  
93 - * @return BigDecimal  
94 - *  
95 - * @psalm-pure  
96 - */  
97 - public static function zero() : BigDecimal  
98 - {  
99 - /**  
100 - * @psalm-suppress ImpureStaticVariable  
101 - * @var BigDecimal|null $zero  
102 - */  
103 - static $zero;  
104 -  
105 - if ($zero === null) {  
106 - $zero = new BigDecimal('0');  
107 - }  
108 -  
109 - return $zero;  
110 - }  
111 -  
112 - /**  
113 - * Returns a BigDecimal representing one, with a scale of zero.  
114 - *  
115 - * @return BigDecimal  
116 - *  
117 - * @psalm-pure  
118 - */  
119 - public static function one() : BigDecimal  
120 - {  
121 - /**  
122 - * @psalm-suppress ImpureStaticVariable  
123 - * @var BigDecimal|null $one  
124 - */  
125 - static $one;  
126 -  
127 - if ($one === null) {  
128 - $one = new BigDecimal('1');  
129 - }  
130 -  
131 - return $one;  
132 - }  
133 -  
134 - /**  
135 - * Returns a BigDecimal representing ten, with a scale of zero.  
136 - *  
137 - * @return BigDecimal  
138 - *  
139 - * @psalm-pure  
140 - */  
141 - public static function ten() : BigDecimal  
142 - {  
143 - /**  
144 - * @psalm-suppress ImpureStaticVariable  
145 - * @var BigDecimal|null $ten  
146 - */  
147 - static $ten;  
148 -  
149 - if ($ten === null) {  
150 - $ten = new BigDecimal('10');  
151 - }  
152 -  
153 - return $ten;  
154 - }  
155 -  
156 - /**  
157 - * Returns the sum of this number and the given one.  
158 - *  
159 - * The result has a scale of `max($this->scale, $that->scale)`.  
160 - *  
161 - * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal.  
162 - *  
163 - * @return BigDecimal The result.  
164 - *  
165 - * @throws MathException If the number is not valid, or is not convertible to a BigDecimal.  
166 - */  
167 - public function plus($that) : BigDecimal  
168 - {  
169 - $that = BigDecimal::of($that);  
170 -  
171 - if ($that->value === '0' && $that->scale <= $this->scale) {  
172 - return $this;  
173 - }  
174 -  
175 - if ($this->value === '0' && $this->scale <= $that->scale) {  
176 - return $that;  
177 - }  
178 -  
179 - [$a, $b] = $this->scaleValues($this, $that);  
180 -  
181 - $value = Calculator::get()->add($a, $b);  
182 - $scale = $this->scale > $that->scale ? $this->scale : $that->scale;  
183 -  
184 - return new BigDecimal($value, $scale);  
185 - }  
186 -  
187 - /**  
188 - * Returns the difference of this number and the given one.  
189 - *  
190 - * The result has a scale of `max($this->scale, $that->scale)`.  
191 - *  
192 - * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal.  
193 - *  
194 - * @return BigDecimal The result.  
195 - *  
196 - * @throws MathException If the number is not valid, or is not convertible to a BigDecimal.  
197 - */  
198 - public function minus($that) : BigDecimal  
199 - {  
200 - $that = BigDecimal::of($that);  
201 -  
202 - if ($that->value === '0' && $that->scale <= $this->scale) {  
203 - return $this;  
204 - }  
205 -  
206 - [$a, $b] = $this->scaleValues($this, $that);  
207 -  
208 - $value = Calculator::get()->sub($a, $b);  
209 - $scale = $this->scale > $that->scale ? $this->scale : $that->scale;  
210 -  
211 - return new BigDecimal($value, $scale);  
212 - }  
213 -  
214 - /**  
215 - * Returns the product of this number and the given one.  
216 - *  
217 - * The result has a scale of `$this->scale + $that->scale`.  
218 - *  
219 - * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal.  
220 - *  
221 - * @return BigDecimal The result.  
222 - *  
223 - * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal.  
224 - */  
225 - public function multipliedBy($that) : BigDecimal  
226 - {  
227 - $that = BigDecimal::of($that);  
228 -  
229 - if ($that->value === '1' && $that->scale === 0) {  
230 - return $this;  
231 - }  
232 -  
233 - if ($this->value === '1' && $this->scale === 0) {  
234 - return $that;  
235 - }  
236 -  
237 - $value = Calculator::get()->mul($this->value, $that->value);  
238 - $scale = $this->scale + $that->scale;  
239 -  
240 - return new BigDecimal($value, $scale);  
241 - }  
242 -  
243 - /**  
244 - * Returns the result of the division of this number by the given one, at the given scale.  
245 - *  
246 - * @param BigNumber|int|float|string $that The divisor.  
247 - * @param int|null $scale The desired scale, or null to use the scale of this number.  
248 - * @param int $roundingMode An optional rounding mode.  
249 - *  
250 - * @return BigDecimal  
251 - *  
252 - * @throws \InvalidArgumentException If the scale or rounding mode is invalid.  
253 - * @throws MathException If the number is invalid, is zero, or rounding was necessary.  
254 - */  
255 - public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal  
256 - {  
257 - $that = BigDecimal::of($that);  
258 -  
259 - if ($that->isZero()) {  
260 - throw DivisionByZeroException::divisionByZero();  
261 - }  
262 -  
263 - if ($scale === null) {  
264 - $scale = $this->scale;  
265 - } elseif ($scale < 0) {  
266 - throw new \InvalidArgumentException('Scale cannot be negative.');  
267 - }  
268 -  
269 - if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) {  
270 - return $this;  
271 - }  
272 -  
273 - $p = $this->valueWithMinScale($that->scale + $scale);  
274 - $q = $that->valueWithMinScale($this->scale - $scale);  
275 -  
276 - $result = Calculator::get()->divRound($p, $q, $roundingMode);  
277 -  
278 - return new BigDecimal($result, $scale);  
279 - }  
280 -  
281 - /**  
282 - * Returns the exact result of the division of this number by the given one.  
283 - *  
284 - * The scale of the result is automatically calculated to fit all the fraction digits.  
285 - *  
286 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.  
287 - *  
288 - * @return BigDecimal The result.  
289 - *  
290 - * @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero,  
291 - * or the result yields an infinite number of digits.  
292 - */  
293 - public function exactlyDividedBy($that) : BigDecimal  
294 - {  
295 - $that = BigDecimal::of($that);  
296 -  
297 - if ($that->value === '0') {  
298 - throw DivisionByZeroException::divisionByZero();  
299 - }  
300 -  
301 - [, $b] = $this->scaleValues($this, $that);  
302 -  
303 - $d = \rtrim($b, '0');  
304 - $scale = \strlen($b) - \strlen($d);  
305 -  
306 - $calculator = Calculator::get();  
307 -  
308 - foreach ([5, 2] as $prime) {  
309 - for (;;) {  
310 - $lastDigit = (int) $d[-1];  
311 -  
312 - if ($lastDigit % $prime !== 0) {  
313 - break;  
314 - }  
315 -  
316 - $d = $calculator->divQ($d, (string) $prime);  
317 - $scale++;  
318 - }  
319 - }  
320 -  
321 - return $this->dividedBy($that, $scale)->stripTrailingZeros();  
322 - }  
323 -  
324 - /**  
325 - * Returns this number exponentiated to the given value.  
326 - *  
327 - * The result has a scale of `$this->scale * $exponent`.  
328 - *  
329 - * @param int $exponent The exponent.  
330 - *  
331 - * @return BigDecimal The result.  
332 - *  
333 - * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.  
334 - */  
335 - public function power(int $exponent) : BigDecimal  
336 - {  
337 - if ($exponent === 0) {  
338 - return BigDecimal::one();  
339 - }  
340 -  
341 - if ($exponent === 1) {  
342 - return $this;  
343 - }  
344 -  
345 - if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {  
346 - throw new \InvalidArgumentException(\sprintf(  
347 - 'The exponent %d is not in the range 0 to %d.',  
348 - $exponent,  
349 - Calculator::MAX_POWER  
350 - ));  
351 - }  
352 -  
353 - return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent);  
354 - }  
355 -  
356 - /**  
357 - * Returns the quotient of the division of this number by this given one.  
358 - *  
359 - * The quotient has a scale of `0`.  
360 - *  
361 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.  
362 - *  
363 - * @return BigDecimal The quotient.  
364 - *  
365 - * @throws MathException If the divisor is not a valid decimal number, or is zero.  
366 - */  
367 - public function quotient($that) : BigDecimal  
368 - {  
369 - $that = BigDecimal::of($that);  
370 -  
371 - if ($that->isZero()) {  
372 - throw DivisionByZeroException::divisionByZero();  
373 - }  
374 -  
375 - $p = $this->valueWithMinScale($that->scale);  
376 - $q = $that->valueWithMinScale($this->scale);  
377 -  
378 - $quotient = Calculator::get()->divQ($p, $q);  
379 -  
380 - return new BigDecimal($quotient, 0);  
381 - }  
382 -  
383 - /**  
384 - * Returns the remainder of the division of this number by this given one.  
385 - *  
386 - * The remainder has a scale of `max($this->scale, $that->scale)`.  
387 - *  
388 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.  
389 - *  
390 - * @return BigDecimal The remainder.  
391 - *  
392 - * @throws MathException If the divisor is not a valid decimal number, or is zero.  
393 - */  
394 - public function remainder($that) : BigDecimal  
395 - {  
396 - $that = BigDecimal::of($that);  
397 -  
398 - if ($that->isZero()) {  
399 - throw DivisionByZeroException::divisionByZero();  
400 - }  
401 -  
402 - $p = $this->valueWithMinScale($that->scale);  
403 - $q = $that->valueWithMinScale($this->scale);  
404 -  
405 - $remainder = Calculator::get()->divR($p, $q);  
406 -  
407 - $scale = $this->scale > $that->scale ? $this->scale : $that->scale;  
408 -  
409 - return new BigDecimal($remainder, $scale);  
410 - }  
411 -  
412 - /**  
413 - * Returns the quotient and remainder of the division of this number by the given one.  
414 - *  
415 - * The quotient has a scale of `0`, and the remainder has a scale of `max($this->scale, $that->scale)`.  
416 - *  
417 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.  
418 - *  
419 - * @return BigDecimal[] An array containing the quotient and the remainder.  
420 - *  
421 - * @throws MathException If the divisor is not a valid decimal number, or is zero.  
422 - */  
423 - public function quotientAndRemainder($that) : array  
424 - {  
425 - $that = BigDecimal::of($that);  
426 -  
427 - if ($that->isZero()) {  
428 - throw DivisionByZeroException::divisionByZero();  
429 - }  
430 -  
431 - $p = $this->valueWithMinScale($that->scale);  
432 - $q = $that->valueWithMinScale($this->scale);  
433 -  
434 - [$quotient, $remainder] = Calculator::get()->divQR($p, $q);  
435 -  
436 - $scale = $this->scale > $that->scale ? $this->scale : $that->scale;  
437 -  
438 - $quotient = new BigDecimal($quotient, 0);  
439 - $remainder = new BigDecimal($remainder, $scale);  
440 -  
441 - return [$quotient, $remainder];  
442 - }  
443 -  
444 - /**  
445 - * Returns the square root of this number, rounded down to the given number of decimals.  
446 - *  
447 - * @param int $scale  
448 - *  
449 - * @return BigDecimal  
450 - *  
451 - * @throws \InvalidArgumentException If the scale is negative.  
452 - * @throws NegativeNumberException If this number is negative.  
453 - */  
454 - public function sqrt(int $scale) : BigDecimal  
455 - {  
456 - if ($scale < 0) {  
457 - throw new \InvalidArgumentException('Scale cannot be negative.');  
458 - }  
459 -  
460 - if ($this->value === '0') {  
461 - return new BigDecimal('0', $scale);  
462 - }  
463 -  
464 - if ($this->value[0] === '-') {  
465 - throw new NegativeNumberException('Cannot calculate the square root of a negative number.');  
466 - }  
467 -  
468 - $value = $this->value;  
469 - $addDigits = 2 * $scale - $this->scale;  
470 -  
471 - if ($addDigits > 0) {  
472 - // add zeros  
473 - $value .= \str_repeat('0', $addDigits);  
474 - } elseif ($addDigits < 0) {  
475 - // trim digits  
476 - if (-$addDigits >= \strlen($this->value)) {  
477 - // requesting a scale too low, will always yield a zero result  
478 - return new BigDecimal('0', $scale);  
479 - }  
480 -  
481 - $value = \substr($value, 0, $addDigits);  
482 - }  
483 -  
484 - $value = Calculator::get()->sqrt($value);  
485 -  
486 - return new BigDecimal($value, $scale);  
487 - }  
488 -  
489 - /**  
490 - * Returns a copy of this BigDecimal with the decimal point moved $n places to the left.  
491 - *  
492 - * @param int $n  
493 - *  
494 - * @return BigDecimal  
495 - */  
496 - public function withPointMovedLeft(int $n) : BigDecimal  
497 - {  
498 - if ($n === 0) {  
499 - return $this;  
500 - }  
501 -  
502 - if ($n < 0) {  
503 - return $this->withPointMovedRight(-$n);  
504 - }  
505 -  
506 - return new BigDecimal($this->value, $this->scale + $n);  
507 - }  
508 -  
509 - /**  
510 - * Returns a copy of this BigDecimal with the decimal point moved $n places to the right.  
511 - *  
512 - * @param int $n  
513 - *  
514 - * @return BigDecimal  
515 - */  
516 - public function withPointMovedRight(int $n) : BigDecimal  
517 - {  
518 - if ($n === 0) {  
519 - return $this;  
520 - }  
521 -  
522 - if ($n < 0) {  
523 - return $this->withPointMovedLeft(-$n);  
524 - }  
525 -  
526 - $value = $this->value;  
527 - $scale = $this->scale - $n;  
528 -  
529 - if ($scale < 0) {  
530 - if ($value !== '0') {  
531 - $value .= \str_repeat('0', -$scale);  
532 - }  
533 - $scale = 0;  
534 - }  
535 -  
536 - return new BigDecimal($value, $scale);  
537 - }  
538 -  
539 - /**  
540 - * Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part.  
541 - *  
542 - * @return BigDecimal  
543 - */  
544 - public function stripTrailingZeros() : BigDecimal  
545 - {  
546 - if ($this->scale === 0) {  
547 - return $this;  
548 - }  
549 -  
550 - $trimmedValue = \rtrim($this->value, '0');  
551 -  
552 - if ($trimmedValue === '') {  
553 - return BigDecimal::zero();  
554 - }  
555 -  
556 - $trimmableZeros = \strlen($this->value) - \strlen($trimmedValue);  
557 -  
558 - if ($trimmableZeros === 0) {  
559 - return $this;  
560 - }  
561 -  
562 - if ($trimmableZeros > $this->scale) {  
563 - $trimmableZeros = $this->scale;  
564 - }  
565 -  
566 - $value = \substr($this->value, 0, -$trimmableZeros);  
567 - $scale = $this->scale - $trimmableZeros;  
568 -  
569 - return new BigDecimal($value, $scale);  
570 - }  
571 -  
572 - /**  
573 - * Returns the absolute value of this number.  
574 - *  
575 - * @return BigDecimal  
576 - */  
577 - public function abs() : BigDecimal  
578 - {  
579 - return $this->isNegative() ? $this->negated() : $this;  
580 - }  
581 -  
582 - /**  
583 - * Returns the negated value of this number.  
584 - *  
585 - * @return BigDecimal  
586 - */  
587 - public function negated() : BigDecimal  
588 - {  
589 - return new BigDecimal(Calculator::get()->neg($this->value), $this->scale);  
590 - }  
591 -  
592 - /**  
593 - * {@inheritdoc}  
594 - */  
595 - public function compareTo($that) : int  
596 - {  
597 - $that = BigNumber::of($that);  
598 -  
599 - if ($that instanceof BigInteger) {  
600 - $that = $that->toBigDecimal();  
601 - }  
602 -  
603 - if ($that instanceof BigDecimal) {  
604 - [$a, $b] = $this->scaleValues($this, $that);  
605 -  
606 - return Calculator::get()->cmp($a, $b);  
607 - }  
608 -  
609 - return - $that->compareTo($this);  
610 - }  
611 -  
612 - /**  
613 - * {@inheritdoc}  
614 - */  
615 - public function getSign() : int  
616 - {  
617 - return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);  
618 - }  
619 -  
620 - /**  
621 - * @return BigInteger  
622 - */  
623 - public function getUnscaledValue() : BigInteger  
624 - {  
625 - return BigInteger::create($this->value);  
626 - }  
627 -  
628 - /**  
629 - * @return int  
630 - */  
631 - public function getScale() : int  
632 - {  
633 - return $this->scale;  
634 - }  
635 -  
636 - /**  
637 - * Returns a string representing the integral part of this decimal number.  
638 - *  
639 - * Example: `-123.456` => `-123`.  
640 - *  
641 - * @return string  
642 - */  
643 - public function getIntegralPart() : string  
644 - {  
645 - if ($this->scale === 0) {  
646 - return $this->value;  
647 - }  
648 -  
649 - $value = $this->getUnscaledValueWithLeadingZeros();  
650 -  
651 - return \substr($value, 0, -$this->scale);  
652 - }  
653 -  
654 - /**  
655 - * Returns a string representing the fractional part of this decimal number.  
656 - *  
657 - * If the scale is zero, an empty string is returned.  
658 - *  
659 - * Examples: `-123.456` => '456', `123` => ''.  
660 - *  
661 - * @return string  
662 - */  
663 - public function getFractionalPart() : string  
664 - {  
665 - if ($this->scale === 0) {  
666 - return '';  
667 - }  
668 -  
669 - $value = $this->getUnscaledValueWithLeadingZeros();  
670 -  
671 - return \substr($value, -$this->scale);  
672 - }  
673 -  
674 - /**  
675 - * Returns whether this decimal number has a non-zero fractional part.  
676 - *  
677 - * @return bool  
678 - */  
679 - public function hasNonZeroFractionalPart() : bool  
680 - {  
681 - return $this->getFractionalPart() !== \str_repeat('0', $this->scale);  
682 - }  
683 -  
684 - /**  
685 - * {@inheritdoc}  
686 - */  
687 - public function toBigInteger() : BigInteger  
688 - {  
689 - $zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0);  
690 -  
691 - return BigInteger::create($zeroScaleDecimal->value);  
692 - }  
693 -  
694 - /**  
695 - * {@inheritdoc}  
696 - */  
697 - public function toBigDecimal() : BigDecimal  
698 - {  
699 - return $this;  
700 - }  
701 -  
702 - /**  
703 - * {@inheritdoc}  
704 - */  
705 - public function toBigRational() : BigRational  
706 - {  
707 - $numerator = BigInteger::create($this->value);  
708 - $denominator = BigInteger::create('1' . \str_repeat('0', $this->scale));  
709 -  
710 - return BigRational::create($numerator, $denominator, false);  
711 - }  
712 -  
713 - /**  
714 - * {@inheritdoc}  
715 - */  
716 - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal  
717 - {  
718 - if ($scale === $this->scale) {  
719 - return $this;  
720 - }  
721 -  
722 - return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode);  
723 - }  
724 -  
725 - /**  
726 - * {@inheritdoc}  
727 - */  
728 - public function toInt() : int  
729 - {  
730 - return $this->toBigInteger()->toInt();  
731 - }  
732 -  
733 - /**  
734 - * {@inheritdoc}  
735 - */  
736 - public function toFloat() : float  
737 - {  
738 - return (float) (string) $this;  
739 - }  
740 -  
741 - /**  
742 - * {@inheritdoc}  
743 - */  
744 - public function __toString() : string  
745 - {  
746 - if ($this->scale === 0) {  
747 - return $this->value;  
748 - }  
749 -  
750 - $value = $this->getUnscaledValueWithLeadingZeros();  
751 -  
752 - return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->scale);  
753 - }  
754 -  
755 - /**  
756 - * This method is required for serializing the object and SHOULD NOT be accessed directly.  
757 - *  
758 - * @internal  
759 - *  
760 - * @return array{value: string, scale: int}  
761 - */  
762 - public function __serialize(): array  
763 - {  
764 - return ['value' => $this->value, 'scale' => $this->scale];  
765 - }  
766 -  
767 - /**  
768 - * This method is only here to allow unserializing the object and cannot be accessed directly.  
769 - *  
770 - * @internal  
771 - * @psalm-suppress RedundantPropertyInitializationCheck  
772 - *  
773 - * @param array{value: string, scale: int} $data  
774 - *  
775 - * @return void  
776 - *  
777 - * @throws \LogicException  
778 - */  
779 - public function __unserialize(array $data): void  
780 - {  
781 - if (isset($this->value)) {  
782 - throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');  
783 - }  
784 -  
785 - $this->value = $data['value'];  
786 - $this->scale = $data['scale'];  
787 - }  
788 -  
789 - /**  
790 - * This method is required by interface Serializable and SHOULD NOT be accessed directly.  
791 - *  
792 - * @internal  
793 - *  
794 - * @return string  
795 - */  
796 - public function serialize() : string  
797 - {  
798 - return $this->value . ':' . $this->scale;  
799 - }  
800 -  
801 - /**  
802 - * This method is only here to implement interface Serializable and cannot be accessed directly.  
803 - *  
804 - * @internal  
805 - * @psalm-suppress RedundantPropertyInitializationCheck  
806 - *  
807 - * @param string $value  
808 - *  
809 - * @return void  
810 - *  
811 - * @throws \LogicException  
812 - */  
813 - public function unserialize($value) : void  
814 - {  
815 - if (isset($this->value)) {  
816 - throw new \LogicException('unserialize() is an internal function, it must not be called directly.');  
817 - }  
818 -  
819 - [$value, $scale] = \explode(':', $value);  
820 -  
821 - $this->value = $value;  
822 - $this->scale = (int) $scale;  
823 - }  
824 -  
825 - /**  
826 - * Puts the internal values of the given decimal numbers on the same scale.  
827 - *  
828 - * @param BigDecimal $x The first decimal number.  
829 - * @param BigDecimal $y The second decimal number.  
830 - *  
831 - * @return array{string, string} The scaled integer values of $x and $y.  
832 - */  
833 - private function scaleValues(BigDecimal $x, BigDecimal $y) : array  
834 - {  
835 - $a = $x->value;  
836 - $b = $y->value;  
837 -  
838 - if ($b !== '0' && $x->scale > $y->scale) {  
839 - $b .= \str_repeat('0', $x->scale - $y->scale);  
840 - } elseif ($a !== '0' && $x->scale < $y->scale) {  
841 - $a .= \str_repeat('0', $y->scale - $x->scale);  
842 - }  
843 -  
844 - return [$a, $b];  
845 - }  
846 -  
847 - /**  
848 - * @param int $scale  
849 - *  
850 - * @return string  
851 - */  
852 - private function valueWithMinScale(int $scale) : string  
853 - {  
854 - $value = $this->value;  
855 -  
856 - if ($this->value !== '0' && $scale > $this->scale) {  
857 - $value .= \str_repeat('0', $scale - $this->scale);  
858 - }  
859 -  
860 - return $value;  
861 - }  
862 -  
863 - /**  
864 - * Adds leading zeros if necessary to the unscaled value to represent the full decimal number.  
865 - *  
866 - * @return string  
867 - */  
868 - private function getUnscaledValueWithLeadingZeros() : string  
869 - {  
870 - $value = $this->value;  
871 - $targetLength = $this->scale + 1;  
872 - $negative = ($value[0] === '-');  
873 - $length = \strlen($value);  
874 -  
875 - if ($negative) {  
876 - $length--;  
877 - }  
878 -  
879 - if ($length >= $targetLength) {  
880 - return $this->value;  
881 - }  
882 -  
883 - if ($negative) {  
884 - $value = \substr($value, 1);  
885 - }  
886 -  
887 - $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT);  
888 -  
889 - if ($negative) {  
890 - $value = '-' . $value;  
891 - }  
892 -  
893 - return $value;  
894 - }  
895 -}  
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\IntegerOverflowException;  
9 -use Brick\Math\Exception\MathException;  
10 -use Brick\Math\Exception\NegativeNumberException;  
11 -use Brick\Math\Exception\NumberFormatException;  
12 -use Brick\Math\Internal\Calculator;  
13 -  
14 -/**  
15 - * An arbitrary-size integer.  
16 - *  
17 - * All methods accepting a number as a parameter accept either a BigInteger instance,  
18 - * an integer, or a string representing an arbitrary size integer.  
19 - *  
20 - * @psalm-immutable  
21 - */  
22 -final class BigInteger extends BigNumber  
23 -{  
24 - /**  
25 - * The value, as a string of digits with optional leading minus sign.  
26 - *  
27 - * No leading zeros must be present.  
28 - * No leading minus sign must be present if the number is zero.  
29 - *  
30 - * @var string  
31 - */  
32 - private $value;  
33 -  
34 - /**  
35 - * Protected constructor. Use a factory method to obtain an instance.  
36 - *  
37 - * @param string $value A string of digits, with optional leading minus sign.  
38 - */  
39 - protected function __construct(string $value)  
40 - {  
41 - $this->value = $value;  
42 - }  
43 -  
44 - /**  
45 - * Creates a BigInteger of the given value.  
46 - *  
47 - * @param BigNumber|int|float|string $value  
48 - *  
49 - * @return BigInteger  
50 - *  
51 - * @throws MathException If the value cannot be converted to a BigInteger.  
52 - *  
53 - * @psalm-pure  
54 - */  
55 - public static function of($value) : BigNumber  
56 - {  
57 - return parent::of($value)->toBigInteger();  
58 - }  
59 -  
60 - /**  
61 - * Creates a number from a string in a given base.  
62 - *  
63 - * The string can optionally be prefixed with the `+` or `-` sign.  
64 - *  
65 - * Bases greater than 36 are not supported by this method, as there is no clear consensus on which of the lowercase  
66 - * or uppercase characters should come first. Instead, this method accepts any base up to 36, and does not  
67 - * differentiate lowercase and uppercase characters, which are considered equal.  
68 - *  
69 - * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method.  
70 - *  
71 - * @param string $number The number to convert, in the given base.  
72 - * @param int $base The base of the number, between 2 and 36.  
73 - *  
74 - * @return BigInteger  
75 - *  
76 - * @throws NumberFormatException If the number is empty, or contains invalid chars for the given base.  
77 - * @throws \InvalidArgumentException If the base is out of range.  
78 - *  
79 - * @psalm-pure  
80 - */  
81 - public static function fromBase(string $number, int $base) : BigInteger  
82 - {  
83 - if ($number === '') {  
84 - throw new NumberFormatException('The number cannot be empty.');  
85 - }  
86 -  
87 - if ($base < 2 || $base > 36) {  
88 - throw new \InvalidArgumentException(\sprintf('Base %d is not in range 2 to 36.', $base));  
89 - }  
90 -  
91 - if ($number[0] === '-') {  
92 - $sign = '-';  
93 - $number = \substr($number, 1);  
94 - } elseif ($number[0] === '+') {  
95 - $sign = '';  
96 - $number = \substr($number, 1);  
97 - } else {  
98 - $sign = '';  
99 - }  
100 -  
101 - if ($number === '') {  
102 - throw new NumberFormatException('The number cannot be empty.');  
103 - }  
104 -  
105 - $number = \ltrim($number, '0');  
106 -  
107 - if ($number === '') {  
108 - // The result will be the same in any base, avoid further calculation.  
109 - return BigInteger::zero();  
110 - }  
111 -  
112 - if ($number === '1') {  
113 - // The result will be the same in any base, avoid further calculation.  
114 - return new BigInteger($sign . '1');  
115 - }  
116 -  
117 - $pattern = '/[^' . \substr(Calculator::ALPHABET, 0, $base) . ']/';  
118 -  
119 - if (\preg_match($pattern, \strtolower($number), $matches) === 1) {  
120 - throw new NumberFormatException(\sprintf('"%s" is not a valid character in base %d.', $matches[0], $base));  
121 - }  
122 -  
123 - if ($base === 10) {  
124 - // The number is usable as is, avoid further calculation.  
125 - return new BigInteger($sign . $number);  
126 - }  
127 -  
128 - $result = Calculator::get()->fromBase($number, $base);  
129 -  
130 - return new BigInteger($sign . $result);  
131 - }  
132 -  
133 - /**  
134 - * Parses a string containing an integer in an arbitrary base, using a custom alphabet.  
135 - *  
136 - * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers.  
137 - *  
138 - * @param string $number The number to parse.  
139 - * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.  
140 - *  
141 - * @return BigInteger  
142 - *  
143 - * @throws NumberFormatException If the given number is empty or contains invalid chars for the given alphabet.  
144 - * @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars.  
145 - *  
146 - * @psalm-pure  
147 - */  
148 - public static function fromArbitraryBase(string $number, string $alphabet) : BigInteger  
149 - {  
150 - if ($number === '') {  
151 - throw new NumberFormatException('The number cannot be empty.');  
152 - }  
153 -  
154 - $base = \strlen($alphabet);  
155 -  
156 - if ($base < 2) {  
157 - throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');  
158 - }  
159 -  
160 - $pattern = '/[^' . \preg_quote($alphabet, '/') . ']/';  
161 -  
162 - if (\preg_match($pattern, $number, $matches) === 1) {  
163 - throw NumberFormatException::charNotInAlphabet($matches[0]);  
164 - }  
165 -  
166 - $number = Calculator::get()->fromArbitraryBase($number, $alphabet, $base);  
167 -  
168 - return new BigInteger($number);  
169 - }  
170 -  
171 - /**  
172 - * Translates a string of bytes containing the binary representation of a BigInteger into a BigInteger.  
173 - *  
174 - * The input string is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element.  
175 - *  
176 - * If `$signed` is true, the input is assumed to be in two's-complement representation, and the leading bit is  
177 - * interpreted as a sign bit. If `$signed` is false, the input is interpreted as an unsigned number, and the  
178 - * resulting BigInteger will always be positive or zero.  
179 - *  
180 - * This method can be used to retrieve a number exported by `toBytes()`, as long as the `$signed` flags match.  
181 - *  
182 - * @param string $value The byte string.  
183 - * @param bool $signed Whether to interpret as a signed number in two's-complement representation with a leading  
184 - * sign bit.  
185 - *  
186 - * @return BigInteger  
187 - *  
188 - * @throws NumberFormatException If the string is empty.  
189 - */  
190 - public static function fromBytes(string $value, bool $signed = true) : BigInteger  
191 - {  
192 - if ($value === '') {  
193 - throw new NumberFormatException('The byte string must not be empty.');  
194 - }  
195 -  
196 - $twosComplement = false;  
197 -  
198 - if ($signed) {  
199 - $x = \ord($value[0]);  
200 -  
201 - if (($twosComplement = ($x >= 0x80))) {  
202 - $value = ~$value;  
203 - }  
204 - }  
205 -  
206 - $number = self::fromBase(\bin2hex($value), 16);  
207 -  
208 - if ($twosComplement) {  
209 - return $number->plus(1)->negated();  
210 - }  
211 -  
212 - return $number;  
213 - }  
214 -  
215 - /**  
216 - * Generates a pseudo-random number in the range 0 to 2^numBits - 1.  
217 - *  
218 - * Using the default random bytes generator, this method is suitable for cryptographic use.  
219 - *  
220 - * @psalm-param callable(int): string $randomBytesGenerator  
221 - *  
222 - * @param int $numBits The number of bits.  
223 - * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, and returns a  
224 - * string of random bytes of the given length. Defaults to the  
225 - * `random_bytes()` function.  
226 - *  
227 - * @return BigInteger  
228 - *  
229 - * @throws \InvalidArgumentException If $numBits is negative.  
230 - */  
231 - public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger  
232 - {  
233 - if ($numBits < 0) {  
234 - throw new \InvalidArgumentException('The number of bits cannot be negative.');  
235 - }  
236 -  
237 - if ($numBits === 0) {  
238 - return BigInteger::zero();  
239 - }  
240 -  
241 - if ($randomBytesGenerator === null) {  
242 - $randomBytesGenerator = 'random_bytes';  
243 - }  
244 -  
245 - $byteLength = \intdiv($numBits - 1, 8) + 1;  
246 -  
247 - $extraBits = ($byteLength * 8 - $numBits);  
248 - $bitmask = \chr(0xFF >> $extraBits);  
249 -  
250 - $randomBytes = $randomBytesGenerator($byteLength);  
251 - $randomBytes[0] = $randomBytes[0] & $bitmask;  
252 -  
253 - return self::fromBytes($randomBytes, false);  
254 - }  
255 -  
256 - /**  
257 - * Generates a pseudo-random number between `$min` and `$max`.  
258 - *  
259 - * Using the default random bytes generator, this method is suitable for cryptographic use.  
260 - *  
261 - * @psalm-param (callable(int): string)|null $randomBytesGenerator  
262 - *  
263 - * @param BigNumber|int|float|string $min The lower bound. Must be convertible to a BigInteger.  
264 - * @param BigNumber|int|float|string $max The upper bound. Must be convertible to a BigInteger.  
265 - * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer,  
266 - * and returns a string of random bytes of the given length.  
267 - * Defaults to the `random_bytes()` function.  
268 - *  
269 - * @return BigInteger  
270 - *  
271 - * @throws MathException If one of the parameters cannot be converted to a BigInteger,  
272 - * or `$min` is greater than `$max`.  
273 - */  
274 - public static function randomRange($min, $max, ?callable $randomBytesGenerator = null) : BigInteger  
275 - {  
276 - $min = BigInteger::of($min);  
277 - $max = BigInteger::of($max);  
278 -  
279 - if ($min->isGreaterThan($max)) {  
280 - throw new MathException('$min cannot be greater than $max.');  
281 - }  
282 -  
283 - if ($min->isEqualTo($max)) {  
284 - return $min;  
285 - }  
286 -  
287 - $diff = $max->minus($min);  
288 - $bitLength = $diff->getBitLength();  
289 -  
290 - // try until the number is in range (50% to 100% chance of success)  
291 - do {  
292 - $randomNumber = self::randomBits($bitLength, $randomBytesGenerator);  
293 - } while ($randomNumber->isGreaterThan($diff));  
294 -  
295 - return $randomNumber->plus($min);  
296 - }  
297 -  
298 - /**  
299 - * Returns a BigInteger representing zero.  
300 - *  
301 - * @return BigInteger  
302 - *  
303 - * @psalm-pure  
304 - */  
305 - public static function zero() : BigInteger  
306 - {  
307 - /**  
308 - * @psalm-suppress ImpureStaticVariable  
309 - * @var BigInteger|null $zero  
310 - */  
311 - static $zero;  
312 -  
313 - if ($zero === null) {  
314 - $zero = new BigInteger('0');  
315 - }  
316 -  
317 - return $zero;  
318 - }  
319 -  
320 - /**  
321 - * Returns a BigInteger representing one.  
322 - *  
323 - * @return BigInteger  
324 - *  
325 - * @psalm-pure  
326 - */  
327 - public static function one() : BigInteger  
328 - {  
329 - /**  
330 - * @psalm-suppress ImpureStaticVariable  
331 - * @var BigInteger|null $one  
332 - */  
333 - static $one;  
334 -  
335 - if ($one === null) {  
336 - $one = new BigInteger('1');  
337 - }  
338 -  
339 - return $one;  
340 - }  
341 -  
342 - /**  
343 - * Returns a BigInteger representing ten.  
344 - *  
345 - * @return BigInteger  
346 - *  
347 - * @psalm-pure  
348 - */  
349 - public static function ten() : BigInteger  
350 - {  
351 - /**  
352 - * @psalm-suppress ImpureStaticVariable  
353 - * @var BigInteger|null $ten  
354 - */  
355 - static $ten;  
356 -  
357 - if ($ten === null) {  
358 - $ten = new BigInteger('10');  
359 - }  
360 -  
361 - return $ten;  
362 - }  
363 -  
364 - /**  
365 - * Returns the sum of this number and the given one.  
366 - *  
367 - * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger.  
368 - *  
369 - * @return BigInteger The result.  
370 - *  
371 - * @throws MathException If the number is not valid, or is not convertible to a BigInteger.  
372 - */  
373 - public function plus($that) : BigInteger  
374 - {  
375 - $that = BigInteger::of($that);  
376 -  
377 - if ($that->value === '0') {  
378 - return $this;  
379 - }  
380 -  
381 - if ($this->value === '0') {  
382 - return $that;  
383 - }  
384 -  
385 - $value = Calculator::get()->add($this->value, $that->value);  
386 -  
387 - return new BigInteger($value);  
388 - }  
389 -  
390 - /**  
391 - * Returns the difference of this number and the given one.  
392 - *  
393 - * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger.  
394 - *  
395 - * @return BigInteger The result.  
396 - *  
397 - * @throws MathException If the number is not valid, or is not convertible to a BigInteger.  
398 - */  
399 - public function minus($that) : BigInteger  
400 - {  
401 - $that = BigInteger::of($that);  
402 -  
403 - if ($that->value === '0') {  
404 - return $this;  
405 - }  
406 -  
407 - $value = Calculator::get()->sub($this->value, $that->value);  
408 -  
409 - return new BigInteger($value);  
410 - }  
411 -  
412 - /**  
413 - * Returns the product of this number and the given one.  
414 - *  
415 - * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger.  
416 - *  
417 - * @return BigInteger The result.  
418 - *  
419 - * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger.  
420 - */  
421 - public function multipliedBy($that) : BigInteger  
422 - {  
423 - $that = BigInteger::of($that);  
424 -  
425 - if ($that->value === '1') {  
426 - return $this;  
427 - }  
428 -  
429 - if ($this->value === '1') {  
430 - return $that;  
431 - }  
432 -  
433 - $value = Calculator::get()->mul($this->value, $that->value);  
434 -  
435 - return new BigInteger($value);  
436 - }  
437 -  
438 - /**  
439 - * Returns the result of the division of this number by the given one.  
440 - *  
441 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.  
442 - * @param int $roundingMode An optional rounding mode.  
443 - *  
444 - * @return BigInteger The result.  
445 - *  
446 - * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero,  
447 - * or RoundingMode::UNNECESSARY is used and the remainder is not zero.  
448 - */  
449 - public function dividedBy($that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger  
450 - {  
451 - $that = BigInteger::of($that);  
452 -  
453 - if ($that->value === '1') {  
454 - return $this;  
455 - }  
456 -  
457 - if ($that->value === '0') {  
458 - throw DivisionByZeroException::divisionByZero();  
459 - }  
460 -  
461 - $result = Calculator::get()->divRound($this->value, $that->value, $roundingMode);  
462 -  
463 - return new BigInteger($result);  
464 - }  
465 -  
466 - /**  
467 - * Returns this number exponentiated to the given value.  
468 - *  
469 - * @param int $exponent The exponent.  
470 - *  
471 - * @return BigInteger The result.  
472 - *  
473 - * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.  
474 - */  
475 - public function power(int $exponent) : BigInteger  
476 - {  
477 - if ($exponent === 0) {  
478 - return BigInteger::one();  
479 - }  
480 -  
481 - if ($exponent === 1) {  
482 - return $this;  
483 - }  
484 -  
485 - if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {  
486 - throw new \InvalidArgumentException(\sprintf(  
487 - 'The exponent %d is not in the range 0 to %d.',  
488 - $exponent,  
489 - Calculator::MAX_POWER  
490 - ));  
491 - }  
492 -  
493 - return new BigInteger(Calculator::get()->pow($this->value, $exponent));  
494 - }  
495 -  
496 - /**  
497 - * Returns the quotient of the division of this number by the given one.  
498 - *  
499 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.  
500 - *  
501 - * @return BigInteger  
502 - *  
503 - * @throws DivisionByZeroException If the divisor is zero.  
504 - */  
505 - public function quotient($that) : BigInteger  
506 - {  
507 - $that = BigInteger::of($that);  
508 -  
509 - if ($that->value === '1') {  
510 - return $this;  
511 - }  
512 -  
513 - if ($that->value === '0') {  
514 - throw DivisionByZeroException::divisionByZero();  
515 - }  
516 -  
517 - $quotient = Calculator::get()->divQ($this->value, $that->value);  
518 -  
519 - return new BigInteger($quotient);  
520 - }  
521 -  
522 - /**  
523 - * Returns the remainder of the division of this number by the given one.  
524 - *  
525 - * The remainder, when non-zero, has the same sign as the dividend.  
526 - *  
527 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.  
528 - *  
529 - * @return BigInteger  
530 - *  
531 - * @throws DivisionByZeroException If the divisor is zero.  
532 - */  
533 - public function remainder($that) : BigInteger  
534 - {  
535 - $that = BigInteger::of($that);  
536 -  
537 - if ($that->value === '1') {  
538 - return BigInteger::zero();  
539 - }  
540 -  
541 - if ($that->value === '0') {  
542 - throw DivisionByZeroException::divisionByZero();  
543 - }  
544 -  
545 - $remainder = Calculator::get()->divR($this->value, $that->value);  
546 -  
547 - return new BigInteger($remainder);  
548 - }  
549 -  
550 - /**  
551 - * Returns the quotient and remainder of the division of this number by the given one.  
552 - *  
553 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.  
554 - *  
555 - * @return BigInteger[] An array containing the quotient and the remainder.  
556 - *  
557 - * @throws DivisionByZeroException If the divisor is zero.  
558 - */  
559 - public function quotientAndRemainder($that) : array  
560 - {  
561 - $that = BigInteger::of($that);  
562 -  
563 - if ($that->value === '0') {  
564 - throw DivisionByZeroException::divisionByZero();  
565 - }  
566 -  
567 - [$quotient, $remainder] = Calculator::get()->divQR($this->value, $that->value);  
568 -  
569 - return [  
570 - new BigInteger($quotient),  
571 - new BigInteger($remainder)  
572 - ];  
573 - }  
574 -  
575 - /**  
576 - * Returns the modulo of this number and the given one.  
577 - *  
578 - * The modulo operation yields the same result as the remainder operation when both operands are of the same sign,  
579 - * and may differ when signs are different.  
580 - *  
581 - * The result of the modulo operation, when non-zero, has the same sign as the divisor.  
582 - *  
583 - * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.  
584 - *  
585 - * @return BigInteger  
586 - *  
587 - * @throws DivisionByZeroException If the divisor is zero.  
588 - */  
589 - public function mod($that) : BigInteger  
590 - {  
591 - $that = BigInteger::of($that);  
592 -  
593 - if ($that->value === '0') {  
594 - throw DivisionByZeroException::modulusMustNotBeZero();  
595 - }  
596 -  
597 - $value = Calculator::get()->mod($this->value, $that->value);  
598 -  
599 - return new BigInteger($value);  
600 - }  
601 -  
602 - /**  
603 - * Returns the modular multiplicative inverse of this BigInteger modulo $m.  
604 - *  
605 - * @param BigInteger $m  
606 - *  
607 - * @return BigInteger  
608 - *  
609 - * @throws DivisionByZeroException If $m is zero.  
610 - * @throws NegativeNumberException If $m is negative.  
611 - * @throws MathException If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger  
612 - * is not relatively prime to m).  
613 - */  
614 - public function modInverse(BigInteger $m) : BigInteger  
615 - {  
616 - if ($m->value === '0') {  
617 - throw DivisionByZeroException::modulusMustNotBeZero();  
618 - }  
619 -  
620 - if ($m->isNegative()) {  
621 - throw new NegativeNumberException('Modulus must not be negative.');  
622 - }  
623 -  
624 - if ($m->value === '1') {  
625 - return BigInteger::zero();  
626 - }  
627 -  
628 - $value = Calculator::get()->modInverse($this->value, $m->value);  
629 -  
630 - if ($value === null) {  
631 - throw new MathException('Unable to compute the modInverse for the given modulus.');  
632 - }  
633 -  
634 - return new BigInteger($value);  
635 - }  
636 -  
637 - /**  
638 - * Returns this number raised into power with modulo.  
639 - *  
640 - * This operation only works on positive numbers.  
641 - *  
642 - * @param BigNumber|int|float|string $exp The exponent. Must be positive or zero.  
643 - * @param BigNumber|int|float|string $mod The modulus. Must be strictly positive.  
644 - *  
645 - * @return BigInteger  
646 - *  
647 - * @throws NegativeNumberException If any of the operands is negative.  
648 - * @throws DivisionByZeroException If the modulus is zero.  
649 - */  
650 - public function modPow($exp, $mod) : BigInteger  
651 - {  
652 - $exp = BigInteger::of($exp);  
653 - $mod = BigInteger::of($mod);  
654 -  
655 - if ($this->isNegative() || $exp->isNegative() || $mod->isNegative()) {  
656 - throw new NegativeNumberException('The operands cannot be negative.');  
657 - }  
658 -  
659 - if ($mod->isZero()) {  
660 - throw DivisionByZeroException::modulusMustNotBeZero();  
661 - }  
662 -  
663 - $result = Calculator::get()->modPow($this->value, $exp->value, $mod->value);  
664 -  
665 - return new BigInteger($result);  
666 - }  
667 -  
668 - /**  
669 - * Returns the greatest common divisor of this number and the given one.  
670 - *  
671 - * The GCD is always positive, unless both operands are zero, in which case it is zero.  
672 - *  
673 - * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.  
674 - *  
675 - * @return BigInteger  
676 - */  
677 - public function gcd($that) : BigInteger  
678 - {  
679 - $that = BigInteger::of($that);  
680 -  
681 - if ($that->value === '0' && $this->value[0] !== '-') {  
682 - return $this;  
683 - }  
684 -  
685 - if ($this->value === '0' && $that->value[0] !== '-') {  
686 - return $that;  
687 - }  
688 -  
689 - $value = Calculator::get()->gcd($this->value, $that->value);  
690 -  
691 - return new BigInteger($value);  
692 - }  
693 -  
694 - /**  
695 - * Returns the integer square root number of this number, rounded down.  
696 - *  
697 - * The result is the largest x such that x² ≤ n.  
698 - *  
699 - * @return BigInteger  
700 - *  
701 - * @throws NegativeNumberException If this number is negative.  
702 - */  
703 - public function sqrt() : BigInteger  
704 - {  
705 - if ($this->value[0] === '-') {  
706 - throw new NegativeNumberException('Cannot calculate the square root of a negative number.');  
707 - }  
708 -  
709 - $value = Calculator::get()->sqrt($this->value);  
710 -  
711 - return new BigInteger($value);  
712 - }  
713 -  
714 - /**  
715 - * Returns the absolute value of this number.  
716 - *  
717 - * @return BigInteger  
718 - */  
719 - public function abs() : BigInteger  
720 - {  
721 - return $this->isNegative() ? $this->negated() : $this;  
722 - }  
723 -  
724 - /**  
725 - * Returns the inverse of this number.  
726 - *  
727 - * @return BigInteger  
728 - */  
729 - public function negated() : BigInteger  
730 - {  
731 - return new BigInteger(Calculator::get()->neg($this->value));  
732 - }  
733 -  
734 - /**  
735 - * Returns the integer bitwise-and combined with another integer.  
736 - *  
737 - * This method returns a negative BigInteger if and only if both operands are negative.  
738 - *  
739 - * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.  
740 - *  
741 - * @return BigInteger  
742 - */  
743 - public function and($that) : BigInteger  
744 - {  
745 - $that = BigInteger::of($that);  
746 -  
747 - return new BigInteger(Calculator::get()->and($this->value, $that->value));  
748 - }  
749 -  
750 - /**  
751 - * Returns the integer bitwise-or combined with another integer.  
752 - *  
753 - * This method returns a negative BigInteger if and only if either of the operands is negative.  
754 - *  
755 - * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.  
756 - *  
757 - * @return BigInteger  
758 - */  
759 - public function or($that) : BigInteger  
760 - {  
761 - $that = BigInteger::of($that);  
762 -  
763 - return new BigInteger(Calculator::get()->or($this->value, $that->value));  
764 - }  
765 -  
766 - /**  
767 - * Returns the integer bitwise-xor combined with another integer.  
768 - *  
769 - * This method returns a negative BigInteger if and only if exactly one of the operands is negative.  
770 - *  
771 - * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.  
772 - *  
773 - * @return BigInteger  
774 - */  
775 - public function xor($that) : BigInteger  
776 - {  
777 - $that = BigInteger::of($that);  
778 -  
779 - return new BigInteger(Calculator::get()->xor($this->value, $that->value));  
780 - }  
781 -  
782 - /**  
783 - * Returns the bitwise-not of this BigInteger.  
784 - *  
785 - * @return BigInteger  
786 - */  
787 - public function not() : BigInteger  
788 - {  
789 - return $this->negated()->minus(1);  
790 - }  
791 -  
792 - /**  
793 - * Returns the integer left shifted by a given number of bits.  
794 - *  
795 - * @param int $distance The distance to shift.  
796 - *  
797 - * @return BigInteger  
798 - */  
799 - public function shiftedLeft(int $distance) : BigInteger  
800 - {  
801 - if ($distance === 0) {  
802 - return $this;  
803 - }  
804 -  
805 - if ($distance < 0) {  
806 - return $this->shiftedRight(- $distance);  
807 - }  
808 -  
809 - return $this->multipliedBy(BigInteger::of(2)->power($distance));  
810 - }  
811 -  
812 - /**  
813 - * Returns the integer right shifted by a given number of bits.  
814 - *  
815 - * @param int $distance The distance to shift.  
816 - *  
817 - * @return BigInteger  
818 - */  
819 - public function shiftedRight(int $distance) : BigInteger  
820 - {  
821 - if ($distance === 0) {  
822 - return $this;  
823 - }  
824 -  
825 - if ($distance < 0) {  
826 - return $this->shiftedLeft(- $distance);  
827 - }  
828 -  
829 - $operand = BigInteger::of(2)->power($distance);  
830 -  
831 - if ($this->isPositiveOrZero()) {  
832 - return $this->quotient($operand);  
833 - }  
834 -  
835 - return $this->dividedBy($operand, RoundingMode::UP);  
836 - }  
837 -  
838 - /**  
839 - * Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit.  
840 - *  
841 - * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation.  
842 - * Computes (ceil(log2(this < 0 ? -this : this+1))).  
843 - *  
844 - * @return int  
845 - */  
846 - public function getBitLength() : int  
847 - {  
848 - if ($this->value === '0') {  
849 - return 0;  
850 - }  
851 -  
852 - if ($this->isNegative()) {  
853 - return $this->abs()->minus(1)->getBitLength();  
854 - }  
855 -  
856 - return \strlen($this->toBase(2));  
857 - }  
858 -  
859 - /**  
860 - * Returns the index of the rightmost (lowest-order) one bit in this BigInteger.  
861 - *  
862 - * Returns -1 if this BigInteger contains no one bits.  
863 - *  
864 - * @return int  
865 - */  
866 - public function getLowestSetBit() : int  
867 - {  
868 - $n = $this;  
869 - $bitLength = $this->getBitLength();  
870 -  
871 - for ($i = 0; $i <= $bitLength; $i++) {  
872 - if ($n->isOdd()) {  
873 - return $i;  
874 - }  
875 -  
876 - $n = $n->shiftedRight(1);  
877 - }  
878 -  
879 - return -1;  
880 - }  
881 -  
882 - /**  
883 - * Returns whether this number is even.  
884 - *  
885 - * @return bool  
886 - */  
887 - public function isEven() : bool  
888 - {  
889 - return \in_array($this->value[-1], ['0', '2', '4', '6', '8'], true);  
890 - }  
891 -  
892 - /**  
893 - * Returns whether this number is odd.  
894 - *  
895 - * @return bool  
896 - */  
897 - public function isOdd() : bool  
898 - {  
899 - return \in_array($this->value[-1], ['1', '3', '5', '7', '9'], true);  
900 - }  
901 -  
902 - /**  
903 - * Returns true if and only if the designated bit is set.  
904 - *  
905 - * Computes ((this & (1<<n)) != 0).  
906 - *  
907 - * @param int $n The bit to test, 0-based.  
908 - *  
909 - * @return bool  
910 - *  
911 - * @throws \InvalidArgumentException If the bit to test is negative.  
912 - */  
913 - public function testBit(int $n) : bool  
914 - {  
915 - if ($n < 0) {  
916 - throw new \InvalidArgumentException('The bit to test cannot be negative.');  
917 - }  
918 -  
919 - return $this->shiftedRight($n)->isOdd();  
920 - }  
921 -  
922 - /**  
923 - * {@inheritdoc}  
924 - */  
925 - public function compareTo($that) : int  
926 - {  
927 - $that = BigNumber::of($that);  
928 -  
929 - if ($that instanceof BigInteger) {  
930 - return Calculator::get()->cmp($this->value, $that->value);  
931 - }  
932 -  
933 - return - $that->compareTo($this);  
934 - }  
935 -  
936 - /**  
937 - * {@inheritdoc}  
938 - */  
939 - public function getSign() : int  
940 - {  
941 - return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);  
942 - }  
943 -  
944 - /**  
945 - * {@inheritdoc}  
946 - */  
947 - public function toBigInteger() : BigInteger  
948 - {  
949 - return $this;  
950 - }  
951 -  
952 - /**  
953 - * {@inheritdoc}  
954 - */  
955 - public function toBigDecimal() : BigDecimal  
956 - {  
957 - return BigDecimal::create($this->value);  
958 - }  
959 -  
960 - /**  
961 - * {@inheritdoc}  
962 - */  
963 - public function toBigRational() : BigRational  
964 - {  
965 - return BigRational::create($this, BigInteger::one(), false);  
966 - }  
967 -  
968 - /**  
969 - * {@inheritdoc}  
970 - */  
971 - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal  
972 - {  
973 - return $this->toBigDecimal()->toScale($scale, $roundingMode);  
974 - }  
975 -  
976 - /**  
977 - * {@inheritdoc}  
978 - */  
979 - public function toInt() : int  
980 - {  
981 - $intValue = (int) $this->value;  
982 -  
983 - if ($this->value !== (string) $intValue) {  
984 - throw IntegerOverflowException::toIntOverflow($this);  
985 - }  
986 -  
987 - return $intValue;  
988 - }  
989 -  
990 - /**  
991 - * {@inheritdoc}  
992 - */  
993 - public function toFloat() : float  
994 - {  
995 - return (float) $this->value;  
996 - }  
997 -  
998 - /**  
999 - * Returns a string representation of this number in the given base.  
1000 - *  
1001 - * The output will always be lowercase for bases greater than 10.  
1002 - *  
1003 - * @param int $base  
1004 - *  
1005 - * @return string  
1006 - *  
1007 - * @throws \InvalidArgumentException If the base is out of range.  
1008 - */  
1009 - public function toBase(int $base) : string  
1010 - {  
1011 - if ($base === 10) {  
1012 - return $this->value;  
1013 - }  
1014 -  
1015 - if ($base < 2 || $base > 36) {  
1016 - throw new \InvalidArgumentException(\sprintf('Base %d is out of range [2, 36]', $base));  
1017 - }  
1018 -  
1019 - return Calculator::get()->toBase($this->value, $base);  
1020 - }  
1021 -  
1022 - /**  
1023 - * Returns a string representation of this number in an arbitrary base with a custom alphabet.  
1024 - *  
1025 - * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers;  
1026 - * a NegativeNumberException will be thrown when attempting to call this method on a negative number.  
1027 - *  
1028 - * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.  
1029 - *  
1030 - * @return string  
1031 - *  
1032 - * @throws NegativeNumberException If this number is negative.  
1033 - * @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars.  
1034 - */  
1035 - public function toArbitraryBase(string $alphabet) : string  
1036 - {  
1037 - $base = \strlen($alphabet);  
1038 -  
1039 - if ($base < 2) {  
1040 - throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');  
1041 - }  
1042 -  
1043 - if ($this->value[0] === '-') {  
1044 - throw new NegativeNumberException(__FUNCTION__ . '() does not support negative numbers.');  
1045 - }  
1046 -  
1047 - return Calculator::get()->toArbitraryBase($this->value, $alphabet, $base);  
1048 - }  
1049 -  
1050 - /**  
1051 - * Returns a string of bytes containing the binary representation of this BigInteger.  
1052 - *  
1053 - * The string is in big-endian byte-order: the most significant byte is in the zeroth element.  
1054 - *  
1055 - * If `$signed` is true, the output will be in two's-complement representation, and a sign bit will be prepended to  
1056 - * the output. If `$signed` is false, no sign bit will be prepended, and this method will throw an exception if the  
1057 - * number is negative.  
1058 - *  
1059 - * The string will contain the minimum number of bytes required to represent this BigInteger, including a sign bit  
1060 - * if `$signed` is true.  
1061 - *  
1062 - * This representation is compatible with the `fromBytes()` factory method, as long as the `$signed` flags match.  
1063 - *  
1064 - * @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit.  
1065 - *  
1066 - * @return string  
1067 - *  
1068 - * @throws NegativeNumberException If $signed is false, and the number is negative.  
1069 - */  
1070 - public function toBytes(bool $signed = true) : string  
1071 - {  
1072 - if (! $signed && $this->isNegative()) {  
1073 - throw new NegativeNumberException('Cannot convert a negative number to a byte string when $signed is false.');  
1074 - }  
1075 -  
1076 - $hex = $this->abs()->toBase(16);  
1077 -  
1078 - if (\strlen($hex) % 2 !== 0) {  
1079 - $hex = '0' . $hex;  
1080 - }  
1081 -  
1082 - $baseHexLength = \strlen($hex);  
1083 -  
1084 - if ($signed) {  
1085 - if ($this->isNegative()) {  
1086 - $bin = \hex2bin($hex);  
1087 - assert($bin !== false);  
1088 -  
1089 - $hex = \bin2hex(~$bin);  
1090 - $hex = self::fromBase($hex, 16)->plus(1)->toBase(16);  
1091 -  
1092 - $hexLength = \strlen($hex);  
1093 -  
1094 - if ($hexLength < $baseHexLength) {  
1095 - $hex = \str_repeat('0', $baseHexLength - $hexLength) . $hex;  
1096 - }  
1097 -  
1098 - if ($hex[0] < '8') {  
1099 - $hex = 'FF' . $hex;  
1100 - }  
1101 - } else {  
1102 - if ($hex[0] >= '8') {  
1103 - $hex = '00' . $hex;  
1104 - }  
1105 - }  
1106 - }  
1107 -  
1108 - return \hex2bin($hex);  
1109 - }  
1110 -  
1111 - /**  
1112 - * {@inheritdoc}  
1113 - */  
1114 - public function __toString() : string  
1115 - {  
1116 - return $this->value;  
1117 - }  
1118 -  
1119 - /**  
1120 - * This method is required for serializing the object and SHOULD NOT be accessed directly.  
1121 - *  
1122 - * @internal  
1123 - *  
1124 - * @return array{value: string}  
1125 - */  
1126 - public function __serialize(): array  
1127 - {  
1128 - return ['value' => $this->value];  
1129 - }  
1130 -  
1131 - /**  
1132 - * This method is only here to allow unserializing the object and cannot be accessed directly.  
1133 - *  
1134 - * @internal  
1135 - * @psalm-suppress RedundantPropertyInitializationCheck  
1136 - *  
1137 - * @param array{value: string} $data  
1138 - *  
1139 - * @return void  
1140 - *  
1141 - * @throws \LogicException  
1142 - */  
1143 - public function __unserialize(array $data): void  
1144 - {  
1145 - if (isset($this->value)) {  
1146 - throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');  
1147 - }  
1148 -  
1149 - $this->value = $data['value'];  
1150 - }  
1151 -  
1152 - /**  
1153 - * This method is required by interface Serializable and SHOULD NOT be accessed directly.  
1154 - *  
1155 - * @internal  
1156 - *  
1157 - * @return string  
1158 - */  
1159 - public function serialize() : string  
1160 - {  
1161 - return $this->value;  
1162 - }  
1163 -  
1164 - /**  
1165 - * This method is only here to implement interface Serializable and cannot be accessed directly.  
1166 - *  
1167 - * @internal  
1168 - * @psalm-suppress RedundantPropertyInitializationCheck  
1169 - *  
1170 - * @param string $value  
1171 - *  
1172 - * @return void  
1173 - *  
1174 - * @throws \LogicException  
1175 - */  
1176 - public function unserialize($value) : void  
1177 - {  
1178 - if (isset($this->value)) {  
1179 - throw new \LogicException('unserialize() is an internal function, it must not be called directly.');  
1180 - }  
1181 -  
1182 - $this->value = $value;  
1183 - }  
1184 -}  
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 - private const PARSE_REGEXP =  
23 - '/^' .  
24 - '(?<sign>[\-\+])?' .  
25 - '(?:' .  
26 - '(?:' .  
27 - '(?<integral>[0-9]+)?' .  
28 - '(?<point>\.)?' .  
29 - '(?<fractional>[0-9]+)?' .  
30 - '(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .  
31 - ')|(?:' .  
32 - '(?<numerator>[0-9]+)' .  
33 - '\/?' .  
34 - '(?<denominator>[0-9]+)' .  
35 - ')' .  
36 - ')' .  
37 - '$/';  
38 -  
39 - /**  
40 - * Creates a BigNumber of the given value.  
41 - *  
42 - * The concrete return type is dependent on the given value, with the following rules:  
43 - *  
44 - * - BigNumber instances are returned as is  
45 - * - integer numbers are returned as BigInteger  
46 - * - floating point numbers are converted to a string then parsed as such  
47 - * - strings containing a `/` character are returned as BigRational  
48 - * - strings containing a `.` character or using an exponential notation are returned as BigDecimal  
49 - * - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger  
50 - *  
51 - * @param BigNumber|int|float|string $value  
52 - *  
53 - * @return BigNumber  
54 - *  
55 - * @throws NumberFormatException If the format of the number is not valid.  
56 - * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.  
57 - *  
58 - * @psalm-pure  
59 - */  
60 - public static function of($value) : BigNumber  
61 - {  
62 - if ($value instanceof BigNumber) {  
63 - return $value;  
64 - }  
65 -  
66 - if (\is_int($value)) {  
67 - return new BigInteger((string) $value);  
68 - }  
69 -  
70 - /** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */  
71 - $value = \is_float($value) ? self::floatToString($value) : (string) $value;  
72 -  
73 - $throw = static function() use ($value) : void {  
74 - throw new NumberFormatException(\sprintf(  
75 - 'The given value "%s" does not represent a valid number.',  
76 - $value  
77 - ));  
78 - };  
79 -  
80 - if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) {  
81 - $throw();  
82 - }  
83 -  
84 - $getMatch = static function(string $value) use ($matches) : ?string {  
85 - return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null;  
86 - };  
87 -  
88 - $sign = $getMatch('sign');  
89 - $numerator = $getMatch('numerator');  
90 - $denominator = $getMatch('denominator');  
91 -  
92 - if ($numerator !== null) {  
93 - assert($denominator !== null);  
94 -  
95 - if ($sign !== null) {  
96 - $numerator = $sign . $numerator;  
97 - }  
98 -  
99 - $numerator = self::cleanUp($numerator);  
100 - $denominator = self::cleanUp($denominator);  
101 -  
102 - if ($denominator === '0') {  
103 - throw DivisionByZeroException::denominatorMustNotBeZero();  
104 - }  
105 -  
106 - return new BigRational(  
107 - new BigInteger($numerator),  
108 - new BigInteger($denominator),  
109 - false  
110 - );  
111 - }  
112 -  
113 - $point = $getMatch('point');  
114 - $integral = $getMatch('integral');  
115 - $fractional = $getMatch('fractional');  
116 - $exponent = $getMatch('exponent');  
117 -  
118 - if ($integral === null && $fractional === null) {  
119 - $throw();  
120 - }  
121 -  
122 - if ($integral === null) {  
123 - $integral = '0';  
124 - }  
125 -  
126 - if ($point !== null || $exponent !== null) {  
127 - $fractional = ($fractional ?? '');  
128 - $exponent = ($exponent !== null) ? (int) $exponent : 0;  
129 -  
130 - if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) {  
131 - throw new NumberFormatException('Exponent too large.');  
132 - }  
133 -  
134 - $unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional);  
135 -  
136 - $scale = \strlen($fractional) - $exponent;  
137 -  
138 - if ($scale < 0) {  
139 - if ($unscaledValue !== '0') {  
140 - $unscaledValue .= \str_repeat('0', - $scale);  
141 - }  
142 - $scale = 0;  
143 - }  
144 -  
145 - return new BigDecimal($unscaledValue, $scale);  
146 - }  
147 -  
148 - $integral = self::cleanUp(($sign ?? '') . $integral);  
149 -  
150 - return new BigInteger($integral);  
151 - }  
152 -  
153 - /**  
154 - * Safely converts float to string, avoiding locale-dependent issues.  
155 - *  
156 - * @see https://github.com/brick/math/pull/20  
157 - *  
158 - * @param float $float  
159 - *  
160 - * @return string  
161 - *  
162 - * @psalm-pure  
163 - * @psalm-suppress ImpureFunctionCall  
164 - */  
165 - private static function floatToString(float $float) : string  
166 - {  
167 - $currentLocale = \setlocale(LC_NUMERIC, '0');  
168 - \setlocale(LC_NUMERIC, 'C');  
169 -  
170 - $result = (string) $float;  
171 -  
172 - \setlocale(LC_NUMERIC, $currentLocale);  
173 -  
174 - return $result;  
175 - }  
176 -  
177 - /**  
178 - * Proxy method to access protected constructors from sibling classes.  
179 - *  
180 - * @internal  
181 - *  
182 - * @param mixed ...$args The arguments to the constructor.  
183 - *  
184 - * @return static  
185 - *  
186 - * @psalm-pure  
187 - * @psalm-suppress TooManyArguments  
188 - * @psalm-suppress UnsafeInstantiation  
189 - */  
190 - protected static function create(... $args) : BigNumber  
191 - {  
192 - return new static(... $args);  
193 - }  
194 -  
195 - /**  
196 - * Returns the minimum of the given values.  
197 - *  
198 - * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible  
199 - * to an instance of the class this method is called on.  
200 - *  
201 - * @return static The minimum value.  
202 - *  
203 - * @throws \InvalidArgumentException If no values are given.  
204 - * @throws MathException If an argument is not valid.  
205 - *  
206 - * @psalm-suppress LessSpecificReturnStatement  
207 - * @psalm-suppress MoreSpecificReturnType  
208 - * @psalm-pure  
209 - */  
210 - public static function min(...$values) : BigNumber  
211 - {  
212 - $min = null;  
213 -  
214 - foreach ($values as $value) {  
215 - $value = static::of($value);  
216 -  
217 - if ($min === null || $value->isLessThan($min)) {  
218 - $min = $value;  
219 - }  
220 - }  
221 -  
222 - if ($min === null) {  
223 - throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');  
224 - }  
225 -  
226 - return $min;  
227 - }  
228 -  
229 - /**  
230 - * Returns the maximum of the given values.  
231 - *  
232 - * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible  
233 - * to an instance of the class this method is called on.  
234 - *  
235 - * @return static The maximum value.  
236 - *  
237 - * @throws \InvalidArgumentException If no values are given.  
238 - * @throws MathException If an argument is not valid.  
239 - *  
240 - * @psalm-suppress LessSpecificReturnStatement  
241 - * @psalm-suppress MoreSpecificReturnType  
242 - * @psalm-pure  
243 - */  
244 - public static function max(...$values) : BigNumber  
245 - {  
246 - $max = null;  
247 -  
248 - foreach ($values as $value) {  
249 - $value = static::of($value);  
250 -  
251 - if ($max === null || $value->isGreaterThan($max)) {  
252 - $max = $value;  
253 - }  
254 - }  
255 -  
256 - if ($max === null) {  
257 - throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');  
258 - }  
259 -  
260 - return $max;  
261 - }  
262 -  
263 - /**  
264 - * Returns the sum of the given values.  
265 - *  
266 - * @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible  
267 - * to an instance of the class this method is called on.  
268 - *  
269 - * @return static The sum.  
270 - *  
271 - * @throws \InvalidArgumentException If no values are given.  
272 - * @throws MathException If an argument is not valid.  
273 - *  
274 - * @psalm-suppress LessSpecificReturnStatement  
275 - * @psalm-suppress MoreSpecificReturnType  
276 - * @psalm-pure  
277 - */  
278 - public static function sum(...$values) : BigNumber  
279 - {  
280 - /** @var BigNumber|null $sum */  
281 - $sum = null;  
282 -  
283 - foreach ($values as $value) {  
284 - $value = static::of($value);  
285 -  
286 - $sum = $sum === null ? $value : self::add($sum, $value);  
287 - }  
288 -  
289 - if ($sum === null) {  
290 - throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');  
291 - }  
292 -  
293 - return $sum;  
294 - }  
295 -  
296 - /**  
297 - * Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException.  
298 - *  
299 - * @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to  
300 - * concrete classes the responsibility to perform the addition themselves or delegate it to the given number,  
301 - * depending on their ability to perform the operation. This will also require a version bump because we're  
302 - * potentially breaking custom BigNumber implementations (if any...)  
303 - *  
304 - * @param BigNumber $a  
305 - * @param BigNumber $b  
306 - *  
307 - * @return BigNumber  
308 - *  
309 - * @psalm-pure  
310 - */  
311 - private static function add(BigNumber $a, BigNumber $b) : BigNumber  
312 - {  
313 - if ($a instanceof BigRational) {  
314 - return $a->plus($b);  
315 - }  
316 -  
317 - if ($b instanceof BigRational) {  
318 - return $b->plus($a);  
319 - }  
320 -  
321 - if ($a instanceof BigDecimal) {  
322 - return $a->plus($b);  
323 - }  
324 -  
325 - if ($b instanceof BigDecimal) {  
326 - return $b->plus($a);  
327 - }  
328 -  
329 - /** @var BigInteger $a */  
330 -  
331 - return $a->plus($b);  
332 - }  
333 -  
334 - /**  
335 - * Removes optional leading zeros and + sign from the given number.  
336 - *  
337 - * @param string $number The number, validated as a non-empty string of digits with optional leading sign.  
338 - *  
339 - * @return string  
340 - *  
341 - * @psalm-pure  
342 - */  
343 - private static function cleanUp(string $number) : string  
344 - {  
345 - $firstChar = $number[0];  
346 -  
347 - if ($firstChar === '+' || $firstChar === '-') {  
348 - $number = \substr($number, 1);  
349 - }  
350 -  
351 - $number = \ltrim($number, '0');  
352 -  
353 - if ($number === '') {  
354 - return '0';  
355 - }  
356 -  
357 - if ($firstChar === '-') {  
358 - return '-' . $number;  
359 - }  
360 -  
361 - return $number;  
362 - }  
363 -  
364 - /**  
365 - * Checks if this number is equal to the given one.  
366 - *  
367 - * @param BigNumber|int|float|string $that  
368 - *  
369 - * @return bool  
370 - */  
371 - public function isEqualTo($that) : bool  
372 - {  
373 - return $this->compareTo($that) === 0;  
374 - }  
375 -  
376 - /**  
377 - * Checks if this number is strictly lower than the given one.  
378 - *  
379 - * @param BigNumber|int|float|string $that  
380 - *  
381 - * @return bool  
382 - */  
383 - public function isLessThan($that) : bool  
384 - {  
385 - return $this->compareTo($that) < 0;  
386 - }  
387 -  
388 - /**  
389 - * Checks if this number is lower than or equal to the given one.  
390 - *  
391 - * @param BigNumber|int|float|string $that  
392 - *  
393 - * @return bool  
394 - */  
395 - public function isLessThanOrEqualTo($that) : bool  
396 - {  
397 - return $this->compareTo($that) <= 0;  
398 - }  
399 -  
400 - /**  
401 - * Checks if this number is strictly greater than the given one.  
402 - *  
403 - * @param BigNumber|int|float|string $that  
404 - *  
405 - * @return bool  
406 - */  
407 - public function isGreaterThan($that) : bool  
408 - {  
409 - return $this->compareTo($that) > 0;  
410 - }  
411 -  
412 - /**  
413 - * Checks if this number is greater than or equal to the given one.  
414 - *  
415 - * @param BigNumber|int|float|string $that  
416 - *  
417 - * @return bool  
418 - */  
419 - public function isGreaterThanOrEqualTo($that) : bool  
420 - {  
421 - return $this->compareTo($that) >= 0;  
422 - }  
423 -  
424 - /**  
425 - * Checks if this number equals zero.  
426 - *  
427 - * @return bool  
428 - */  
429 - public function isZero() : bool  
430 - {  
431 - return $this->getSign() === 0;  
432 - }  
433 -  
434 - /**  
435 - * Checks if this number is strictly negative.  
436 - *  
437 - * @return bool  
438 - */  
439 - public function isNegative() : bool  
440 - {  
441 - return $this->getSign() < 0;  
442 - }  
443 -  
444 - /**  
445 - * Checks if this number is negative or zero.  
446 - *  
447 - * @return bool  
448 - */  
449 - public function isNegativeOrZero() : bool  
450 - {  
451 - return $this->getSign() <= 0;  
452 - }  
453 -  
454 - /**  
455 - * Checks if this number is strictly positive.  
456 - *  
457 - * @return bool  
458 - */  
459 - public function isPositive() : bool  
460 - {  
461 - return $this->getSign() > 0;  
462 - }  
463 -  
464 - /**  
465 - * Checks if this number is positive or zero.  
466 - *  
467 - * @return bool  
468 - */  
469 - public function isPositiveOrZero() : bool  
470 - {  
471 - return $this->getSign() >= 0;  
472 - }  
473 -  
474 - /**  
475 - * Returns the sign of this number.  
476 - *  
477 - * @return int -1 if the number is negative, 0 if zero, 1 if positive.  
478 - */  
479 - abstract public function getSign() : int;  
480 -  
481 - /**  
482 - * Compares this number to the given one.  
483 - *  
484 - * @param BigNumber|int|float|string $that  
485 - *  
486 - * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`.  
487 - *  
488 - * @throws MathException If the number is not valid.  
489 - */  
490 - abstract public function compareTo($that) : int;  
491 -  
492 - /**  
493 - * Converts this number to a BigInteger.  
494 - *  
495 - * @return BigInteger The converted number.  
496 - *  
497 - * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding.  
498 - */  
499 - abstract public function toBigInteger() : BigInteger;  
500 -  
501 - /**  
502 - * Converts this number to a BigDecimal.  
503 - *  
504 - * @return BigDecimal The converted number.  
505 - *  
506 - * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding.  
507 - */  
508 - abstract public function toBigDecimal() : BigDecimal;  
509 -  
510 - /**  
511 - * Converts this number to a BigRational.  
512 - *  
513 - * @return BigRational The converted number.  
514 - */  
515 - abstract public function toBigRational() : BigRational;  
516 -  
517 - /**  
518 - * Converts this number to a BigDecimal with the given scale, using rounding if necessary.  
519 - *  
520 - * @param int $scale The scale of the resulting `BigDecimal`.  
521 - * @param int $roundingMode A `RoundingMode` constant.  
522 - *  
523 - * @return BigDecimal  
524 - *  
525 - * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding.  
526 - * This only applies when RoundingMode::UNNECESSARY is used.  
527 - */  
528 - abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;  
529 -  
530 - /**  
531 - * Returns the exact value of this number as a native integer.  
532 - *  
533 - * If this number cannot be converted to a native integer without losing precision, an exception is thrown.  
534 - * Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit.  
535 - *  
536 - * @return int The converted value.  
537 - *  
538 - * @throws MathException If this number cannot be exactly converted to a native integer.  
539 - */  
540 - abstract public function toInt() : int;  
541 -  
542 - /**  
543 - * Returns an approximation of this number as a floating-point value.  
544 - *  
545 - * Note that this method can discard information as the precision of a floating-point value  
546 - * is inherently limited.  
547 - *  
548 - * If the number is greater than the largest representable floating point number, positive infinity is returned.  
549 - * If the number is less than the smallest representable floating point number, negative infinity is returned.  
550 - *  
551 - * @return float The converted value.  
552 - */  
553 - abstract public function toFloat() : float;  
554 -  
555 - /**  
556 - * Returns a string representation of this number.  
557 - *  
558 - * The output of this method can be parsed by the `of()` factory method;  
559 - * this will yield an object equal to this one, without any information loss.  
560 - *  
561 - * @return string  
562 - */  
563 - abstract public function __toString() : string;  
564 -  
565 - /**  
566 - * {@inheritdoc}  
567 - */  
568 - public function jsonSerialize() : string  
569 - {  
570 - return $this->__toString();  
571 - }  
572 -}  
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 - * An arbitrarily large rational number.  
14 - *  
15 - * This class is immutable.  
16 - *  
17 - * @psalm-immutable  
18 - */  
19 -final class BigRational extends BigNumber  
20 -{  
21 - /**  
22 - * The numerator.  
23 - *  
24 - * @var BigInteger  
25 - */  
26 - private $numerator;  
27 -  
28 - /**  
29 - * The denominator. Always strictly positive.  
30 - *  
31 - * @var BigInteger  
32 - */  
33 - private $denominator;  
34 -  
35 - /**  
36 - * Protected constructor. Use a factory method to obtain an instance.  
37 - *  
38 - * @param BigInteger $numerator The numerator.  
39 - * @param BigInteger $denominator The denominator.  
40 - * @param bool $checkDenominator Whether to check the denominator for negative and zero.  
41 - *  
42 - * @throws DivisionByZeroException If the denominator is zero.  
43 - */  
44 - protected function __construct(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator)  
45 - {  
46 - if ($checkDenominator) {  
47 - if ($denominator->isZero()) {  
48 - throw DivisionByZeroException::denominatorMustNotBeZero();  
49 - }  
50 -  
51 - if ($denominator->isNegative()) {  
52 - $numerator = $numerator->negated();  
53 - $denominator = $denominator->negated();  
54 - }  
55 - }  
56 -  
57 - $this->numerator = $numerator;  
58 - $this->denominator = $denominator;  
59 - }  
60 -  
61 - /**  
62 - * Creates a BigRational of the given value.  
63 - *  
64 - * @param BigNumber|int|float|string $value  
65 - *  
66 - * @return BigRational  
67 - *  
68 - * @throws MathException If the value cannot be converted to a BigRational.  
69 - *  
70 - * @psalm-pure  
71 - */  
72 - public static function of($value) : BigNumber  
73 - {  
74 - return parent::of($value)->toBigRational();  
75 - }  
76 -  
77 - /**  
78 - * Creates a BigRational out of a numerator and a denominator.  
79 - *  
80 - * If the denominator is negative, the signs of both the numerator and the denominator  
81 - * will be inverted to ensure that the denominator is always positive.  
82 - *  
83 - * @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger.  
84 - * @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger.  
85 - *  
86 - * @return BigRational  
87 - *  
88 - * @throws NumberFormatException If an argument does not represent a valid number.  
89 - * @throws RoundingNecessaryException If an argument represents a non-integer number.  
90 - * @throws DivisionByZeroException If the denominator is zero.  
91 - *  
92 - * @psalm-pure  
93 - */  
94 - public static function nd($numerator, $denominator) : BigRational  
95 - {  
96 - $numerator = BigInteger::of($numerator);  
97 - $denominator = BigInteger::of($denominator);  
98 -  
99 - return new BigRational($numerator, $denominator, true);  
100 - }  
101 -  
102 - /**  
103 - * Returns a BigRational representing zero.  
104 - *  
105 - * @return BigRational  
106 - *  
107 - * @psalm-pure  
108 - */  
109 - public static function zero() : BigRational  
110 - {  
111 - /**  
112 - * @psalm-suppress ImpureStaticVariable  
113 - * @var BigRational|null $zero  
114 - */  
115 - static $zero;  
116 -  
117 - if ($zero === null) {  
118 - $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false);  
119 - }  
120 -  
121 - return $zero;  
122 - }  
123 -  
124 - /**  
125 - * Returns a BigRational representing one.  
126 - *  
127 - * @return BigRational  
128 - *  
129 - * @psalm-pure  
130 - */  
131 - public static function one() : BigRational  
132 - {  
133 - /**  
134 - * @psalm-suppress ImpureStaticVariable  
135 - * @var BigRational|null $one  
136 - */  
137 - static $one;  
138 -  
139 - if ($one === null) {  
140 - $one = new BigRational(BigInteger::one(), BigInteger::one(), false);  
141 - }  
142 -  
143 - return $one;  
144 - }  
145 -  
146 - /**  
147 - * Returns a BigRational representing ten.  
148 - *  
149 - * @return BigRational  
150 - *  
151 - * @psalm-pure  
152 - */  
153 - public static function ten() : BigRational  
154 - {  
155 - /**  
156 - * @psalm-suppress ImpureStaticVariable  
157 - * @var BigRational|null $ten  
158 - */  
159 - static $ten;  
160 -  
161 - if ($ten === null) {  
162 - $ten = new BigRational(BigInteger::ten(), BigInteger::one(), false);  
163 - }  
164 -  
165 - return $ten;  
166 - }  
167 -  
168 - /**  
169 - * @return BigInteger  
170 - */  
171 - public function getNumerator() : BigInteger  
172 - {  
173 - return $this->numerator;  
174 - }  
175 -  
176 - /**  
177 - * @return BigInteger  
178 - */  
179 - public function getDenominator() : BigInteger  
180 - {  
181 - return $this->denominator;  
182 - }  
183 -  
184 - /**  
185 - * Returns the quotient of the division of the numerator by the denominator.  
186 - *  
187 - * @return BigInteger  
188 - */  
189 - public function quotient() : BigInteger  
190 - {  
191 - return $this->numerator->quotient($this->denominator);  
192 - }  
193 -  
194 - /**  
195 - * Returns the remainder of the division of the numerator by the denominator.  
196 - *  
197 - * @return BigInteger  
198 - */  
199 - public function remainder() : BigInteger  
200 - {  
201 - return $this->numerator->remainder($this->denominator);  
202 - }  
203 -  
204 - /**  
205 - * Returns the quotient and remainder of the division of the numerator by the denominator.  
206 - *  
207 - * @return BigInteger[]  
208 - */  
209 - public function quotientAndRemainder() : array  
210 - {  
211 - return $this->numerator->quotientAndRemainder($this->denominator);  
212 - }  
213 -  
214 - /**  
215 - * Returns the sum of this number and the given one.  
216 - *  
217 - * @param BigNumber|int|float|string $that The number to add.  
218 - *  
219 - * @return BigRational The result.  
220 - *  
221 - * @throws MathException If the number is not valid.  
222 - */  
223 - public function plus($that) : BigRational  
224 - {  
225 - $that = BigRational::of($that);  
226 -  
227 - $numerator = $this->numerator->multipliedBy($that->denominator);  
228 - $numerator = $numerator->plus($that->numerator->multipliedBy($this->denominator));  
229 - $denominator = $this->denominator->multipliedBy($that->denominator);  
230 -  
231 - return new BigRational($numerator, $denominator, false);  
232 - }  
233 -  
234 - /**  
235 - * Returns the difference of this number and the given one.  
236 - *  
237 - * @param BigNumber|int|float|string $that The number to subtract.  
238 - *  
239 - * @return BigRational The result.  
240 - *  
241 - * @throws MathException If the number is not valid.  
242 - */  
243 - public function minus($that) : BigRational  
244 - {  
245 - $that = BigRational::of($that);  
246 -  
247 - $numerator = $this->numerator->multipliedBy($that->denominator);  
248 - $numerator = $numerator->minus($that->numerator->multipliedBy($this->denominator));  
249 - $denominator = $this->denominator->multipliedBy($that->denominator);  
250 -  
251 - return new BigRational($numerator, $denominator, false);  
252 - }  
253 -  
254 - /**  
255 - * Returns the product of this number and the given one.  
256 - *  
257 - * @param BigNumber|int|float|string $that The multiplier.  
258 - *  
259 - * @return BigRational The result.  
260 - *  
261 - * @throws MathException If the multiplier is not a valid number.  
262 - */  
263 - public function multipliedBy($that) : BigRational  
264 - {  
265 - $that = BigRational::of($that);  
266 -  
267 - $numerator = $this->numerator->multipliedBy($that->numerator);  
268 - $denominator = $this->denominator->multipliedBy($that->denominator);  
269 -  
270 - return new BigRational($numerator, $denominator, false);  
271 - }  
272 -  
273 - /**  
274 - * Returns the result of the division of this number by the given one.  
275 - *  
276 - * @param BigNumber|int|float|string $that The divisor.  
277 - *  
278 - * @return BigRational The result.  
279 - *  
280 - * @throws MathException If the divisor is not a valid number, or is zero.  
281 - */  
282 - public function dividedBy($that) : BigRational  
283 - {  
284 - $that = BigRational::of($that);  
285 -  
286 - $numerator = $this->numerator->multipliedBy($that->denominator);  
287 - $denominator = $this->denominator->multipliedBy($that->numerator);  
288 -  
289 - return new BigRational($numerator, $denominator, true);  
290 - }  
291 -  
292 - /**  
293 - * Returns this number exponentiated to the given value.  
294 - *  
295 - * @param int $exponent The exponent.  
296 - *  
297 - * @return BigRational The result.  
298 - *  
299 - * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.  
300 - */  
301 - public function power(int $exponent) : BigRational  
302 - {  
303 - if ($exponent === 0) {  
304 - $one = BigInteger::one();  
305 -  
306 - return new BigRational($one, $one, false);  
307 - }  
308 -  
309 - if ($exponent === 1) {  
310 - return $this;  
311 - }  
312 -  
313 - return new BigRational(  
314 - $this->numerator->power($exponent),  
315 - $this->denominator->power($exponent),  
316 - false  
317 - );  
318 - }  
319 -  
320 - /**  
321 - * Returns the reciprocal of this BigRational.  
322 - *  
323 - * The reciprocal has the numerator and denominator swapped.  
324 - *  
325 - * @return BigRational  
326 - *  
327 - * @throws DivisionByZeroException If the numerator is zero.  
328 - */  
329 - public function reciprocal() : BigRational  
330 - {  
331 - return new BigRational($this->denominator, $this->numerator, true);  
332 - }  
333 -  
334 - /**  
335 - * Returns the absolute value of this BigRational.  
336 - *  
337 - * @return BigRational  
338 - */  
339 - public function abs() : BigRational  
340 - {  
341 - return new BigRational($this->numerator->abs(), $this->denominator, false);  
342 - }  
343 -  
344 - /**  
345 - * Returns the negated value of this BigRational.  
346 - *  
347 - * @return BigRational  
348 - */  
349 - public function negated() : BigRational  
350 - {  
351 - return new BigRational($this->numerator->negated(), $this->denominator, false);  
352 - }  
353 -  
354 - /**  
355 - * Returns the simplified value of this BigRational.  
356 - *  
357 - * @return BigRational  
358 - */  
359 - public function simplified() : BigRational  
360 - {  
361 - $gcd = $this->numerator->gcd($this->denominator);  
362 -  
363 - $numerator = $this->numerator->quotient($gcd);  
364 - $denominator = $this->denominator->quotient($gcd);  
365 -  
366 - return new BigRational($numerator, $denominator, false);  
367 - }  
368 -  
369 - /**  
370 - * {@inheritdoc}  
371 - */  
372 - public function compareTo($that) : int  
373 - {  
374 - return $this->minus($that)->getSign();  
375 - }  
376 -  
377 - /**  
378 - * {@inheritdoc}  
379 - */  
380 - public function getSign() : int  
381 - {  
382 - return $this->numerator->getSign();  
383 - }  
384 -  
385 - /**  
386 - * {@inheritdoc}  
387 - */  
388 - public function toBigInteger() : BigInteger  
389 - {  
390 - $simplified = $this->simplified();  
391 -  
392 - if (! $simplified->denominator->isEqualTo(1)) {  
393 - throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.');  
394 - }  
395 -  
396 - return $simplified->numerator;  
397 - }  
398 -  
399 - /**  
400 - * {@inheritdoc}  
401 - */  
402 - public function toBigDecimal() : BigDecimal  
403 - {  
404 - return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator);  
405 - }  
406 -  
407 - /**  
408 - * {@inheritdoc}  
409 - */  
410 - public function toBigRational() : BigRational  
411 - {  
412 - return $this;  
413 - }  
414 -  
415 - /**  
416 - * {@inheritdoc}  
417 - */  
418 - public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal  
419 - {  
420 - return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);  
421 - }  
422 -  
423 - /**  
424 - * {@inheritdoc}  
425 - */  
426 - public function toInt() : int  
427 - {  
428 - return $this->toBigInteger()->toInt();  
429 - }  
430 -  
431 - /**  
432 - * {@inheritdoc}  
433 - */  
434 - public function toFloat() : float  
435 - {  
436 - return $this->numerator->toFloat() / $this->denominator->toFloat();  
437 - }  
438 -  
439 - /**  
440 - * {@inheritdoc}  
441 - */  
442 - public function __toString() : string  
443 - {  
444 - $numerator = (string) $this->numerator;  
445 - $denominator = (string) $this->denominator;  
446 -  
447 - if ($denominator === '1') {  
448 - return $numerator;  
449 - }  
450 -  
451 - return $this->numerator . '/' . $this->denominator;  
452 - }  
453 -  
454 - /**  
455 - * This method is required for serializing the object and SHOULD NOT be accessed directly.  
456 - *  
457 - * @internal  
458 - *  
459 - * @return array{numerator: BigInteger, denominator: BigInteger}  
460 - */  
461 - public function __serialize(): array  
462 - {  
463 - return ['numerator' => $this->numerator, 'denominator' => $this->denominator];  
464 - }  
465 -  
466 - /**  
467 - * This method is only here to allow unserializing the object and cannot be accessed directly.  
468 - *  
469 - * @internal  
470 - * @psalm-suppress RedundantPropertyInitializationCheck  
471 - *  
472 - * @param array{numerator: BigInteger, denominator: BigInteger} $data  
473 - *  
474 - * @return void  
475 - *  
476 - * @throws \LogicException  
477 - */  
478 - public function __unserialize(array $data): void  
479 - {  
480 - if (isset($this->numerator)) {  
481 - throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');  
482 - }  
483 -  
484 - $this->numerator = $data['numerator'];  
485 - $this->denominator = $data['denominator'];  
486 - }  
487 -  
488 - /**  
489 - * This method is required by interface Serializable and SHOULD NOT be accessed directly.  
490 - *  
491 - * @internal  
492 - *  
493 - * @return string  
494 - */  
495 - public function serialize() : string  
496 - {  
497 - return $this->numerator . '/' . $this->denominator;  
498 - }  
499 -  
500 - /**  
501 - * This method is only here to implement interface Serializable and cannot be accessed directly.  
502 - *  
503 - * @internal  
504 - * @psalm-suppress RedundantPropertyInitializationCheck  
505 - *  
506 - * @param string $value  
507 - *  
508 - * @return void  
509 - *  
510 - * @throws \LogicException  
511 - */  
512 - public function unserialize($value) : void  
513 - {  
514 - if (isset($this->numerator)) {  
515 - throw new \LogicException('unserialize() is an internal function, it must not be called directly.');  
516 - }  
517 -  
518 - [$numerator, $denominator] = \explode('/', $value);  
519 -  
520 - $this->numerator = BigInteger::of($numerator);  
521 - $this->denominator = BigInteger::of($denominator);  
522 - }  
523 -}  
1 -<?php  
2 -  
3 -declare(strict_types=1);  
4 -  
5 -namespace Brick\Math\Exception;  
6 -  
7 -/**  
8 - * Exception thrown when a division by zero occurs.  
9 - */  
10 -class DivisionByZeroException extends MathException  
11 -{  
12 - /**  
13 - * @return DivisionByZeroException  
14 - *  
15 - * @psalm-pure  
16 - */  
17 - public static function divisionByZero() : DivisionByZeroException  
18 - {  
19 - return new self('Division by zero.');  
20 - }  
21 -  
22 - /**  
23 - * @return DivisionByZeroException  
24 - *  
25 - * @psalm-pure  
26 - */  
27 - public static function modulusMustNotBeZero() : DivisionByZeroException  
28 - {  
29 - return new self('The modulus must not be zero.');  
30 - }  
31 -  
32 - /**  
33 - * @return DivisionByZeroException  
34 - *  
35 - * @psalm-pure  
36 - */  
37 - public static function denominatorMustNotBeZero() : DivisionByZeroException  
38 - {  
39 - return new self('The denominator of a rational number cannot be zero.');  
40 - }  
41 -}  
1 -<?php  
2 -  
3 -declare(strict_types=1);  
4 -  
5 -namespace Brick\Math\Exception;  
6 -  
7 -use Brick\Math\BigInteger;  
8 -  
9 -/**  
10 - * Exception thrown when an integer overflow occurs.  
11 - */  
12 -class IntegerOverflowException extends MathException  
13 -{  
14 - /**  
15 - * @param BigInteger $value  
16 - *  
17 - * @return IntegerOverflowException  
18 - *  
19 - * @psalm-pure  
20 - */  
21 - public static function toIntOverflow(BigInteger $value) : IntegerOverflowException  
22 - {  
23 - $message = '%s is out of range %d to %d and cannot be represented as an integer.';  
24 -  
25 - return new self(\sprintf($message, (string) $value, PHP_INT_MIN, PHP_INT_MAX));  
26 - }  
27 -}  
1 -<?php  
2 -  
3 -declare(strict_types=1);  
4 -  
5 -namespace Brick\Math\Exception;  
6 -  
7 -/**  
8 - * Base class for all math exceptions.  
9 - *  
10 - * This class is abstract to ensure that only fine-grained exceptions are thrown throughout the code.  
11 - */  
12 -class MathException extends \RuntimeException  
13 -{  
14 -}  
1 -<?php  
2 -  
3 -declare(strict_types=1);  
4 -  
5 -namespace Brick\Math\Exception;  
6 -  
7 -/**  
8 - * Exception thrown when attempting to perform an unsupported operation, such as a square root, on a negative number.  
9 - */  
10 -class NegativeNumberException extends MathException  
11 -{  
12 -}  
1 -<?php  
2 -  
3 -declare(strict_types=1);  
4 -  
5 -namespace Brick\Math\Exception;  
6 -  
7 -/**  
8 - * Exception thrown when attempting to create a number from a string with an invalid format.  
9 - */  
10 -class NumberFormatException extends MathException  
11 -{  
12 - /**  
13 - * @param string $char The failing character.  
14 - *  
15 - * @return NumberFormatException  
16 - *  
17 - * @psalm-pure  
18 - */  
19 - public static function charNotInAlphabet(string $char) : self  
20 - {  
21 - $ord = \ord($char);  
22 -  
23 - if ($ord < 32 || $ord > 126) {  
24 - $char = \strtoupper(\dechex($ord));  
25 -  
26 - if ($ord < 10) {  
27 - $char = '0' . $char;  
28 - }  
29 - } else {  
30 - $char = '"' . $char . '"';  
31 - }  
32 -  
33 - return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char));  
34 - }  
35 -}  
1 -<?php  
2 -  
3 -declare(strict_types=1);  
4 -  
5 -namespace Brick\Math\Exception;  
6 -  
7 -/**  
8 - * Exception thrown when a number cannot be represented at the requested scale without rounding.  
9 - */  
10 -class RoundingNecessaryException extends MathException  
11 -{  
12 - /**  
13 - * @return RoundingNecessaryException  
14 - *  
15 - * @psalm-pure  
16 - */  
17 - public static function roundingNecessary() : RoundingNecessaryException  
18 - {  
19 - return new self('Rounding is necessary to represent the result of the operation at this scale.');  
20 - }  
21 -}