static public BigDecimal tan ( final BigDecimal x ) { if ( x . compareTo ( BigDecimal . ZERO ) == 0 ) { return BigDecimal . ZERO ; } else if ( x . compareTo ( BigDecimal . ZERO ) < 0 ) { return tan ( x . negate ( ) ) . negate ( ) ; } else { /* reduce modulo pi */ BigDecimal res = modpi ( x ) ; /* absolute error in the result is err(x)/cos^2(x) to lowest order */ final double xDbl = res . doubleValue ( ) ; final double xUlpDbl = x . ulp ( ) . doubleValue ( ) / 2. ; final double eps = xUlpDbl / 2. / Math . pow ( Math . cos ( xDbl ) , 2. ) ; if ( xDbl > 0.8 ) { /* tan(x) = 1/cot(x) */ BigDecimal co = cot ( x ) ; MathContext mc = new MathContext ( err2prec ( 1. / co . doubleValue ( ) , eps ) ) ; return BigDecimal . ONE . divide ( co , mc ) ; } else { final BigDecimal xhighpr = scalePrec ( res , 2 ) ; final BigDecimal xhighprSq = multiplyRound ( xhighpr , xhighpr ) ; BigDecimal result = xhighpr . plus ( ) ; /* x^(2i+1) */ BigDecimal xpowi = xhighpr ; Bernoulli b = new Bernoulli ( ) ; /* 2^(2i) */ BigInteger fourn = BigInteger . valueOf ( 4 ) ; /* (2i)! */ BigInteger fac = BigInteger . valueOf ( 2 ) ; for ( int i = 2 ; ; i ++ ) { Rational f = b . at ( 2 * i ) . abs ( ) ; fourn = fourn . shiftLeft ( 2 ) ; fac = fac . multiply ( BigInteger . valueOf ( 2 * i ) ) . multiply ( BigInteger . valueOf ( 2 * i - 1 ) ) ; f = f . multiply ( fourn ) . multiply ( fourn . subtract ( BigInteger . ONE ) ) . divide ( fac ) ; xpowi = multiplyRound ( xpowi , xhighprSq ) ; BigDecimal c = multiplyRound ( xpowi , f ) ; result = result . add ( c ) ; if ( Math . abs ( c . doubleValue ( ) ) < 0.1 * eps ) { break ; } } MathContext mc = new MathContext ( err2prec ( result . doubleValue ( ) , eps ) ) ; return result . round ( mc ) ; } } }
The trigonometric tangent .