@@ -848,6 +848,35 @@ public function arccos($scale = null)
848
848
)->round ($ scale );
849
849
}
850
850
851
+ /**
852
+ * Calculates the arctangente of this with the highest possible accuracy
853
+ *
854
+ * @param integer $scale
855
+ * @return Decimal
856
+ */
857
+ public function arctan ($ scale = null )
858
+ {
859
+ $ piOverFour = DecimalConstants::pi ()->div (Decimal::fromInteger (4 ), $ scale + 2 )->round ($ scale );
860
+
861
+ if ($ this ->round ($ scale )->isZero ()) {
862
+ return DecimalConstants::zero ();
863
+ }
864
+ if ($ this ->round ($ scale )->equals (DecimalConstants::one ())) {
865
+ return $ piOverFour ;
866
+ }
867
+ if ($ this ->round ($ scale )->equals (DecimalConstants::negativeOne ())) {
868
+ return DecimalConstants::negativeOne ()->mul ($ piOverFour );
869
+ }
870
+
871
+ $ scale = ($ scale === null ) ? 32 : $ scale ;
872
+
873
+ return self ::simplePowerSerie (
874
+ $ this ,
875
+ DecimalConstants::zero (),
876
+ $ scale
877
+ )->round ($ scale );
878
+ }
879
+
851
880
/**
852
881
* Returns exp($this), said in other words: e^$this .
853
882
*
@@ -905,7 +934,7 @@ private static function factorialSerie (Decimal $x, Decimal $firstTerm, callable
905
934
906
935
907
936
/**
908
- * Internal method used to compute arcsine *
937
+ * Internal method used to compute arcsine and arcosine
909
938
*
910
939
* @param Decimal $x
911
940
* @param Decimal $firstTerm
@@ -953,6 +982,44 @@ private static function powerSerie (Decimal $x, Decimal $firstTerm, $scale)
953
982
return $ approx ->round ($ scale );
954
983
}
955
984
985
+ /**
986
+ * Internal method used to compute arctan and arccotan
987
+ *
988
+ * @param Decimal $x
989
+ * @param Decimal $firstTerm
990
+ * @param $scale
991
+ * @return Decimal
992
+ */
993
+ private static function simplePowerSerie (Decimal $ x , Decimal $ firstTerm , $ scale )
994
+ {
995
+ $ approx = $ firstTerm ;
996
+ $ change = InfiniteDecimal::getPositiveInfinite ();
997
+
998
+ $ xPowerN = DecimalConstants::One (); // Calculates x^n
999
+ $ sign = DecimalConstants::One (); // Calculates a_n
1000
+
1001
+ for ($ i = 1 ; !$ change ->floor ($ scale + 2 )->isZero (); $ i ++) {
1002
+ $ xPowerN = $ xPowerN ->mul ($ x );
1003
+
1004
+ if ($ i % 2 === 0 ) {
1005
+ $ factorN = DecimalConstants::zero ();
1006
+ } else {
1007
+ if ($ i % 4 === 1 ) {
1008
+ $ factorN = DecimalConstants::one ()->div (Decimal::fromInteger ($ i ), $ scale + 2 );
1009
+ } else {
1010
+ $ factorN = DecimalConstants::negativeOne ()->div (Decimal::fromInteger ($ i ), $ scale + 2 );
1011
+ }
1012
+ }
1013
+
1014
+ if (!$ factorN ->isZero ()) {
1015
+ $ change = $ factorN ->mul ($ xPowerN , $ scale + 2 );
1016
+ $ approx = $ approx ->add ($ change , $ scale + 2 );
1017
+ }
1018
+ }
1019
+
1020
+ return $ approx ->round ($ scale );
1021
+ }
1022
+
956
1023
/**
957
1024
* Calculates the tangent of this method with the highest possible accuracy
958
1025
* Note that accuracy is limited by the accuracy of predefined PI;
0 commit comments