Passed
Pull Request — master (#132)
by Jordan
05:46
created

ArithmeticTests::divisionMutableDecimalProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
eloc 32
nc 1
nop 0
dl 0
loc 36
rs 9.408
c 3
b 0
f 0
1
<?php
2
3
namespace Samsara\Fermat\Values;
4
5
use PHPUnit\Framework\TestCase;
6
use Samsara\Exceptions\SystemError\PlatformError\MissingPackage;
7
use Samsara\Exceptions\UsageError\IntegrityConstraint;
8
use Samsara\Fermat\Enums\NumberBase;
9
use Samsara\Fermat\Types\Base\Number;
10
use Samsara\Fermat\Enums\CalcMode;
11
12
class ArithmeticTests extends TestCase
13
{
14
15
    /*
16
     * ADDITION
17
     */
18
19
    public function additionImmutableDecimalProvider(): array
20
    {
21
22
        $five = (new ImmutableDecimal(5))->setMode(CalcMode::Precision);
23
        $fiveBaseFive = (new ImmutableDecimal(5, null, NumberBase::Five))->setMode(CalcMode::Precision);
24
        $ten = (new ImmutableDecimal(10))->setMode(CalcMode::Precision);
25
        $oneQuarter = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
26
        $sixTenths = (new ImmutableDecimal('0.6'))->setMode(CalcMode::Precision);
27
        $fourTenths = (new ImmutableDecimal('0.4'))->setMode(CalcMode::Precision);
28
        $oneTenth = (new ImmutableDecimal('0.1'))->setMode(CalcMode::Precision);
29
        $twoTenths = (new ImmutableDecimal('0.2'))->setMode(CalcMode::Precision);
30
        $tenScale = (new ImmutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
31
        $elevenScale = (new ImmutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
32
        $tenPowThirty = (new ImmutableDecimal('1000000000000000000000000000000'))->setMode(CalcMode::Precision);
33
        $negFour = (new ImmutableDecimal('-4'))->setMode(CalcMode::Precision);
34
        $fiveI = (new ImmutableDecimal('5i'))->setMode(CalcMode::Precision);
35
        $tenI = (new ImmutableDecimal('10i'))->setMode(CalcMode::Precision);
36
37
        return [
38
            'IDecimal 5+10' => [$five, $ten, '15', NumberBase::Ten, 10],
39
            'IDecimal 5+10 base 5' => [$fiveBaseFive, $ten, '30', NumberBase::Five, 10],
40
            'IDecimal 5+1/4' => [$five, $oneQuarter, '5.25', NumberBase::Ten, 10],
41
            'IDecimal 1/4+5' => [$oneQuarter, $five, '21/4', NumberBase::Ten, 10],
42
            'IDecimal 0.6+0.4' => [$sixTenths, $fourTenths, '1', NumberBase::Ten, 10],
43
            'IDecimal 0.1+0.2' => [$oneTenth, $twoTenths, '0.3', NumberBase::Ten, 10],
44
            'IDecimal 0.1+0.0000000001' => [$oneTenth, $tenScale, '0.1000000001', NumberBase::Ten, 10],
45
            'IDecimal 0.1+0.00000000001' => [$oneTenth, $elevenScale, '0.1', NumberBase::Ten, 10],
46
            'IDecimal 1000000000000000000000000000000+5' => [$tenPowThirty, $five, '1000000000000000000000000000005', NumberBase::Ten, 10],
47
            'IDecimal 1000000000000000000000000000000+0.00000000001' => [$tenPowThirty, $elevenScale, '1000000000000000000000000000000', NumberBase::Ten, 10],
48
            'IDecimal 0.00000000001+1000000000000000000000000000000' => [$elevenScale, $tenPowThirty, '1000000000000000000000000000000.00000000001', NumberBase::Ten, 11],
49
            'IDecimal -4+0.1' => [$negFour, $oneTenth, '-3.9', NumberBase::Ten, 10],
50
            'IDecimal 5+5i' => [$five, $fiveI, MissingPackage::class, NumberBase::Ten, 10],
51
            'IDecimal 5i+10i' => [$fiveI, $tenI, '15i', NumberBase::Ten, 10],
52
        ];
53
54
    }
55
56
    public function additionMutableDecimalProvider(): array
57
    {
58
59
        $five = (new MutableDecimal(5))->setMode(CalcMode::Precision);
60
        $fiveBaseFive = (new MutableDecimal(5, null, NumberBase::Five))->setMode(CalcMode::Precision);
61
        $ten = (new MutableDecimal(10))->setMode(CalcMode::Precision);
62
        $oneQuarter = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
63
        $sixTenths = (new MutableDecimal('0.6'))->setMode(CalcMode::Precision);
64
        $fourTenths = (new MutableDecimal('0.4'))->setMode(CalcMode::Precision);
65
        $oneTenth = (new MutableDecimal('0.1'))->setMode(CalcMode::Precision);
66
        $twoTenths = (new MutableDecimal('0.2'))->setMode(CalcMode::Precision);
67
        $tenScale = (new MutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
68
        $elevenScale = (new MutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
69
        $tenPowThirty = (new MutableDecimal('1000000000000000000000000000000'))->setMode(CalcMode::Precision);
70
        $negFour = (new MutableDecimal('-4'))->setMode(CalcMode::Precision);
71
        $fiveI = (new MutableDecimal('5i'))->setMode(CalcMode::Precision);
72
        $tenI = (new MutableDecimal('10i'))->setMode(CalcMode::Precision);
73
74
        return [
75
            'MDecimal 5+10' => [$five, $ten, '15', NumberBase::Ten, 10],
76
            'MDecimal 5+10 base 5' => [$fiveBaseFive, $ten, '30', NumberBase::Five, 10],
77
            'MDecimal 5+1/4' => [$five, $oneQuarter, '15.25', NumberBase::Ten, 10],
78
            'MDecimal 1/4+5' => [$oneQuarter, $five, '31/2', NumberBase::Ten, 10],
79
            'MDecimal 0.6+0.4' => [$sixTenths, $fourTenths, '1', NumberBase::Ten, 10],
80
            'MDecimal 0.1+0.2' => [$oneTenth, $twoTenths, '0.3', NumberBase::Ten, 10],
81
            'MDecimal 0.1+0.0000000001' => [$oneTenth, $tenScale, '0.3000000001', NumberBase::Ten, 10],
82
            'MDecimal 0.1+0.00000000001' => [$oneTenth, $elevenScale, '0.3000000001', NumberBase::Ten, 10],
83
            'MDecimal 1000000000000000000000000000000+5' => [$tenPowThirty, $five, '1000000000000000000000000000015.25', NumberBase::Ten, 10],
84
            'MDecimal 1000000000000000000000000000000+0.00000000001' => [$tenPowThirty, $elevenScale, '1000000000000000000000000000015.25', NumberBase::Ten, 10],
85
            'MDecimal 0.00000000001+1000000000000000000000000000000' => [$elevenScale, $tenPowThirty, '1000000000000000000000000000015.25000000001', NumberBase::Ten, 11],
86
            'MDecimal -4+0.1' => [$negFour, $oneTenth, '-3.6999999999', NumberBase::Ten, 10],
87
            'MDecimal 5+5i' => [$five, $fiveI, MissingPackage::class, NumberBase::Ten, 10],
88
            'MDecimal 5i+10i' => [$fiveI, $tenI, '15i', NumberBase::Ten, 10],
89
        ];
90
91
    }
92
93
    public function additionImmutableFractionProvider(): array
94
    {
95
        $a = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
96
        $b = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(5))->setMode(CalcMode::Precision));
97
        $c = new ImmutableFraction((new ImmutableDecimal(3))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
98
        $d = new ImmutableFraction((new ImmutableDecimal(4))->setMode(CalcMode::Precision), (new ImmutableDecimal(5))->setMode(CalcMode::Precision));
99
        $e = new ImmutableFraction((new ImmutableDecimal(4))->setMode(CalcMode::Precision), (new ImmutableDecimal(8))->setMode(CalcMode::Precision));
100
        $f = new ImmutableFraction((new ImmutableDecimal(3))->setMode(CalcMode::Precision), (new ImmutableDecimal('10000000000000000000000000'))->setMode(CalcMode::Precision));
101
102
        return [
103
            'IFraction 1/4+1/5' => [$a, $b, '9/20', NumberBase::Ten, 10],
104
            'IFraction 1/4+3/4' => [$a, $c, '1/1', NumberBase::Ten, 10],
105
            'IFraction 1/5+4/5' => [$b, $d, '1/1', NumberBase::Ten, 10],
106
            'IFraction 1/5+3/4' => [$b, $c, '19/20', NumberBase::Ten, 10],
107
            'IFraction 1/4+4/5' => [$a, $d, '21/20', NumberBase::Ten, 10],
108
            'IFraction 1/4+4/8' => [$a, $e, '3/4', NumberBase::Ten, 10],
109
            'IFraction 4/8+1/4' => [$e, $a, '3/4', NumberBase::Ten, 10],
110
            'IFraction 1/4+3/10000000000000000000000000' => [$a, $f, '2500000000000000000000003/10000000000000000000000000', NumberBase::Ten, 10]
111
        ];
112
    }
113
114
    /**
115
     * @dataProvider additionImmutableDecimalProvider
116
     * @dataProvider additionMutableDecimalProvider
117
     * @dataProvider additionImmutableFractionProvider
118
     */
119
    public function testAddition(Number $a, Number $b, string $expected, NumberBase $base, int $scale)
120
    {
121
        if (str_contains($expected, 'Exception')) {
122
            $this->expectException($expected);
123
            $a->add($b);
124
        } else {
125
            $answer = $a->add($b);
126
            $this->assertEquals($expected, $answer->getValue());
127
            $this->assertEquals($base, $answer->getBase());
0 ignored issues
show
Bug introduced by
The method getBase() does not exist on Samsara\Fermat\Types\Bas...Numbers\NumberInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Samsara\Fermat\Types\Bas...s\SimpleNumberInterface or Samsara\Fermat\Types\Bas...mbers\FractionInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

127
            $this->assertEquals($base, $answer->/** @scrutinizer ignore-call */ getBase());
Loading history...
Bug introduced by
The method getBase() does not exist on Samsara\Fermat\Types\Bas...mbers\FractionInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Samsara\Fermat\Types\Bas...mbers\FractionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

127
            $this->assertEquals($base, $answer->/** @scrutinizer ignore-call */ getBase());
Loading history...
128
            $this->assertEquals($scale, $answer->getScale());
129
        }
130
    }
131
132
    /*
133
     * SUBTRACTION
134
     */
135
136
    public function subtractionMutableDecimalProvider(): array
137
    {
138
139
        $five = (new MutableDecimal(5))->setMode(CalcMode::Precision);
140
        $fiveBaseFive = (new MutableDecimal(5, null, NumberBase::Five))->setMode(CalcMode::Precision);
141
        $ten = (new MutableDecimal(10))->setMode(CalcMode::Precision);
142
        $oneQuarter = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
143
        $sixTenths = (new MutableDecimal('0.6'))->setMode(CalcMode::Precision);
144
        $fourTenths = (new MutableDecimal('0.4'))->setMode(CalcMode::Precision);
145
        $oneTenth = (new MutableDecimal('0.1'))->setMode(CalcMode::Precision);
146
        $twoTenths = (new MutableDecimal('0.2'))->setMode(CalcMode::Precision);
147
        $tenScale = (new MutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
148
        $elevenScale = (new MutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
149
        $tenPowThirty = (new MutableDecimal('1000000000000000000000000000000'))->setMode(CalcMode::Precision);
150
        $negFour = (new MutableDecimal('-4'))->setMode(CalcMode::Precision);
151
        $fiveI = (new MutableDecimal('5i'))->setMode(CalcMode::Precision);
152
        $tenI = (new MutableDecimal('10i'))->setMode(CalcMode::Precision);
153
154
        return [
155
            'MDecimal 5-10' => [$five, $ten, '-5', NumberBase::Ten, 10],
156
            'MDecimal 5-10 base 5' => [$fiveBaseFive, $ten, '-10', NumberBase::Five, 10],
157
            'MDecimal 5-1/4' => [$five, $oneQuarter, '-5.25', NumberBase::Ten, 10],
158
            'MDecimal 1/4-5' => [$oneQuarter, $five, '11/2', NumberBase::Ten, 10],
159
            'MDecimal 0.6-0.4' => [$sixTenths, $fourTenths, '0.2', NumberBase::Ten, 10],
160
            'MDecimal 0.1-0.2' => [$oneTenth, $twoTenths, '-0.1', NumberBase::Ten, 10],
161
            'MDecimal 0.1-0.0000000001' => [$oneTenth, $tenScale, '-0.1000000001', NumberBase::Ten, 10],
162
            'MDecimal 0.1-0.00000000001' => [$oneTenth, $elevenScale, '-0.1000000001', NumberBase::Ten, 10],
163
            'MDecimal 1000000000000000000000000000000-5' => [$tenPowThirty, $five, '1000000000000000000000000000005.25', NumberBase::Ten, 10],
164
            'MDecimal 1000000000000000000000000000000-0.00000000001' => [$tenPowThirty, $elevenScale, '1000000000000000000000000000005.25', NumberBase::Ten, 10],
165
            'MDecimal 0.00000000001-1000000000000000000000000000000' => [$elevenScale, $tenPowThirty, '-1000000000000000000000000000005.24999999999', NumberBase::Ten, 11],
166
            'MDecimal -4-0.1' => [$negFour, $oneTenth, '-3.8999999999', NumberBase::Ten, 10],
167
            'MDecimal 5-5i' => [$five, $fiveI, MissingPackage::class, NumberBase::Ten, 10],
168
            'MDecimal 5i-10i' => [$fiveI, $tenI, '-5i', NumberBase::Ten, 10],
169
        ];
170
171
    }
172
173
    public function subtractionImmutableDecimalProvider(): array
174
    {
175
176
        $five = (new ImmutableDecimal(5))->setMode(CalcMode::Precision);
177
        $fiveBaseFive = (new ImmutableDecimal(5, null, NumberBase::Five))->setMode(CalcMode::Precision);
178
        $ten = (new ImmutableDecimal(10))->setMode(CalcMode::Precision);
179
        $oneQuarter = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
180
        $sixTenths = (new ImmutableDecimal('0.6'))->setMode(CalcMode::Precision);
181
        $fourTenths = (new ImmutableDecimal('0.4'))->setMode(CalcMode::Precision);
182
        $oneTenth = (new ImmutableDecimal('0.1'))->setMode(CalcMode::Precision);
183
        $twoTenths = (new ImmutableDecimal('0.2'))->setMode(CalcMode::Precision);
184
        $tenScale = (new ImmutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
185
        $elevenScale = (new ImmutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
186
        $tenPowThirty = (new ImmutableDecimal('1000000000000000000000000000000'))->setMode(CalcMode::Precision);
187
        $negFour = (new ImmutableDecimal('-4'))->setMode(CalcMode::Precision);
188
        $fiveI = (new ImmutableDecimal('5i'))->setMode(CalcMode::Precision);
189
        $tenI = (new ImmutableDecimal('10i'))->setMode(CalcMode::Precision);
190
191
        return [
192
            'IDecimal 5-10' => [$five, $ten, '-5', NumberBase::Ten, 10],
193
            'IDecimal 5-10 base 5' => [$fiveBaseFive, $ten, '-10', NumberBase::Five, 10],
194
            'IDecimal 5-1/4' => [$five, $oneQuarter, '4.75', NumberBase::Ten, 10],
195
            'IDecimal 1/4-5' => [$oneQuarter, $five, '-19/4', NumberBase::Ten, 10],
196
            'IDecimal 0.6-0.4' => [$sixTenths, $fourTenths, '0.2', NumberBase::Ten, 10],
197
            'IDecimal 0.1-0.2' => [$oneTenth, $twoTenths, '-0.1', NumberBase::Ten, 10],
198
            'IDecimal 0.1-0.0000000001' => [$oneTenth, $tenScale, '0.0999999999', NumberBase::Ten, 10],
199
            'IDecimal 0.1-0.00000000001' => [$oneTenth, $elevenScale, '0.1', NumberBase::Ten, 10],
200
            'IDecimal 1000000000000000000000000000000-5' => [$tenPowThirty, $five, '999999999999999999999999999995', NumberBase::Ten, 10],
201
            'IDecimal 1000000000000000000000000000000-0.00000000001' => [$tenPowThirty, $elevenScale, '1000000000000000000000000000000', NumberBase::Ten, 10],
202
            'IDecimal 0.00000000001-1000000000000000000000000000000' => [$elevenScale, $tenPowThirty, '-999999999999999999999999999999.99999999999', NumberBase::Ten, 11],
203
            'IDecimal -4-0.1' => [$negFour, $oneTenth, '-4.1', NumberBase::Ten, 10],
204
            'IDecimal 5-5i' => [$five, $fiveI, MissingPackage::class, NumberBase::Ten, 10],
205
            'IDecimal 5i-10i' => [$fiveI, $tenI, '-5i', NumberBase::Ten, 10],
206
        ];
207
208
    }
209
210
    public function subtractionImmutableFractionProvider(): array
211
    {
212
        $a = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
213
        $b = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(5))->setMode(CalcMode::Precision));
214
        $c = new ImmutableFraction((new ImmutableDecimal(3))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
215
        $d = new ImmutableFraction((new ImmutableDecimal(4))->setMode(CalcMode::Precision), (new ImmutableDecimal(5))->setMode(CalcMode::Precision));
216
        $e = new ImmutableFraction((new ImmutableDecimal(4))->setMode(CalcMode::Precision), (new ImmutableDecimal(8))->setMode(CalcMode::Precision));
217
        $f = new ImmutableFraction((new ImmutableDecimal(3))->setMode(CalcMode::Precision), (new ImmutableDecimal('10000000000000000000000000'))->setMode(CalcMode::Precision));
218
219
        return [
220
            'IFraction 1/4-1/5' =>[$a, $b, '1/20', NumberBase::Ten, 10],
221
            'IFraction 1/4-3/4' =>[$a, $c, '-1/2', NumberBase::Ten, 10],
222
            'IFraction 1/5-4/5' =>[$b, $d, '-3/5', NumberBase::Ten, 10],
223
            'IFraction 1/5-3/4' =>[$b, $c, '-11/20', NumberBase::Ten, 10],
224
            'IFraction 1/4-4/5' =>[$a, $d, '-11/20', NumberBase::Ten, 10],
225
            'IFraction 1/4-4/8' =>[$a, $e, '-1/4', NumberBase::Ten, 10],
226
            'IFraction 4/8-1/4' =>[$e, $a, '1/4', NumberBase::Ten, 10],
227
            'IFraction 1/4-3/10000000000000000000000000' =>[$a, $f, '2499999999999999999999997/10000000000000000000000000', NumberBase::Ten, 10]
228
        ];
229
    }
230
231
    /**
232
     * @dataProvider subtractionImmutableDecimalProvider
233
     * @dataProvider subtractionMutableDecimalProvider
234
     * @dataProvider subtractionImmutableFractionProvider
235
     */
236
    public function testSubtraction(Number $a, Number $b, string $expected, NumberBase $base, int $scale)
237
    {
238
        if (str_contains($expected, 'Exception')) {
239
            $this->expectException($expected);
240
            $a->subtract($b);
241
        } else {
242
            $answer = $a->subtract($b);
243
            $this->assertEquals($expected, $answer->getValue());
244
            $this->assertEquals($base, $answer->getBase());
245
            $this->assertEquals($scale, $answer->getScale());
246
        }
247
    }
248
249
    /*
250
     * MULTIPLICATION
251
     */
252
253
    public function multiplicationImmutableDecimalProvider(): array
254
    {
255
        $a = (new ImmutableDecimal('2'))->setMode(CalcMode::Precision);
256
        $a2 = (new ImmutableDecimal('2', null, NumberBase::Five))->setMode(CalcMode::Precision);
257
        $b = (new ImmutableDecimal('3'))->setMode(CalcMode::Precision);
258
        $c = (new ImmutableDecimal('-2'))->setMode(CalcMode::Precision);
259
        $d = (new ImmutableDecimal('-3'))->setMode(CalcMode::Precision);
260
        $e = (new ImmutableDecimal('0.5'))->setMode(CalcMode::Precision);
261
        $f = (new ImmutableDecimal('-0.5'))->setMode(CalcMode::Precision);
262
        $g = (new ImmutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
263
        $h = (new ImmutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
264
        $i = (new ImmutableDecimal('1000000000000000000000000000000'))->setMode(CalcMode::Precision);
265
        $j = (new ImmutableDecimal('2i'))->setMode(CalcMode::Precision);
266
        $k = (new ImmutableDecimal('3i'))->setMode(CalcMode::Precision);
267
268
        return [
269
            'IDecimal 2*3' => [$a, $b, '6', NumberBase::Ten, 10],
270
            'IDecimal 2*3 base 5' => [$a2, $b, '11', NumberBase::Five, 10],
271
            'IDecimal 2*-2' => [$a, $c, '-4', NumberBase::Ten, 10],
272
            'IDecimal 3*-2' => [$b, $c, '-6', NumberBase::Ten, 10],
273
            'IDecimal -2*-3' => [$c, $d, '6', NumberBase::Ten, 10],
274
            'IDecimal 2*0.5' => [$a, $e, '1', NumberBase::Ten, 10],
275
            'IDecimal 3*0.5' => [$b, $e, '1.5', NumberBase::Ten, 10],
276
            'IDecimal 2*-0.5' => [$a, $f, '-1', NumberBase::Ten, 10],
277
            'IDecimal 3*-0.5' => [$b, $f, '-1.5', NumberBase::Ten, 10],
278
            'IDecimal 2*0.0000000001' => [$a, $g, '0.0000000002', NumberBase::Ten, 10],
279
            'IDecimal 2*0.00000000001' => [$a, $h, '0', NumberBase::Ten, 10],
280
            'IDecimal 2*1000000000000000000000000000000' => [$a, $i, '2000000000000000000000000000000', NumberBase::Ten, 10],
281
            'IDecimal 0.0000000001*1000000000000000000000000000000' => [$g, $i, '100000000000000000000', NumberBase::Ten, 10],
282
            'IDecimal 2*2i' => [$a, $j, '4i', NumberBase::Ten, 10],
283
            'IDecimal 2i*3i' => [$j, $k, '-6', NumberBase::Ten, 10],
284
        ];
285
    }
286
287
    public function multiplicationMutableDecimalProvider(): array
288
    {
289
        $a = (new MutableDecimal('2'))->setMode(CalcMode::Precision);
290
        $a2 = (new MutableDecimal('2', null, NumberBase::Five))->setMode(CalcMode::Precision);
291
        $b = (new MutableDecimal('3'))->setMode(CalcMode::Precision);
292
        $c = (new MutableDecimal('-2'))->setMode(CalcMode::Precision);
293
        $d = (new MutableDecimal('-3'))->setMode(CalcMode::Precision);
294
        $e = (new MutableDecimal('0.5'))->setMode(CalcMode::Precision);
295
        $f = (new MutableDecimal('-0.5'))->setMode(CalcMode::Precision);
296
        $g = (new MutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
297
        $h = (new MutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
298
        $i = (new MutableDecimal('1000000000000000000000000000000'))->setMode(CalcMode::Precision);
299
        $j = (new MutableDecimal('2i'))->setMode(CalcMode::Precision);
300
        $k = (new MutableDecimal('3i'))->setMode(CalcMode::Precision);
301
302
        return [
303
            'MDecimal 2*3' => [$a, $b, '6', NumberBase::Ten, 10],
304
            'MDecimal 2*3 base 5' => [$a2, $b, '11', NumberBase::Five, 10],
305
            'MDecimal 2*-2' => [$a, $c, '-12', NumberBase::Ten, 10],
306
            'MDecimal 3*-2' => [$b, $c, '-6', NumberBase::Ten, 10],
307
            'MDecimal -2*-3' => [$c, $d, '6', NumberBase::Ten, 10],
308
            'MDecimal 2*0.5' => [$a, $e, '-6', NumberBase::Ten, 10],
309
            'MDecimal 3*0.5' => [$b, $e, '-3', NumberBase::Ten, 10],
310
            'MDecimal 2*-0.5' => [$a, $f, '3', NumberBase::Ten, 10],
311
            'MDecimal 3*-0.5' => [$b, $f, '1.5', NumberBase::Ten, 10],
312
            'MDecimal 2*0.0000000001' => [$a, $g, '0.0000000003', NumberBase::Ten, 10],
313
            'MDecimal 2*0.00000000001' => [$a, $h, '0', NumberBase::Ten, 10],
314
            'MDecimal 2*1000000000000000000000000000000' => [$a, $i, '0', NumberBase::Ten, 10],
315
            'MDecimal 0.0000000001*1000000000000000000000000000000' => [$g, $i, '100000000000000000000', NumberBase::Ten, 10],
316
            'MDecimal 2*2i' => [$a, $j, '0i', NumberBase::Ten, 10],
317
            'MDecimal 2i*3i' => [$j, $k, '-6', NumberBase::Ten, 10],
318
        ];
319
    }
320
321
    public function multiplicationImmutableFractionProvider(): array
322
    {
323
        $a = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
324
        $b = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(5))->setMode(CalcMode::Precision));
325
        $c = new ImmutableFraction((new ImmutableDecimal(3))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
326
        $d = new ImmutableFraction((new ImmutableDecimal(4))->setMode(CalcMode::Precision), (new ImmutableDecimal(5))->setMode(CalcMode::Precision));
327
        $e = new ImmutableFraction((new ImmutableDecimal(4))->setMode(CalcMode::Precision), (new ImmutableDecimal(8))->setMode(CalcMode::Precision));
328
        $f = new ImmutableFraction((new ImmutableDecimal(3))->setMode(CalcMode::Precision), (new ImmutableDecimal('10000000000000000000000000'))->setMode(CalcMode::Precision));
329
330
        return [
331
            'IFraction 1/4*1/5' => [$a, $b, '1/20', NumberBase::Ten, 10],
332
            'IFraction 1/4*3/4' => [$a, $c, '3/16', NumberBase::Ten, 10],
333
            'IFraction 1/5*4/5' => [$b, $d, '4/25', NumberBase::Ten, 10],
334
            'IFraction 1/5*3/4' => [$b, $c, '3/20', NumberBase::Ten, 10],
335
            'IFraction 1/4*4/5' => [$a, $d, '1/5', NumberBase::Ten, 10],
336
            'IFraction 1/4*4/8' => [$a, $e, '1/8', NumberBase::Ten, 10],
337
            'IFraction 4/8*1/4' => [$e, $a, '1/8', NumberBase::Ten, 10],
338
            'IFraction 1/4*3/10000000000000000000000000' => [$a, $f, '3/40000000000000000000000000', NumberBase::Ten, 10]
339
        ];
340
    }
341
342
    /**
343
     * @dataProvider multiplicationImmutableDecimalProvider
344
     * @dataProvider multiplicationMutableDecimalProvider
345
     * @dataProvider multiplicationImmutableFractionProvider
346
     */
347
    public function testMultiplication(Number $a, Number $b, string $expected, NumberBase $base, int $scale)
348
    {
349
        $answer = $a->multiply($b);
350
        $this->assertEquals($expected, $answer->getValue());
351
        $this->assertEquals($base, $answer->getBase());
352
        $this->assertEquals($scale, $answer->getScale());
353
    }
354
355
    /*
356
     * DIVISION
357
     */
358
359
    public function divisionImmutableDecimalProvider(): array
360
    {
361
        $a = (new ImmutableDecimal('2'))->setMode(CalcMode::Precision);
362
        $a2 = (new ImmutableDecimal('2', null, NumberBase::Five))->setMode(CalcMode::Precision);
363
        $b = (new ImmutableDecimal('3'))->setMode(CalcMode::Precision);
364
        $c = (new ImmutableDecimal('-2'))->setMode(CalcMode::Precision);
365
        $d = (new ImmutableDecimal('-3'))->setMode(CalcMode::Precision);
366
        $e = (new ImmutableDecimal('0.5'))->setMode(CalcMode::Precision);
367
        $f = (new ImmutableDecimal('-0.5'))->setMode(CalcMode::Precision);
368
        $g = (new ImmutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
369
        $h = (new ImmutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
370
        $i = (new ImmutableDecimal('1000000000000000000000000000000'))->setMode(CalcMode::Precision);
371
        $j = (new ImmutableDecimal('5i'))->setMode(CalcMode::Precision);
372
        $k = (new ImmutableDecimal('10i'))->setMode(CalcMode::Precision);
373
        $l = (new ImmutableDecimal('0'))->setMode(CalcMode::Precision);
374
375
        return [
376
            'IDecimal 2 / 3' => [$a, $b, '0.6666666667', NumberBase::Ten, 10],
377
            'IDecimal 2 / 3 base 5' => [$a2, $b, '0.131313131002111', NumberBase::Five, 10],
378
            'IDecimal 2 / -2' => [$a, $c, '-1', NumberBase::Ten, 10],
379
            'IDecimal 3 / -2' => [$b, $c, '-1.5', NumberBase::Ten, 10],
380
            'IDecimal -2 / -3' => [$c, $d, '0.6666666667', NumberBase::Ten, 10],
381
            'IDecimal 2 / 0.5' => [$a, $e, '4', NumberBase::Ten, 10],
382
            'IDecimal 3 / 0.5' => [$b, $e, '6', NumberBase::Ten, 10],
383
            'IDecimal 2 / -0.5' => [$a, $f, '-4', NumberBase::Ten, 10],
384
            'IDecimal 3 / -0.5' => [$b, $f, '-6', NumberBase::Ten, 10],
385
            'IDecimal 2 / 0.0000000001' => [$a, $g, '20000000000', NumberBase::Ten, 10],
386
            'IDecimal 2 / 0.00000000001' => [$a, $h, '200000000000', NumberBase::Ten, 10],
387
            'IDecimal 2 / 1000000000000000000000000000000' => [$a, $i, '0', NumberBase::Ten, 10],
388
            'IDecimal 1000000000000000000000000000000 / 2' => [$i, $a, '500000000000000000000000000000', NumberBase::Ten, 10],
389
            'IDecimal 0.0000000001 / 1000000000000000000000000000000' => [$g, $i, '0', NumberBase::Ten, 10],
390
            'IDecimal 2 / 5i' => [$a, $j, '-0.4i', NumberBase::Ten, 10],
391
            'IDecimal 5i / 2' => [$j, $a, '2.5i', NumberBase::Ten, 10],
392
            'IDecimal 5i / 10i' => [$j, $k, '0.5', NumberBase::Ten, 10],
393
            'IDecimal 2 / 0' => [$a, $l, IntegrityConstraint::class, NumberBase::Ten, 10]
394
        ];
395
    }
396
397
    public function divisionMutableDecimalProvider(): array
398
    {
399
        $a = (new MutableDecimal('2'))->setMode(CalcMode::Precision);
400
        $a2 = (new MutableDecimal('2', null, NumberBase::Five))->setMode(CalcMode::Precision);
401
        $b = (new MutableDecimal('3'))->setMode(CalcMode::Precision);
402
        $c = (new MutableDecimal('-2'))->setMode(CalcMode::Precision);
403
        $d = (new MutableDecimal('-3'))->setMode(CalcMode::Precision);
404
        $e = (new MutableDecimal('0.5'))->setMode(CalcMode::Precision);
405
        $f = (new MutableDecimal('-0.5'))->setMode(CalcMode::Precision);
406
        $g = (new MutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
407
        $h = (new MutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
408
        $i = (new MutableDecimal('1000000000000000000000000000000'))->setMode(CalcMode::Precision);
409
        $j = (new MutableDecimal('5i'))->setMode(CalcMode::Precision);
410
        $k = (new MutableDecimal('10i'))->setMode(CalcMode::Precision);
411
        $l = (new MutableDecimal('0'))->setMode(CalcMode::Precision);
412
413
414
        return [
415
            'MDecimal 2 / 3' => [$a, $b, '0.6666666667', NumberBase::Ten, 10],
416
            'MDecimal 2 / 3 base 5' => [$a2, $b, '0.131313131002111', NumberBase::Five, 10],
417
            'MDecimal 2 / -2' => [$a, $c, '-0.3333333334', NumberBase::Ten, 10],
418
            'MDecimal 3 / -2' => [$b, $c, '-1.5', NumberBase::Ten, 10],
419
            'MDecimal -2 / -3' => [$c, $d, '0.6666666667', NumberBase::Ten, 10],
420
            'MDecimal 2 / 0.5' => [$a, $e, '-0.6666666668', NumberBase::Ten, 10],
421
            'MDecimal 3 / 0.5' => [$b, $e, '-3', NumberBase::Ten, 10],
422
            'MDecimal 2 / -0.5' => [$a, $f, '1.3333333336', NumberBase::Ten, 10],
423
            'MDecimal 3 / -0.5' => [$b, $f, '6', NumberBase::Ten, 10],
424
            'MDecimal 2 / 0.0000000001' => [$a, $g, '13333333336', NumberBase::Ten, 10],
425
            'MDecimal 2 / 0.00000000001' => [$a, $h, '1333333333600000000000', NumberBase::Ten, 10],
426
            'MDecimal 2 / 1000000000000000000000000000000' => [$a, $i, '0.0000000013', NumberBase::Ten, 10],
427
            'MDecimal 1000000000000000000000000000000 / 2' => [$i, $a, '769230769230769230769230769230769230769.2308', NumberBase::Ten, 10],
428
            'MDecimal 0.0000000001 / 1000000000000000000000000000000' => [$g, $i, '0', NumberBase::Ten, 10],
429
            'MDecimal 2 / 5i' => [$a, $j, '-0.0000000003i', NumberBase::Ten, 10],
430
            'MDecimal 5i / 2' => [$j, $a, '-16666666666.667', NumberBase::Ten, 10],
431
            'MDecimal 5i / 10i' => [$j, $k, '1666666666.6667i', NumberBase::Ten, 10],
432
            'MDecimal 2 / 0' => [$a, $l, IntegrityConstraint::class, NumberBase::Ten, 10]
433
        ];
434
    }
435
436
    public function divisionImmutableFractionProvider(): array
437
    {
438
        $a = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
439
        $b = new ImmutableFraction((new ImmutableDecimal(1))->setMode(CalcMode::Precision), (new ImmutableDecimal(5))->setMode(CalcMode::Precision));
440
        $c = new ImmutableFraction((new ImmutableDecimal(3))->setMode(CalcMode::Precision), (new ImmutableDecimal(4))->setMode(CalcMode::Precision));
441
        $d = new ImmutableFraction((new ImmutableDecimal(4))->setMode(CalcMode::Precision), (new ImmutableDecimal(5))->setMode(CalcMode::Precision));
442
        $e = new ImmutableFraction((new ImmutableDecimal(4))->setMode(CalcMode::Precision), (new ImmutableDecimal(8))->setMode(CalcMode::Precision));
443
        $f = new ImmutableFraction((new ImmutableDecimal(3))->setMode(CalcMode::Precision), (new ImmutableDecimal('10000000000000000000000000'))->setMode(CalcMode::Precision));
444
445
        return [
446
            'IFraction 1/4 / 1/5' => [$a, $b, '5/4', NumberBase::Ten, 10],
447
            'IFraction 1/4 / 3/4' => [$a, $c, '1/3', NumberBase::Ten, 10],
448
            'IFraction 1/5 / 4/5' => [$b, $d, '1/4', NumberBase::Ten, 10],
449
            'IFraction 1/5 / 3/4' => [$b, $c, '4/15', NumberBase::Ten, 10],
450
            'IFraction 1/4 / 4/5' => [$a, $d, '5/16', NumberBase::Ten, 10],
451
            'IFraction 1/4 / 4/8' => [$a, $e, '1/2', NumberBase::Ten, 10],
452
            'IFraction 4/8 / 1/4' => [$e, $a, '2/1', NumberBase::Ten, 10],
453
            'IFraction 1/4 / 3/10000000000000000000000000' => [$a, $f, '2500000000000000000000000/3', NumberBase::Ten, 10]
454
        ];
455
    }
456
457
    /**
458
     * @dataProvider divisionImmutableDecimalProvider
459
     * @dataProvider divisionMutableDecimalProvider
460
     * @dataProvider divisionImmutableFractionProvider
461
     */
462
    public function testDivision(Number $a, Number $b, string $expected, NumberBase $base, int $scale)
463
    {
464
        if (str_contains($expected, 'Exception')) {
465
            $this->expectException($expected);
466
            $a->divide($b);
467
        } else {
468
            $answer = $a->divide($b);
469
            $this->assertEquals($expected, $answer->getValue());
470
            $this->assertEquals($base, $answer->getBase());
471
            $this->assertEquals($scale, $answer->getScale());
472
        }
473
    }
474
475
    /*
476
     * POW
477
     */
478
479
    public function powerImmutableDecimalProvider(): array
480
    {
481
        $a = (new ImmutableDecimal('2'))->setMode(CalcMode::Precision);
482
        $a2 = (new ImmutableDecimal('2', null, NumberBase::Five))->setMode(CalcMode::Precision);
483
        $b = (new ImmutableDecimal('3'))->setMode(CalcMode::Precision);
484
        $c = (new ImmutableDecimal('-2'))->setMode(CalcMode::Precision);
485
        $d = (new ImmutableDecimal('-3'))->setMode(CalcMode::Precision);
486
        $e = (new ImmutableDecimal('0.5'))->setMode(CalcMode::Precision);
487
        $f = (new ImmutableDecimal('-0.5'))->setMode(CalcMode::Precision);
488
        $g = (new ImmutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
489
        $h = (new ImmutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
490
491
492
        return [
493
            'IDecimal 2^3' => [$a, $b, '8', NumberBase::Ten, 10],
494
            'IDecimal 2^3 base 5' => [$a2, $b, '13', NumberBase::Five, 10],
495
            'IDecimal 2^-2' => [$a, $c, '0.25', NumberBase::Ten, 10],
496
            'IDecimal 3^-2' => [$b, $c, '0.1111111111', NumberBase::Ten, 10],
497
            'IDecimal -2^-3' => [$c, $d, '-0.125', NumberBase::Ten, 10],
498
            'IDecimal 2^0.5' => [$a, $e, '1.4142135624', NumberBase::Ten, 10],
499
            'IDecimal -2^0.5' => [$c, $e, MissingPackage::class, NumberBase::Ten, 10],
500
            'IDecimal 3^0.5' => [$b, $e, '1.7320508076', NumberBase::Ten, 10],
501
            'IDecimal 2^-0.5' => [$a, $f, '0.7071067812', NumberBase::Ten, 10],
502
            'IDecimal 3^-0.5' => [$b, $f, '0.5773502692', NumberBase::Ten, 10],
503
            'IDecimal 2^0.0000000001' => [$a, $g, '1.0000000001', NumberBase::Ten, 10],
504
            'IDecimal 2^0.00000000001' => [$a, $h, '1', NumberBase::Ten, 10],
505
        ];
506
    }
507
508
    public function powerMutableDecimalProvider(): array
509
    {
510
        $a = (new MutableDecimal('2'))->setMode(CalcMode::Precision);
511
        $a2 = (new MutableDecimal('2', null, NumberBase::Five))->setMode(CalcMode::Precision);
512
        $b = (new MutableDecimal('3'))->setMode(CalcMode::Precision);
513
        $c = (new MutableDecimal('-2'))->setMode(CalcMode::Precision);
514
        $d = (new MutableDecimal('-3'))->setMode(CalcMode::Precision);
515
        $e = (new MutableDecimal('0.5'))->setMode(CalcMode::Precision);
516
        $f = (new MutableDecimal('-0.5'))->setMode(CalcMode::Precision);
517
        $g = (new MutableDecimal('0.0000000001'))->setMode(CalcMode::Precision);
518
        $h = (new MutableDecimal('0.00000000001'))->setMode(CalcMode::Precision);
519
520
521
        return [
522
            'MDecimal 2^3' => [$a, $b, '8', NumberBase::Ten, 10],
523
            'MDecimal 2^3 base 5' => [$a2, $b, '13', NumberBase::Five, 10],
524
            'MDecimal 2^-2' => [$a, $c, '0.015625', NumberBase::Ten, 10],
525
            'MDecimal 3^-2' => [$b, $c, '0.1111111111', NumberBase::Ten, 10],
526
            'MDecimal -2^-3' => [$c, $d, '-0.125', NumberBase::Ten, 10],
527
            'MDecimal 2^0.5' => [$a, $e, '0.125', NumberBase::Ten, 10],
528
            'MDecimal -2^0.5' => [$c, $e, MissingPackage::class, NumberBase::Ten, 10],
529
            'MDecimal 3^0.5' => [$b, $e, '0.3333333333', NumberBase::Ten, 10],
530
            'MDecimal 2^-0.5' => [$a, $f, '2.8284271247', NumberBase::Ten, 10],
531
            'MDecimal 3^-0.5' => [$b, $f, '1.7320508076', NumberBase::Ten, 10],
532
            'MDecimal 2^0.0000000001' => [$a, $g, '1.0000000001', NumberBase::Ten, 10],
533
            'MDecimal 2^0.00000000001' => [$a, $h, '1', NumberBase::Ten, 10],
534
        ];
535
    }
536
537
    /**
538
     * @dataProvider powerImmutableDecimalProvider
539
     * @dataProvider powerMutableDecimalProvider
540
     */
541
    public function testPower(Number $a, Number $b, string $expected, NumberBase $base, int $scale)
542
    {
543
        if (str_contains($expected, 'Exception')) {
544
            $this->expectException($expected);
545
            $a->pow($b);
546
        } else {
547
            $answer = $a->pow($b);
548
            $this->assertEquals($expected, $answer->getValue());
549
            $this->assertEquals($base, $answer->getBase());
550
            $this->assertEquals($scale, $answer->getScale());
551
        }
552
    }
553
554
}