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

Commit

Permalink
Merge 8ca594e into 91cf80a
Browse files Browse the repository at this point in the history
  • Loading branch information
codisart committed Oct 15, 2015
2 parents 91cf80a + 8ca594e commit fa436a8
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
81 changes: 81 additions & 0 deletions src/Decimal.php
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,38 @@ public function sec($scale = null)
return DecimalConstants::one()->div($cos)->round($scale);
}

/**
* Calculates the arcsine of this with the highest possible accuracy
*
* @param integer $scale [description]
* @return Decimal
*/
public function arcsin($scale = null)
{
if($this->comp(DecimalConstants::one(), $scale + 2) === 1 || $this->comp(DecimalConstants::negativeOne(), $scale + 2) === -1) {
throw new \DomainException(
"The arcsin of this number is undefined."
);
}

if ($this->round($scale)->isZero()) {
return DecimalConstants::zero;
}
if ($this->round($scale)->equals(DecimalConstants::one())) {
return DecimalConstants::pi()->div(Decimal::fromInteger(2))->round($scale);
}
if ($this->round($scale)->equals(DecimalConstants::negativeOne())) {
return DecimalConstants::pi()->div(Decimal::fromInteger(-2))->round($scale);
}

$scale = ($scale === null) ? 32 : $scale;

return self::powerSerie(
$this,
DecimalConstants::zero(),
$scale
);
}
/**
* Returns exp($this), said in other words: e^$this .
*
Expand Down Expand Up @@ -834,6 +865,56 @@ private static function factorialSerie (Decimal $x, Decimal $firstTerm, callable
return $approx->round($scale);
}


/**
* Internal method used to compute arcsine *
*
* @param Decimal $x
* @param Decimal $firstTerm
* @param $scale
* @return Decimal
*/
private static function powerSerie (Decimal $x, Decimal $firstTerm, $scale)
{
$approx = $firstTerm;
$change = InfiniteDecimal::getPositiveInfinite();

$xPowerN = DecimalConstants::One(); // Calculates x^n
$factorN = DecimalConstants::One(); // Calculates a_n

$numerator = DecimalConstants::one();
$denominator = DecimalConstants::one();

for ($i = 1; !$change->floor($scale + 2)->isZero(); $i++) {
$xPowerN = $xPowerN->mul($x);

if ($i % 2 == 0) {
$factorN = DecimalConstants::zero();
} elseif ($i == 1) {
$factorN = DecimalConstants::one();
} else {
$incrementNum = Decimal::fromInteger($i - 2);
$numerator = $numerator->mul($incrementNum, $scale +2);

$incrementDen = Decimal::fromInteger($i - 1);
$increment = Decimal::fromInteger($i);
$denominator = $denominator
->div($incrementNum, $scale +2)
->mul($incrementDen, $scale +2)
->mul($increment, $scale +2);

$factorN = $numerator->div($denominator, $scale + 2);
}

if (!$factorN->isZero()) {
$change = $factorN->mul($xPowerN, $scale + 2);
$approx = $approx->add($change, $scale + 2);
}
}

return $approx->round($scale);
}

/**
* Calculates the tangent of this method with the highest possible accuracy
* Note that accuracy is limited by the accuracy of predefined PI;
Expand Down
50 changes: 50 additions & 0 deletions tests/Decimal/DecimalArcsinTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

use Litipk\BigNumbers\Decimal as Decimal;

/**
* @group arcsin
*/
class DecimalArcsinTest extends PHPUnit_Framework_TestCase
{
public function arcsinProvider() {
// Some values providede by wolframalpha
return [
['0.154', '0.15461530016096', 14],
['1', '1.57079632679489662', 17],
['-1', '-1.57079632679489662', 17],
];
}

/**
* @dataProvider arcsinProvider
*/
public function testSimple($nr, $answer, $digits)
{
$x = Decimal::fromString($nr);
$arcsinX = $x->arcsin($digits);

$this->assertTrue(
Decimal::fromString($answer)->equals($arcsinX),
"The answer must be " . $answer . ", but was " . $arcsinX
);
}

/**
* @expectedException \DomainException
* @expectedExceptionMessage The arcsin of this number is undefined.
*/
public function testArcsinGreaterThanOne()
{
Decimal::fromString('25.546')->arcsin();
}

/**
* @expectedException \DomainException
* @expectedExceptionMessage The arcsin of this number is undefined.
*/
public function testArcsinFewerThanNegativeOne()
{
Decimal::fromString('-304.75')->arcsin();
}
}

0 comments on commit fa436a8

Please sign in to comment.