Total Complexity | 95 |
Total Lines | 716 |
Duplicated Lines | 0 % |
Coverage | 100% |
Changes | 0 |
Complex classes like Real often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Real, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class Real extends Element |
||
20 | { |
||
21 | use UniversalClass; |
||
22 | use PrimitiveType; |
||
23 | |||
24 | /** |
||
25 | * Regex pattern to parse NR1 form number. |
||
26 | * |
||
27 | * @var string |
||
28 | */ |
||
29 | const NR1_REGEX = '/^\s*' . |
||
30 | '(?<s>[+\-])?' . // sign |
||
31 | '(?<i>\d+)' . // integer |
||
32 | '$/'; |
||
33 | |||
34 | /** |
||
35 | * Regex pattern to parse NR2 form number. |
||
36 | * |
||
37 | * @var string |
||
38 | */ |
||
39 | const NR2_REGEX = '/^\s*' . |
||
40 | '(?<s>[+\-])?' . // sign |
||
41 | '(?<d>(?:\d+[\.,]\d*)|(?:\d*[\.,]\d+))' . // decimal number |
||
42 | '$/'; |
||
43 | |||
44 | /** |
||
45 | * Regex pattern to parse NR3 form number. |
||
46 | * |
||
47 | * @var string |
||
48 | */ |
||
49 | const NR3_REGEX = '/^\s*' . |
||
50 | '(?<ms>[+\-])?' . // mantissa sign |
||
51 | '(?<m>(?:\d+[\.,]\d*)|(?:\d*[\.,]\d+))' . // mantissa |
||
52 | '[Ee](?<es>[+\-])?' . // exponent sign |
||
53 | '(?<e>\d+)' . // exponent |
||
54 | '$/'; |
||
55 | |||
56 | /** |
||
57 | * Regex pattern to parse PHP exponent number format. |
||
58 | * |
||
59 | * @see http://php.net/manual/en/language.types.float.php |
||
60 | * |
||
61 | * @var string |
||
62 | */ |
||
63 | const PHP_EXPONENT_DNUM = '/^' . |
||
64 | '(?<ms>[+\-])?' . // sign |
||
65 | '(?<m>' . |
||
66 | '\d+' . // LNUM |
||
67 | '|' . |
||
68 | '(?:\d*\.\d+|\d+\.\d*)' . // DNUM |
||
69 | ')[eE]' . |
||
70 | '(?<es>[+\-])?(?<e>\d+)' . // exponent |
||
71 | '$/'; |
||
72 | |||
73 | /** |
||
74 | * Exponent when value is positive or negative infinite. |
||
75 | * |
||
76 | * @var int |
||
77 | */ |
||
78 | const INF_EXPONENT = 2047; |
||
79 | |||
80 | /** |
||
81 | * Exponent bias for IEEE 754 double precision float. |
||
82 | * |
||
83 | * @var int |
||
84 | */ |
||
85 | const EXP_BIAS = -1023; |
||
86 | |||
87 | /** |
||
88 | * Signed integer mantissa. |
||
89 | * |
||
90 | * @var BigInt |
||
91 | */ |
||
92 | private $_mantissa; |
||
93 | |||
94 | /** |
||
95 | * Signed integer exponent. |
||
96 | * |
||
97 | * @var BigInt |
||
98 | */ |
||
99 | private $_exponent; |
||
100 | |||
101 | /** |
||
102 | * Abstract value base. |
||
103 | * |
||
104 | * Must be 2 or 10. |
||
105 | * |
||
106 | * @var int |
||
107 | */ |
||
108 | private $_base; |
||
109 | |||
110 | /** |
||
111 | * Whether to encode strictly in DER. |
||
112 | * |
||
113 | * @var bool |
||
114 | */ |
||
115 | private $_strictDer; |
||
116 | |||
117 | /** |
||
118 | * Number as a native float. |
||
119 | * |
||
120 | * @internal Lazily initialized |
||
121 | * |
||
122 | * @var null|float |
||
123 | */ |
||
124 | private $_float; |
||
125 | |||
126 | /** |
||
127 | * Constructor. |
||
128 | * |
||
129 | * @param \GMP|int|string $mantissa Integer mantissa |
||
130 | * @param \GMP|int|string $exponent Integer exponent |
||
131 | * @param int $base Base, 2 or 10 |
||
132 | */ |
||
133 | 56 | public function __construct($mantissa, $exponent, int $base = 10) |
|
134 | { |
||
135 | 56 | if (10 !== $base && 2 !== $base) { |
|
136 | 1 | throw new \UnexpectedValueException('Base must be 2 or 10.'); |
|
137 | } |
||
138 | 55 | $this->_typeTag = self::TYPE_REAL; |
|
139 | 55 | $this->_strictDer = true; |
|
140 | 55 | $this->_mantissa = new BigInt($mantissa); |
|
141 | 55 | $this->_exponent = new BigInt($exponent); |
|
142 | 55 | $this->_base = $base; |
|
143 | 55 | } |
|
144 | |||
145 | /** |
||
146 | * {@inheritdoc} |
||
147 | */ |
||
148 | 1 | public function __toString(): string |
|
149 | { |
||
150 | 1 | return sprintf('%g', $this->floatVal()); |
|
151 | } |
||
152 | |||
153 | /** |
||
154 | * Create base 2 real number from float. |
||
155 | * |
||
156 | * @param float $number |
||
157 | * |
||
158 | * @return self |
||
159 | */ |
||
160 | 36 | public static function fromFloat(float $number): self |
|
161 | { |
||
162 | 36 | if (is_infinite($number)) { |
|
163 | 4 | return self::_fromInfinite($number); |
|
164 | } |
||
165 | 32 | if (is_nan($number)) { |
|
166 | 1 | throw new \UnexpectedValueException('NaN values not supported.'); |
|
167 | } |
||
168 | 31 | [$m, $e] = self::_parse754Double(pack('E', $number)); |
|
169 | 31 | return new self($m, $e, 2); |
|
170 | } |
||
171 | |||
172 | /** |
||
173 | * Create base 10 real number from string. |
||
174 | * |
||
175 | * @param string $number Real number in base-10 textual form |
||
176 | * |
||
177 | * @return self |
||
178 | */ |
||
179 | 10 | public static function fromString(string $number): self |
|
180 | { |
||
181 | 10 | [$m, $e] = self::_parseString($number); |
|
182 | 9 | return new self($m, $e, 10); |
|
1 ignored issue
–
show
|
|||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Get self with strict DER flag set or unset. |
||
187 | * |
||
188 | * @param bool $strict whether to encode strictly in DER |
||
189 | * |
||
190 | * @return self |
||
191 | */ |
||
192 | 20 | public function withStrictDER(bool $strict): self |
|
193 | { |
||
194 | 20 | $obj = clone $this; |
|
195 | 20 | $obj->_strictDer = $strict; |
|
196 | 20 | return $obj; |
|
197 | } |
||
198 | |||
199 | /** |
||
200 | * Get the mantissa. |
||
201 | * |
||
202 | * @return BigInt |
||
203 | */ |
||
204 | 1 | public function mantissa(): BigInt |
|
205 | { |
||
206 | 1 | return $this->_mantissa; |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * Get the exponent. |
||
211 | * |
||
212 | * @return BigInt |
||
213 | */ |
||
214 | 3 | public function exponent(): BigInt |
|
215 | { |
||
216 | 3 | return $this->_exponent; |
|
217 | } |
||
218 | |||
219 | /** |
||
220 | * Get the base. |
||
221 | * |
||
222 | * @return int |
||
223 | */ |
||
224 | 1 | public function base(): int |
|
225 | { |
||
226 | 1 | return $this->_base; |
|
227 | } |
||
228 | |||
229 | /** |
||
230 | * Get number as a float. |
||
231 | * |
||
232 | * @return float |
||
233 | */ |
||
234 | 46 | public function floatVal(): float |
|
235 | { |
||
236 | 46 | if (!isset($this->_float)) { |
|
237 | 46 | $m = $this->_mantissa->intVal(); |
|
238 | 46 | $e = $this->_exponent->intVal(); |
|
239 | 46 | $this->_float = (float) ($m * pow($this->_base, $e)); |
|
240 | } |
||
241 | 46 | return $this->_float; |
|
1 ignored issue
–
show
|
|||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Get number as a NR3 form string conforming to DER rules. |
||
246 | * |
||
247 | * @return string |
||
248 | */ |
||
249 | 5 | public function nr3Val(): string |
|
250 | { |
||
251 | // convert to base 10 |
||
252 | 5 | if (2 === $this->_base) { |
|
253 | 1 | [$m, $e] = self::_parseString(sprintf('%15E', $this->floatVal())); |
|
254 | } else { |
||
255 | 4 | $m = $this->_mantissa->gmpObj(); |
|
256 | 4 | $e = $this->_exponent->gmpObj(); |
|
257 | } |
||
258 | // shift trailing zeroes from the mantissa to the exponent |
||
259 | // (X.690 07-2002, section 11.3.2.4) |
||
260 | 5 | while (0 != $m && 0 == $m % 10) { |
|
261 | 1 | $m /= 10; |
|
262 | 1 | ++$e; |
|
263 | } |
||
264 | // if exponent is zero, it must be prefixed with a "+" sign |
||
265 | // (X.690 07-2002, section 11.3.2.6) |
||
266 | 5 | if (0 == $e) { |
|
267 | 1 | $es = '+'; |
|
268 | } else { |
||
269 | 4 | $es = $e < 0 ? '-' : ''; |
|
270 | } |
||
271 | 5 | return sprintf('%s.E%s%s', gmp_strval($m), $es, gmp_strval(gmp_abs($e))); |
|
272 | } |
||
273 | |||
274 | /** |
||
275 | * {@inheritdoc} |
||
276 | */ |
||
277 | 43 | protected function _encodedContentDER(): string |
|
278 | { |
||
279 | 43 | if (self::INF_EXPONENT == $this->_exponent->gmpObj()) { |
|
1 ignored issue
–
show
|
|||
280 | 5 | return $this->_encodeSpecial(); |
|
281 | } |
||
282 | // if the real value is the value zero, there shall be no contents |
||
283 | // octets in the encoding. (X.690 07-2002, section 8.5.2) |
||
284 | 38 | if (0 == $this->_mantissa->gmpObj()) { |
|
1 ignored issue
–
show
|
|||
285 | 2 | return ''; |
|
286 | } |
||
287 | 36 | if (10 === $this->_base) { |
|
288 | 1 | return $this->_encodeDecimal(); |
|
289 | } |
||
290 | 35 | return $this->_encodeBinary(); |
|
291 | } |
||
292 | |||
293 | /** |
||
294 | * Encode in binary format. |
||
295 | * |
||
296 | * @return string |
||
297 | */ |
||
298 | 35 | protected function _encodeBinary(): string |
|
299 | { |
||
300 | 35 | [$base, $sign, $m, $e] = $this->_prepareBinaryEncoding(); |
|
301 | 35 | $zero = gmp_init(0, 10); |
|
302 | 35 | $byte = 0x80; |
|
303 | 35 | if ($sign < 0) { |
|
304 | 14 | $byte |= 0x40; |
|
305 | } |
||
306 | // normalization: mantissa must be 0 or odd |
||
307 | 35 | if (2 === $base) { |
|
308 | // while last bit is zero |
||
309 | 22 | while ($m > 0 && 0 === gmp_cmp($m & 0x01, $zero)) { |
|
310 | 1 | $m >>= 1; |
|
311 | 1 | ++$e; |
|
312 | } |
||
313 | 13 | } elseif (8 === $base) { |
|
314 | 5 | $byte |= 0x10; |
|
315 | // while last 3 bits are zero |
||
316 | 5 | while ($m > 0 && 0 === gmp_cmp($m & 0x07, $zero)) { |
|
317 | 1 | $m >>= 3; |
|
318 | 1 | ++$e; |
|
319 | } |
||
320 | } else { // base === 16 |
||
321 | 8 | $byte |= 0x20; |
|
322 | // while last 4 bits are zero |
||
323 | 8 | while ($m > 0 && 0 === gmp_cmp($m & 0x0f, $zero)) { |
|
324 | 2 | $m >>= 4; |
|
325 | 2 | ++$e; |
|
326 | } |
||
327 | } |
||
328 | // scale factor |
||
329 | 35 | $scale = 0; |
|
330 | 35 | while ($m > 0 && 0 === gmp_cmp($m & 0x01, $zero)) { |
|
331 | 1 | $m >>= 1; |
|
332 | 1 | ++$scale; |
|
333 | } |
||
334 | 35 | $byte |= ($scale & 0x03) << 2; |
|
335 | // encode exponent |
||
336 | 35 | $exp_bytes = (new BigInt($e))->signedOctets(); |
|
337 | 35 | $exp_len = strlen($exp_bytes); |
|
338 | 35 | if ($exp_len > 0xff) { |
|
339 | 1 | throw new \RangeException('Exponent encoding is too long.'); |
|
340 | } |
||
341 | 34 | if ($exp_len <= 3) { |
|
342 | 32 | $byte |= ($exp_len - 1) & 0x03; |
|
343 | 32 | $bytes = chr($byte); |
|
344 | } else { |
||
345 | 2 | $byte |= 0x03; |
|
346 | 2 | $bytes = chr($byte) . chr($exp_len); |
|
347 | } |
||
348 | 34 | $bytes .= $exp_bytes; |
|
349 | // encode mantissa |
||
350 | 34 | $bytes .= (new BigInt($m))->unsignedOctets(); |
|
1 ignored issue
–
show
|
|||
351 | 34 | return $bytes; |
|
352 | } |
||
353 | |||
354 | /** |
||
355 | * Encode in decimal format. |
||
356 | * |
||
357 | * @return strign |
||
358 | */ |
||
359 | 1 | protected function _encodeDecimal(): string |
|
360 | { |
||
361 | // encode in NR3 decimal encoding |
||
362 | 1 | return chr(0x03) . $this->nr3Val(); |
|
363 | } |
||
364 | |||
365 | /** |
||
366 | * Encode special value. |
||
367 | * |
||
368 | * @return string |
||
369 | */ |
||
370 | 5 | protected function _encodeSpecial(): string |
|
371 | { |
||
372 | 5 | switch ($this->_mantissa->intVal()) { |
|
373 | // positive infitinity |
||
374 | 5 | case 1: |
|
375 | 2 | return chr(0x40); |
|
376 | // negative infinity |
||
377 | case -1: |
||
378 | 2 | return chr(0x41); |
|
379 | } |
||
380 | 1 | throw new \LogicException('Invalid special value.'); |
|
381 | } |
||
382 | |||
383 | /** |
||
384 | * {@inheritdoc} |
||
385 | */ |
||
386 | 47 | protected static function _decodeFromDER(Identifier $identifier, |
|
387 | string $data, int &$offset): ElementBase |
||
388 | { |
||
389 | 47 | $idx = $offset; |
|
390 | 47 | $length = Length::expectFromDER($data, $idx)->intLength(); |
|
391 | // if length is zero, value is zero (spec 8.5.2) |
||
392 | 47 | if (!$length) { |
|
393 | 2 | $obj = new self(0, 0, 10); |
|
394 | } else { |
||
395 | 45 | $bytes = substr($data, $idx, $length); |
|
396 | 45 | $byte = ord($bytes[0]); |
|
397 | 45 | if (0x80 & $byte) { // bit 8 = 1 |
|
398 | 37 | $obj = self::_decodeBinaryEncoding($bytes); |
|
399 | 8 | } elseif (0x00 === $byte >> 6) { // bit 8 = 0, bit 7 = 0 |
|
400 | 2 | $obj = self::_decodeDecimalEncoding($bytes); |
|
401 | } else { // bit 8 = 0, bit 7 = 1 |
||
402 | 6 | $obj = self::_decodeSpecialRealValue($bytes); |
|
403 | } |
||
404 | } |
||
405 | 40 | $offset = $idx + $length; |
|
406 | 40 | return $obj; |
|
407 | } |
||
408 | |||
409 | /** |
||
410 | * Decode binary encoding. |
||
411 | * |
||
412 | * @param string $data |
||
413 | */ |
||
414 | 37 | protected static function _decodeBinaryEncoding(string $data) |
|
415 | { |
||
416 | 37 | $byte = ord($data[0]); |
|
417 | // bit 7 is set if mantissa is negative |
||
418 | 37 | $neg = (bool) (0x40 & $byte); |
|
419 | // encoding base in bits 6 and 5 |
||
420 | 37 | switch (($byte >> 4) & 0x03) { |
|
421 | 37 | case 0b00: |
|
422 | 23 | $base = 2; |
|
423 | 23 | break; |
|
424 | 14 | case 0b01: |
|
425 | 5 | $base = 8; |
|
426 | 5 | break; |
|
427 | 9 | case 0b10: |
|
428 | 8 | $base = 16; |
|
429 | 8 | break; |
|
430 | default: |
||
431 | 1 | throw new DecodeException( |
|
432 | 1 | 'Reserved REAL binary encoding base not supported.'); |
|
433 | } |
||
434 | // scaling factor in bits 4 and 3 |
||
435 | 36 | $scale = ($byte >> 2) & 0x03; |
|
436 | 36 | $idx = 1; |
|
437 | // content length in bits 2 and 1 |
||
438 | 36 | $len = ($byte & 0x03) + 1; |
|
439 | // if both bits are set, the next octet encodes the length |
||
440 | 36 | if ($len > 3) { |
|
441 | 2 | if (strlen($data) < 2) { |
|
442 | 1 | throw new DecodeException( |
|
443 | 1 | 'Unexpected end of data while decoding REAL exponent length.'); |
|
444 | } |
||
445 | 1 | $len = ord($data[1]); |
|
446 | 1 | $idx = 2; |
|
447 | } |
||
448 | 35 | if (strlen($data) < $idx + $len) { |
|
449 | 1 | throw new DecodeException( |
|
450 | 1 | 'Unexpected end of data while decoding REAL exponent.'); |
|
451 | } |
||
452 | // decode exponent |
||
453 | 34 | $octets = substr($data, $idx, $len); |
|
454 | 34 | $exp = BigInt::fromSignedOctets($octets)->gmpObj(); |
|
455 | 34 | if (8 === $base) { |
|
456 | 5 | $exp *= 3; |
|
457 | 29 | } elseif (16 === $base) { |
|
458 | 8 | $exp *= 4; |
|
459 | } |
||
460 | 34 | if (strlen($data) <= $idx + $len) { |
|
461 | 1 | throw new DecodeException( |
|
462 | 1 | 'Unexpected end of data while decoding REAL mantissa.'); |
|
463 | } |
||
464 | // decode mantissa |
||
465 | 33 | $octets = substr($data, $idx + $len); |
|
466 | 33 | $n = BigInt::fromUnsignedOctets($octets)->gmpObj(); |
|
467 | 33 | $n *= 2 ** $scale; |
|
468 | 33 | if ($neg) { |
|
469 | 14 | $n = gmp_neg($n); |
|
470 | } |
||
471 | 33 | return new self($n, $exp, 2); |
|
1 ignored issue
–
show
|
|||
472 | } |
||
473 | |||
474 | /** |
||
475 | * Decode decimal encoding. |
||
476 | * |
||
477 | * @param string $data |
||
478 | * |
||
479 | * @throws \RuntimeException |
||
480 | * |
||
481 | * @return self |
||
482 | */ |
||
483 | 2 | protected static function _decodeDecimalEncoding(string $data): self |
|
484 | { |
||
485 | 2 | $nr = ord($data[0]) & 0x3f; |
|
486 | 2 | if (!in_array($nr, [1, 2, 3])) { |
|
487 | 1 | throw new DecodeException('Unsupported decimal encoding form.'); |
|
488 | } |
||
489 | 1 | $str = substr($data, 1); |
|
490 | 1 | return self::fromString($str); |
|
491 | } |
||
492 | |||
493 | /** |
||
494 | * Decode special encoding. |
||
495 | * |
||
496 | * @param string $data |
||
497 | * |
||
498 | * @return self |
||
499 | */ |
||
500 | 6 | protected static function _decodeSpecialRealValue(string $data): self |
|
514 | } |
||
515 | |||
516 | /** |
||
517 | * Prepare value for binary encoding. |
||
518 | * |
||
519 | * @return array (int) base, (int) sign, (\GMP) mantissa and (\GMP) exponent |
||
520 | */ |
||
521 | 35 | protected function _prepareBinaryEncoding(): array |
|
541 | } |
||
542 | |||
543 | /** |
||
544 | * Initialize from INF or -INF. |
||
545 | * |
||
546 | * @param float $inf |
||
547 | * |
||
548 | * @return self |
||
549 | */ |
||
550 | 4 | private static function _fromInfinite(float $inf): self |
|
551 | { |
||
552 | 4 | return new self($inf === -INF ? -1 : 1, self::INF_EXPONENT, 2); |
|
553 | } |
||
554 | |||
555 | /** |
||
556 | * Parse IEEE 754 big endian formatted double precision float to base 2 |
||
557 | * mantissa and exponent. |
||
558 | * |
||
559 | * @param string $octets 64 bits |
||
560 | * |
||
561 | * @return \GMP[] Tuple of mantissa and exponent |
||
562 | */ |
||
563 | 31 | private static function _parse754Double(string $octets): array |
|
564 | { |
||
565 | 31 | $n = gmp_import($octets, 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN); |
|
566 | // sign bit |
||
567 | 31 | $neg = gmp_testbit($n, 63); |
|
1 ignored issue
–
show
|
|||
568 | // 11 bits of biased exponent |
||
569 | 31 | $exp = (gmp_and($n, '0x7ff0000000000000') >> 52) + self::EXP_BIAS; |
|
1 ignored issue
–
show
|
|||
570 | // 52 bits of mantissa |
||
571 | 31 | $man = gmp_and($n, '0xfffffffffffff'); |
|
572 | // zero, ASN.1 doesn't differentiate -0 from +0 |
||
573 | 31 | if (self::EXP_BIAS == $exp && 0 == $man) { |
|
574 | 2 | return [gmp_init(0, 10), gmp_init(0, 10)]; |
|
1 ignored issue
–
show
|
|||
575 | } |
||
576 | // denormalized value, shift binary point |
||
577 | 29 | if (self::EXP_BIAS == $exp) { |
|
578 | 4 | ++$exp; |
|
579 | } |
||
580 | // normalized value, insert implicit leading one before the binary point |
||
581 | else { |
||
582 | 25 | gmp_setbit($man, 52); |
|
583 | } |
||
584 | // find the last fraction bit that is set |
||
585 | 29 | $last = gmp_scan1($man, 0); |
|
586 | 29 | $bits_for_fraction = 52 - $last; |
|
587 | // adjust mantissa and exponent so that we have integer values |
||
588 | 29 | $man >>= $last; |
|
589 | 29 | $exp -= $bits_for_fraction; |
|
590 | // negate mantissa if number was negative |
||
591 | 29 | if ($neg) { |
|
592 | 15 | $man = gmp_neg($man); |
|
593 | } |
||
594 | 29 | return [$man, $exp]; |
|
1 ignored issue
–
show
|
|||
595 | } |
||
596 | |||
597 | /** |
||
598 | * Parse textual REAL number to base 10 mantissa and exponent. |
||
599 | * |
||
600 | * @param string $str Number |
||
601 | * |
||
602 | * @return \GMP[] Tuple of mantissa and exponent |
||
603 | */ |
||
604 | 11 | private static function _parseString(string $str): array |
|
605 | { |
||
606 | // PHP exponent format |
||
607 | 11 | if (preg_match(self::PHP_EXPONENT_DNUM, $str, $match)) { |
|
608 | 2 | [$m, $e] = self::_parsePHPExponentMatch($match); |
|
609 | } |
||
610 | // NR3 format |
||
611 | 9 | elseif (preg_match(self::NR3_REGEX, $str, $match)) { |
|
612 | 3 | [$m, $e] = self::_parseNR3Match($match); |
|
613 | } |
||
614 | // NR2 format |
||
615 | 6 | elseif (preg_match(self::NR2_REGEX, $str, $match)) { |
|
616 | 2 | [$m, $e] = self::_parseNR2Match($match); |
|
617 | } |
||
618 | // NR1 format |
||
619 | 4 | elseif (preg_match(self::NR1_REGEX, $str, $match)) { |
|
620 | 3 | [$m, $e] = self::_parseNR1Match($match); |
|
621 | } |
||
622 | // invalid number |
||
623 | else { |
||
624 | 1 | throw new \UnexpectedValueException( |
|
625 | 1 | "{$str} could not be parsed to REAL."); |
|
626 | } |
||
627 | // normalize so that mantsissa has no trailing zeroes |
||
628 | 10 | while (0 != $m && 0 == $m % 10) { |
|
629 | 1 | $m /= 10; |
|
630 | 1 | ++$e; |
|
631 | } |
||
632 | 10 | return [$m, $e]; |
|
1 ignored issue
–
show
|
|||
633 | } |
||
634 | |||
635 | /** |
||
636 | * Parse PHP form float to base 10 mantissa and exponent. |
||
637 | * |
||
638 | * @param array $match Regexp match |
||
639 | * |
||
640 | * @return \GMP[] Tuple of mantissa and exponent |
||
641 | */ |
||
642 | 2 | private static function _parsePHPExponentMatch(array $match): array |
|
661 | } |
||
662 | |||
663 | /** |
||
664 | * Parse NR3 form number to base 10 mantissa and exponent. |
||
665 | * |
||
666 | * @param array $match Regexp match |
||
667 | * |
||
668 | * @return \GMP[] Tuple of mantissa and exponent |
||
669 | */ |
||
670 | 3 | private static function _parseNR3Match(array $match): array |
|
691 | } |
||
692 | |||
693 | /** |
||
694 | * Parse NR2 form number to base 10 mantissa and exponent. |
||
695 | * |
||
696 | * @param array $match Regexp match |
||
697 | * |
||
698 | * @return \GMP[] Tuple of mantissa and exponent |
||
699 | */ |
||
700 | 2 | private static function _parseNR2Match(array $match): array |
|
717 | } |
||
718 | |||
719 | /** |
||
720 | * Parse NR1 form number to base 10 mantissa and exponent. |
||
721 | * |
||
722 | * @param array $match Regexp match |
||
723 | * |
||
724 | * @return \GMP[] Tuple of mantissa and exponent |
||
725 | */ |
||
726 | 3 | private static function _parseNR1Match(array $match): array |
|
727 | { |
||
728 | 3 | $sign = '-' === $match['s'] ? -1 : 1; |
|
737 |