1
|
|
|
<?php
|
2
|
|
|
|
3
|
|
|
namespace Samsara\Fermat\Values;
|
4
|
|
|
|
5
|
|
|
use Samsara\Exceptions\SystemError\PlatformError\MissingPackage;
|
6
|
|
|
use Samsara\Exceptions\UsageError\IntegrityConstraint;
|
7
|
|
|
use Samsara\Fermat\Enums\NumberBase;
|
8
|
|
|
use Samsara\Fermat\Provider\BaseConversionProvider;
|
9
|
|
|
use Samsara\Fermat\Types\Base\Interfaces\Numbers\NumberInterface;
|
10
|
|
|
use Samsara\Fermat\Types\Decimal;
|
11
|
|
|
use Samsara\Fermat\Numbers;
|
12
|
|
|
use Samsara\Fermat\Types\Base\Interfaces\Numbers\DecimalInterface;
|
13
|
|
|
|
14
|
|
|
/**
|
15
|
|
|
*
|
16
|
|
|
*/
|
17
|
|
|
class MutableDecimal extends Decimal
|
18
|
|
|
{
|
19
|
|
|
|
20
|
|
|
/**
|
21
|
|
|
* @throws IntegrityConstraint
|
22
|
|
|
* @throws MissingPackage
|
23
|
|
|
*/
|
24
|
1 |
|
public function continuousModulo(NumberInterface|string|int|float $mod): DecimalInterface
|
25
|
|
|
{
|
26
|
|
|
|
27
|
1 |
|
$mod = Numbers::makeOrDont(Numbers::IMMUTABLE, $mod, $this->scale+1);
|
28
|
1 |
|
$oldNum = Numbers::make(Numbers::IMMUTABLE, $this->getValue(NumberBase::Ten), $this->scale+1);
|
29
|
|
|
|
30
|
1 |
|
$multiple = $oldNum->divide($mod)->floor();
|
31
|
1 |
|
$multipleCeil = $multiple->ceil();
|
32
|
1 |
|
$digits = $multipleCeil->subtract($multiple)->numberOfLeadingZeros();
|
33
|
|
|
|
34
|
1 |
|
if ($digits >= $this->getScale()) {
|
35
|
|
|
$multiple = $multipleCeil;
|
36
|
|
|
} else {
|
37
|
1 |
|
$multiple = $multiple->floor();
|
38
|
|
|
}
|
39
|
|
|
|
40
|
1 |
|
$remainder = $oldNum->subtract($mod->multiply($multiple));
|
41
|
|
|
|
42
|
1 |
|
return Numbers::make(Numbers::MUTABLE, $remainder->truncate($this->scale-1)->getValue(NumberBase::Ten), $this->scale-1, $this->getBase());
|
43
|
|
|
|
44
|
|
|
}
|
45
|
|
|
|
46
|
|
|
/**
|
47
|
|
|
* @param string $value
|
48
|
|
|
* @param int|null $scale
|
49
|
|
|
* @param NumberBase|null $base
|
50
|
|
|
* @param bool $setToNewBase
|
51
|
|
|
* @return MutableDecimal
|
52
|
|
|
*/
|
53
|
423 |
|
protected function setValue(string $value, ?int $scale = null, ?NumberBase $base = null, bool $setToNewBase = false): self
|
54
|
|
|
{
|
55
|
423 |
|
$imaginary = false;
|
56
|
|
|
|
57
|
423 |
|
if (str_contains($value, 'i')) {
|
58
|
20 |
|
$value = str_replace('i', '', $value);
|
59
|
20 |
|
$imaginary = true;
|
60
|
|
|
}
|
61
|
|
|
|
62
|
423 |
|
if (!is_null($base) && $base != NumberBase::Ten) {
|
63
|
|
|
$value = BaseConversionProvider::convertStringToBaseTen($value, $base);
|
64
|
|
|
}
|
65
|
|
|
|
66
|
423 |
|
$this->imaginary = $imaginary;
|
67
|
|
|
|
68
|
423 |
|
if ($setToNewBase) {
|
69
|
|
|
$this->base = $base ?? $this->getBase();
|
70
|
|
|
}
|
71
|
|
|
|
72
|
423 |
|
$this->value = $this->translateValue($value);
|
73
|
|
|
|
74
|
423 |
|
$scale = $scale ?? $this->getScale();
|
75
|
|
|
|
76
|
423 |
|
$this->scale = $this->determineScale($this->getDecimalPart(), $scale);
|
77
|
|
|
|
78
|
423 |
|
return $this;
|
79
|
|
|
}
|
80
|
|
|
|
81
|
|
|
} |