Completed
Push — master ( b9f967...7a222d )
by Andreu
9s
created

InfiniteDecimal::getPositiveInfinite()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
crap 2
1
<?php
2
3
namespace Litipk\BigNumbers;
4
5
use Litipk\BigNumbers\Decimal as Decimal;
6
use Litipk\BigNumbers\DecimalConstants as DecimalConstants;
7
use Litipk\Exceptions\InvalidCastException;
8
use Litipk\Exceptions\NotImplementedException;
9
10
/**
11
 * Immutable object that represents an infinite number
12
 *
13
 * @author Andreu Correa Casablanca <[email protected]>
14
 */
15
class InfiniteDecimal extends Decimal
16
{
17
	/**
18
     * Single instance of "Positive Infinite"
19
     * @var Decimal
20
     */
21
    private static $pInf = null;
22
23
    /**
24
     * Single instance of "Negative Infinite"
25
     * @var Decimal
26
     */
27
    private static $nInf = null;
28
29
    /**
30
     * Private constructor
31
     * @param string $value
32
     */
33 2
    private function __construct($value)
0 ignored issues
show
Bug introduced by
Consider using a different method name as you override a private method of the parent class.

Overwriting private methods is generally fine as long as you also use private visibility. It might still be preferable for understandability to use a different method name.

Loading history...
34
    {
35 2
        $this->value = $value;
36 2
    }
37
38
    /**
39
     * Private clone method
40
     */
41
    private function __clone()
0 ignored issues
show
Bug introduced by
Consider using a different method name as you override a private method of the parent class.

Overwriting private methods is generally fine as long as you also use private visibility. It might still be preferable for understandability to use a different method name.

Loading history...
42
    {
43
44
    }
45
46
    /**
47
     * Returns a "Positive Infinite" object
48
     * @return Decimal
49
     */
50 73
    public static function getPositiveInfinite()
51
    {
52 73
        if (self::$pInf === null) {
53 1
            self::$pInf = new InfiniteDecimal('INF');
54 1
        }
55
56 73
        return self::$pInf;
57
    }
58
59
    /**
60
     * Returns a "Negative Infinite" object
61
     * @return Decimal
62
     */
63 42
    public static function getNegativeInfinite()
64
    {
65 42
        if (self::$nInf === null) {
66 1
            self::$nInf = new InfiniteDecimal('-INF');
67 1
        }
68
69 42
        return self::$nInf;
70
    }
71
72
    /**
73
     * Adds two Decimal objects
74
     * @param  Decimal $b
75
     * @param  integer $scale
76
     * @return Decimal
77
     */
78 2
    public function add(Decimal $b, $scale = null)
79
    {
80 2
    	self::paramsValidation($b, $scale);
81
82 2
    	if (!$b->isInfinite()) {
83 1
            return $this;
84 1
        } elseif ($this->hasSameSign($b)) {
85 1
            return $this;
86
        } else { // elseif ($this->isPositive() && $b->isNegative || $this->isNegative() && $b->isPositive()) {
87 1
            throw new \DomainException("Infinite numbers with opposite signs can't be added.");
88
        }
89
    }
90
91
    /**
92
     * Subtracts two BigNumber objects
93
     * @param  Decimal $b
94
     * @param  integer $scale
95
     * @return Decimal
96
     */
97 2
    public function sub(Decimal $b, $scale = null)
98
    {
99 2
    	self::paramsValidation($b, $scale);
100
101 2
    	if (!$b->isInfinite()) {
102 1
            return $this;
103 1
        } elseif (!$this->hasSameSign($b)) {
104 1
            return $this;
105
        } else { // elseif () {
106 1
            throw new \DomainException("Infinite numbers with the same sign can't be subtracted.");
107
        }
108
    }
109
110
    /**
111
     * Multiplies two BigNumber objects
112
     * @param  Decimal $b
113
     * @param  integer $scale
114
     * @return Decimal
115
     */
116 5
    public function mul(Decimal $b, $scale = null)
117
    {
118 5
    	self::paramsValidation($b, $scale);
119
120 5
    	if ($b->isZero()) {
121 4
            throw new \DomainException("Zero multiplied by infinite is not allowed.");
122
        }
123
124 1
        if ($this->hasSameSign($b)) {
125 1
            return self::getPositiveInfinite();
126
        } else { // elseif (!$this->hasSameSign($b)) {
127 1
            return self::getNegativeInfinite();
128
        }
129
    }
130
131
    /**
132
     * Divides the object by $b .
133
     * Warning: div with $scale == 0 is not the same as
134
     *          integer division because it rounds the
135
     *          last digit in order to minimize the error.
136
     *
137
     * @param  Decimal $b
138
     * @param  integer $scale
139
     * @return Decimal
140
     */
141 3
    public function div(Decimal $b, $scale = null)
142
    {
143 3
    	self::paramsValidation($b, $scale);
144
145 3
    	if ($b->isZero()) {
146 1
            throw new \DomainException("Division by zero is not allowed.");
147 2
        } elseif ($b->isInfinite()) {
148 1
            throw new \DomainException("Infinite divided by Infinite is not allowed.");
149 1
        } elseif ($b->isPositive()) {
150 1
            return $this;
151
        } else { //if ($b->isNegative()) {
152 1
            return $this->additiveInverse();
153
        }
154
    }
155
156
    /**
157
     * Returns the square root of this object
158
     * @param  integer $scale
159
     * @return Decimal
160
     */
161 2
    public function sqrt($scale = null)
162
    {
163 2
        if ($this->isNegative()) {
164 1
            throw new \DomainException(
165
                "Decimal can't handle square roots of negative numbers (it's only for real numbers)."
166 1
            );
167
        }
168
169 1
        return $this;
170
    }
171
172
    /**
173
     * Powers this value to $b
174
     *
175
     * @param  Decimal  $b      exponent
176
     * @param  integer  $scale
177
     * @return Decimal
178
     */
179 7
    public function pow(Decimal $b, $scale = null)
180
    {
181 7
        if ($b->isPositive()) {
182 3
            if ($this->isPositive()) {
183 1
                return $this;
184
            }
185
186
            // if ($this->isNegative())
187 2
            if ($b->isInfinite()) {
188 1
                throw new \DomainException("Negative infinite elevated to infinite is undefined.");
189
            }
190
191 1
            if ($b->isInteger()) {
192 1
                if (preg_match('/^[+\-]?[0-9]*[02468](\.0+)?$/', $b->value, $captures) === 1) {
193
                    // $b is an even number
194 1
                    return self::$pInf;
195
                } else {
196
                    // $b is an odd number
197 1
                    return $this; // Negative Infinite
198
                }
199
            }
200
201
            throw new NotImplementedException("See issues #21, #22, #23 and #24 on Github.");
202
203 4
        } else if ($b->isNegative()) {
204 2
            return DecimalConstants::Zero();
205 2
        } else if ($b->isZero()) {
206 2
            throw new \DomainException("Infinite elevated to zero is undefined.");
207
        }
208
    }
209
210
    /**
211
     * Returns the object's logarithm in base 10
212
     * @param  integer $scale
213
     * @return Decimal
214
     */
215 2
    public function log10($scale = null)
216
    {
217 2
        if ($this->isNegative()) {
218 1
            throw new \DomainException(
219
                "Decimal can't handle logarithms of negative numbers (it's only for real numbers)."
220 1
            );
221
        }
222
223 1
        return $this;
224
    }
225
226
    /**
227
     * Equality comparison between this object and $b
228
     * @param  Decimal $b
229
     * @param integer $scale
230
     * @return boolean
231
     */
232 19
    public function equals(Decimal $b, $scale = null)
233
    {
234 19
    	return ($this === $b);
235
    }
236
237
    /**
238
     * $this > $b : returns 1 , $this < $b : returns -1 , $this == $b : returns 0
239
     *
240
     * @param  Decimal $b
241
     * @param  integer $scale
242
     * @return integer
243
     */
244 2
    public function comp(Decimal $b, $scale = null)
245
    {
246 2
        self::paramsValidation($b, $scale);
247
248 2
        if ($this === $b) {
249 1
            return 0;
250 2
        } elseif ($this === self::getPositiveInfinite()) {
251 2
            return 1;
252
        } else { // if ($this === self::getNegativeInfinite()) {
253 2
            return -1;
254
        }
255
    }
256
257
    /**
258
     * Returns the element's additive inverse.
259
     * @return Decimal
260
     */
261 4
    public function additiveInverse()
262
    {
263 4
        if ($this === self::getPositiveInfinite()) {
264 3
            return self::$nInf;
265
        } else { // if ($this === self::getNegativeInfinite()) {
266 4
            return self::$pInf;
267
        }
268
    }
269
270
    /**
271
     * "Rounds" the Decimal to have at most $scale digits after the point
272
     * @param  integer $scale
273
     * @return Decimal
274
     */
275 1
    public function round($scale = 0)
276
    {
277 1
    	return $this;
278
    }
279
280
    /**
281
     * "Ceils" the Decimal to have at most $scale digits after the point
282
     * @param  integer $scale
283
     * @return Decimal
284
     */
285 1
    public function ceil($scale = 0)
286
    {
287 1
    	return $this;
288
    }
289
290
    /**
291
     * "Floors" the Decimal to have at most $scale digits after the point
292
     * @param  integer $scale
293
     * @return Decimal
294
     */
295 33
    public function floor($scale = 0)
296
    {
297 33
    	return $this;
298
    }
299
300
    /**
301
     * Throws exception because sine is undefined in the infinite.
302
     *
303
     * @param integer $scale
304
     * @return null
305
     */
306 2
    public function sin($scale = null)
307
    {
308 2
        throw new \DomainException(($this === self::$pInf) ?
309 2
            "Sine function hasn't limit in the positive infinite." :
310
            "Sine function hasn't limit in the negative infinite."
311 2
        );
312
    }
313
314
    /**
315
     * Throws exception because cosecant is undefined in the infinite.
316
     *
317
     * @param integer $scale
318
     * @return null
319
     */
320 2
    public function cosec($scale = null)
321
    {
322 2
        throw new \DomainException(($this === self::$pInf) ?
323 2
            "Cosecant function hasn't limit in the positive infinite." :
324
            "Cosecant function hasn't limit in the negative infinite."
325 2
        );
326
    }
327
328
    /**
329
     * Throws exception because cosine is undefined in the infinite.
330
     *
331
     * @param integer $scale
332
     * @return null
333
     */
334 2
    public function cos($scale = null)
335
    {
336 2
        throw new \DomainException(($this === self::$pInf) ?
337 2
            "Cosine function hasn't limit in the positive infinite." :
338
            "Cosine function hasn't limit in the negative infinite."
339 2
        );
340
    }
341
342
    /**
343
     * Throws exception because secant is undefined in the infinite.
344
     *
345
     * @param integer $scale
346
     * @return null
347
     */
348 2
    public function sec($scale = null)
349
    {
350 2
        throw new \DomainException(($this === self::$pInf) ?
351 2
            "Secant function hasn't limit in the positive infinite." :
352
            "Secant function hasn't limit in the negative infinite."
353 2
        );
354
    }
355
356
    /**
357
     * Returns exp($this), said in other words: e^$this .
358
     *
359
     * @param integer $scale
360
     * @return Decimal
361
     */
362 2
    public function exp($scale = null)
363
    {
364 2
        if ($this == self::$pInf) {
365 1
            return $this;
366
        } else {
367 1
            return DecimalConstants::zero();
368
        }
369
    }
370
371 2
    public function tan($scale = null)
372
    {
373 2
        throw new \DomainException(($this === self::$pInf) ?
374 2
            "Tangent function hasn't limit in the positive infinite." :
375
            "Tangent function hasn't limit in the negative infinite."
376 2
        );
377
    }
378
379 2
    public function cotan($scale = null)
380
    {
381 2
        throw new \DomainException(($this === self::$pInf) ?
382 2
            "Cotangent function hasn't limit in the positive infinite." :
383
            "Cotangent function hasn't limit in the negative infinite."
384 2
        );
385
    }
386
387
    /**
388
     * @param  integer $scale Has no effect, exists only for compatibility.
389
     * @return boolean
390
     */
391 36
    public function isZero($scale = null)
392
    {
393 36
    	return false;
394
    }
395
396
    /**
397
     * @return boolean
398
     */
399 11
    public function isPositive()
400
    {
401 11
        return ($this === self::$pInf);
402
    }
403
404
    /**
405
     * @return boolean
406
     */
407 12
    public function isNegative()
408
    {
409 12
        return ($this === self::$nInf);
410
    }
411
412
    /**
413
     * @return boolean
414
     */
415
    public function isInteger()
416
    {
417
        return false;
418
    }
419
420
    /**
421
     * @return boolean
422
     */
423 13
    public function isInfinite()
424
    {
425 13
        return true;
426
    }
427
428
    /**
429
     * Return value as a float
430
     *
431
     * @return float
432
     */
433 1
    public function asFloat()
434
    {
435 1
        return ($this === self::$pInf) ? INF : -INF;
436
    }
437
438
    /**
439
     * Return value as a integer
440
     *
441
     * @return float
442
     */
443 1
    public function asInteger()
444
    {
445 1
        throw new InvalidCastException("InfiniteDecimal", "int", "PHP integers can't represent infinite values.");
446
    }
447
}
448