@@ -778,7 +778,38 @@ public function sec($scale = null)
778
778
return DecimalConstants::one ()->div ($ cos )->round ($ scale );
779
779
}
780
780
781
+ /**
782
+ * Calculates the arcsine of this with the highest possible accuracy
783
+ *
784
+ * @param integer $scale [description]
785
+ * @return Decimal
786
+ */
787
+ public function arcsin ($ scale = null )
788
+ {
789
+ if ($ this ->comp (DecimalConstants::one (), $ scale + 2 ) === 1 || $ this ->comp (DecimalConstants::negativeOne (), $ scale + 2 ) === -1 ) {
790
+ throw new \DomainException (
791
+ "The arcsin of this number is undefined. "
792
+ );
793
+ }
794
+
795
+ if ($ this ->round ($ scale )->isZero ()) {
796
+ return DecimalConstants::zero;
797
+ }
798
+ if ($ this ->round ($ scale )->equals (DecimalConstants::one ())) {
799
+ return DecimalConstants::pi ()->div (Decimal::fromInteger (2 ))->round ($ scale );
800
+ }
801
+ if ($ this ->round ($ scale )->equals (DecimalConstants::negativeOne ())) {
802
+ return DecimalConstants::pi ()->div (Decimal::fromInteger (-2 ))->round ($ scale );
803
+ }
781
804
805
+ $ scale = ($ scale === null ) ? 32 : $ scale ;
806
+
807
+ return self ::powerSerie (
808
+ $ this ,
809
+ DecimalConstants::zero (),
810
+ $ scale
811
+ );
812
+ }
782
813
/**
783
814
* Returns exp($this), said in other words: e^$this .
784
815
*
@@ -834,6 +865,56 @@ private static function factorialSerie (Decimal $x, Decimal $firstTerm, callable
834
865
return $ approx ->round ($ scale );
835
866
}
836
867
868
+
869
+ /**
870
+ * Internal method used to compute arcsine *
871
+ *
872
+ * @param Decimal $x
873
+ * @param Decimal $firstTerm
874
+ * @param $scale
875
+ * @return Decimal
876
+ */
877
+ private static function powerSerie (Decimal $ x , Decimal $ firstTerm , $ scale )
878
+ {
879
+ $ approx = $ firstTerm ;
880
+ $ change = InfiniteDecimal::getPositiveInfinite ();
881
+
882
+ $ xPowerN = DecimalConstants::One (); // Calculates x^n
883
+ $ factorN = DecimalConstants::One (); // Calculates a_n
884
+
885
+ $ numerator = DecimalConstants::one ();
886
+ $ denominator = DecimalConstants::one ();
887
+
888
+ for ($ i = 1 ; !$ change ->floor ($ scale + 2 )->isZero (); $ i ++) {
889
+ $ xPowerN = $ xPowerN ->mul ($ x );
890
+
891
+ if ($ i % 2 == 0 ) {
892
+ $ factorN = DecimalConstants::zero ();
893
+ } elseif ($ i == 1 ) {
894
+ $ factorN = DecimalConstants::one ();
895
+ } else {
896
+ $ incrementNum = Decimal::fromInteger ($ i - 2 );
897
+ $ numerator = $ numerator ->mul ($ incrementNum , $ scale +2 );
898
+
899
+ $ incrementDen = Decimal::fromInteger ($ i - 1 );
900
+ $ increment = Decimal::fromInteger ($ i );
901
+ $ denominator = $ denominator
902
+ ->div ($ incrementNum , $ scale +2 )
903
+ ->mul ($ incrementDen , $ scale +2 )
904
+ ->mul ($ increment , $ scale +2 );
905
+
906
+ $ factorN = $ numerator ->div ($ denominator , $ scale + 2 );
907
+ }
908
+
909
+ if (!$ factorN ->isZero ()) {
910
+ $ change = $ factorN ->mul ($ xPowerN , $ scale + 2 );
911
+ $ approx = $ approx ->add ($ change , $ scale + 2 );
912
+ }
913
+ }
914
+
915
+ return $ approx ->round ($ scale );
916
+ }
917
+
837
918
/**
838
919
* Calculates the tangent of this method with the highest possible accuracy
839
920
* Note that accuracy is limited by the accuracy of predefined PI;
0 commit comments