Skip to content
This repository was archived by the owner on Dec 27, 2023. It is now read-only.

Commit 5a3247c

Browse files
committed
Fixes to the pow method
1 parent db61975 commit 5a3247c

File tree

4 files changed

+84
-10
lines changed

4 files changed

+84
-10
lines changed

src/Decimal.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,13 @@ public function div(Decimal $b, $scale = null)
328328
self::innerLog10($this_abs->value, $this_abs->scale, 1) -
329329
self::innerLog10($b_abs->value, $b_abs->scale, 1);
330330

331-
$divscale = max(
331+
$divscale = (int)max(
332332
$this->scale + $b->scale,
333333
max(
334334
self::countSignificativeDigits($this, $this_abs),
335335
self::countSignificativeDigits($b, $b_abs)
336336
) - max(ceil($log10_result), 0),
337-
ceil(-$log10_result)
337+
ceil(-$log10_result) + 1
338338
);
339339
}
340340

@@ -386,6 +386,10 @@ public function pow(Decimal $b, $scale = null)
386386
}
387387
} elseif ($b->isZero()) {
388388
return DecimalConstants::One();
389+
} else if ($b->isNegative()) {
390+
return DecimalConstants::One()->div(
391+
$this->pow($b->additiveInverse()), $scale
392+
);
389393
} elseif ($b->scale == 0) {
390394
$pow_scale = $scale === null ?
391395
max($this->scale, $b->scale) : max($this->scale, $b->scale, $scale);
@@ -415,6 +419,16 @@ public function pow(Decimal $b, $scale = null)
415419
$pow_scale
416420
);
417421
} else { // elseif ($this->isNegative())
422+
if ($b->isInteger()) {
423+
if (preg_match('/^[+\-]?[0-9]*[02468](\.0+)?$/', $b->value, $captures) === 1) {
424+
// $b is an even number
425+
return $this->additiveInverse()->pow($b, $scale);
426+
} else {
427+
// $b is an odd number
428+
return $this->additiveInverse()->pow($b, $scale)->additiveInverse();
429+
}
430+
}
431+
418432
throw new NotImplementedException(
419433
"Usually negative numbers can't be powered to non integer numbers. " .
420434
"The cases where is possible are not implemented."

src/InfiniteDecimal.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,14 @@ public function isNegative()
336336
return ($this === self::$nInf);
337337
}
338338

339+
/**
340+
* @return boolean
341+
*/
342+
public function isInteger()
343+
{
344+
return false;
345+
}
346+
339347
/**
340348
* @return boolean
341349
*/

tests/Decimal/DecimalLog10Test.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,7 @@ public function testLittleNumbersLog10()
4646

4747
public function testMediumNumbersLog10()
4848
{
49-
$seventyfive = Decimal::fromInteger(75);
50-
$fortynine = Decimal::fromInteger(49);
51-
52-
$this->assertTrue($seventyfive->log10(5)->equals(Decimal::fromString('1.87506')));
53-
$this->assertTrue($fortynine->log10(7)->equals(Decimal::fromString('1.6901961')));
49+
$this->assertTrue(Decimal::fromInteger(75)->log10(5)->equals(Decimal::fromString('1.87506')));
50+
$this->assertTrue(Decimal::fromInteger(49)->log10(7)->equals(Decimal::fromString('1.6901961')));
5451
}
5552
}

tests/Decimal/DecimalPowTest.php

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22

33
use Litipk\BigNumbers\Decimal as Decimal;
4+
use Litipk\BigNumbers\DecimalConstants as DecimalConstants;
45
use Litipk\Exceptions\NotImplementedException as NotImplementedException;
56

67

@@ -17,9 +18,12 @@ public function testZeroPositive()
1718
$this->assertTrue($zero->pow($two)->isZero());
1819
}
1920

21+
/**
22+
* TODO : Split tests, change idiom to take exception message into account.
23+
*/
2024
public function testZeroNoPositive()
2125
{
22-
$zero = Decimal::fromInteger(0);
26+
$zero = DecimalConstants::Zero();
2327
$nTwo = Decimal::fromInteger(-2);
2428

2529
$catched = false;
@@ -41,8 +45,8 @@ public function testZeroNoPositive()
4145

4246
public function testNoZeroZero()
4347
{
44-
$zero = Decimal::fromInteger(0);
45-
$one = Decimal::fromInteger(1);
48+
$zero = DecimalConstants::Zero();
49+
$one = DecimalConstants::One();
4650

4751
$nTwo = Decimal::fromInteger(-2);
4852
$pTwo = Decimal::fromInteger(2);
@@ -87,6 +91,9 @@ public function testBigPositiveSquareRoot()
8791
$this->assertTrue($bignum1->pow($half, 6)->equals($bignum1->sqrt(6)));
8892
}
8993

94+
/**
95+
* TODO : Incorrect test! (The exception type should be changed, and the "idiom"!)
96+
*/
9097
public function testNegativeSquareRoot()
9198
{
9299
$half = Decimal::fromString('0.5');
@@ -100,4 +107,52 @@ public function testNegativeSquareRoot()
100107
}
101108
$this->assertTrue($catched);
102109
}
110+
111+
public function testPositiveWithNegativeExponent()
112+
{
113+
$pFive = Decimal::fromInteger(5);
114+
115+
$this->assertTrue(
116+
$pFive->pow(Decimal::fromInteger(-1))->equals(Decimal::fromString("0.2")),
117+
"The answer must be 0.2, but was " . $pFive->pow(Decimal::fromInteger(-1))
118+
);
119+
$this->assertTrue(
120+
$pFive->pow(Decimal::fromInteger(-2))->equals(Decimal::fromString("0.04")),
121+
"The answer must be 0.04, but was " . $pFive->pow(Decimal::fromInteger(-2))
122+
);
123+
$this->assertTrue(
124+
$pFive->pow(Decimal::fromInteger(-3))->equals(Decimal::fromString("0.008")),
125+
"The answer must be 0.008, but was " . $pFive->pow(Decimal::fromInteger(-3))
126+
);
127+
$this->assertTrue(
128+
$pFive->pow(Decimal::fromInteger(-4))->equals(Decimal::fromString("0.0016")),
129+
"The answer must be 0.0016, but was " . $pFive->pow(Decimal::fromInteger(-4))
130+
);
131+
132+
$this->assertTrue(
133+
$pFive->pow(Decimal::fromFloat(-4.5))->equals(Decimal::fromString("0.00071554")),
134+
"The answer must be 0.00071554, but was " . $pFive->pow(Decimal::fromFloat(-4.5))
135+
);
136+
}
137+
138+
public function testNegativeWithPositiveExponent()
139+
{
140+
$nFive = Decimal::fromInteger(-5);
141+
142+
$this->assertTrue($nFive->pow(DecimalConstants::One())->equals($nFive));
143+
$this->assertTrue($nFive->pow(Decimal::fromInteger(2))->equals(Decimal::fromInteger(25)));
144+
$this->assertTrue($nFive->pow(Decimal::fromInteger(3))->equals(Decimal::fromInteger(-125)));
145+
}
146+
147+
public function testNegativeWithNegativeExponent()
148+
{
149+
$nFive = Decimal::fromInteger(-5);
150+
151+
$this->assertTrue(
152+
$nFive->pow(Decimal::fromInteger(-1))->equals(Decimal::fromString("-0.2")),
153+
"The answer must be -0.2, but was " . $nFive->pow(Decimal::fromInteger(-1))
154+
);
155+
$this->assertTrue($nFive->pow(Decimal::fromInteger(-2))->equals(Decimal::fromString("0.04")));
156+
$this->assertTrue($nFive->pow(Decimal::fromInteger(-3))->equals(Decimal::fromString("-0.008")));
157+
}
103158
}

0 commit comments

Comments
 (0)