public static BigDecimal asinUsingNewton(BigDecimal x, MathContext mathContext) {
		if (x.compareTo(ONE) > 0) {
			throw new ArithmeticException("Illegal asin(x) for x > 1: x = " + x);
		}
		if (x.compareTo(MINUS_ONE) < 0) {
			throw new ArithmeticException("Illegal asin(x) for x < -1: x = " + x);
		}
		
		if (x.signum() == -1) {
			return asinUsingNewton(x.negate(), mathContext).negate();
		}

		int maxPrecision = mathContext.getPrecision() + 4;

		BigDecimal acceptableError = ONE.movePointLeft(mathContext.getPrecision() + 1);
		MathContext maxMathContext = new MathContext(maxPrecision, mathContext.getRoundingMode());
		
		if (x.compareTo(BigDecimal.valueOf(0.707107)) >= 0) {
			BigDecimal xTransformed = BigDecimalMath.sqrt(ONE.subtract(x.multiply(x, maxMathContext), maxMathContext), maxMathContext);
			return acosUsingNewton(xTransformed, mathContext);
		}

		BigDecimal denominator = BigDecimalMath.cos(x, maxMathContext);

		BigDecimal result = BigDecimal.valueOf(Math.asin(x.doubleValue()));
		int adaptivePrecision = 17;
		BigDecimal step;
		
		do {
			adaptivePrecision = adaptivePrecision * 3;
			if (adaptivePrecision > maxPrecision) {
				adaptivePrecision = maxPrecision;
			}
			MathContext mc = new MathContext(adaptivePrecision, mathContext.getRoundingMode());

			BigDecimal nominator = BigDecimalMath.sin(result, mc).subtract(x, mc); 
			step = nominator.divide(denominator, mc);
			result = result.subtract(step, mc);
//			System.out.println(BigDecimalMath.exponent(step) + " : " + result);
		} while (step.abs().compareTo(acceptableError) > 0);

		return result.round(mathContext);
	}
public static BigDecimal asinUsingNewton ( BigDecimal x , MathContext mathContext ) { if ( x . compareTo ( ONE ) > 0 ) { throw new ArithmeticException ( "Illegal asin(x) for x > 1: x = " + x ) ; } if ( x . compareTo ( MINUS_ONE ) < 0 ) { throw new ArithmeticException ( "Illegal asin(x) for x < -1: x = " + x ) ; } if ( x . signum ( ) == - 1 ) { return asinUsingNewton ( x . negate ( ) , mathContext ) . negate ( ) ; } int maxPrecision = mathContext . getPrecision ( ) + 4 ; BigDecimal acceptableError = ONE . movePointLeft ( mathContext . getPrecision ( ) + 1 ) ; MathContext maxMathContext = new MathContext ( maxPrecision , mathContext . getRoundingMode ( ) ) ; if ( x . compareTo ( BigDecimal . valueOf ( 0.707107 ) ) >= 0 ) { BigDecimal xTransformed = BigDecimalMath . sqrt ( ONE . subtract ( x . multiply ( x , maxMathContext ) , maxMathContext ) , maxMathContext ) ; return acosUsingNewton ( xTransformed , mathContext ) ; } BigDecimal denominator = BigDecimalMath . cos ( x , maxMathContext ) ; BigDecimal result = BigDecimal . valueOf ( Math . asin ( x . doubleValue ( ) ) ) ; int adaptivePrecision = 17 ; BigDecimal step ; do { adaptivePrecision = adaptivePrecision * 3 ; if ( adaptivePrecision > maxPrecision ) { adaptivePrecision = maxPrecision ; } MathContext mc = new MathContext ( adaptivePrecision , mathContext . getRoundingMode ( ) ) ; BigDecimal nominator = BigDecimalMath . sin ( result , mc ) . subtract ( x , mc ) ; step = nominator . divide ( denominator , mc ) ; result = result . subtract ( step , mc ) ; } while ( step . abs ( ) . compareTo ( acceptableError ) > 0 ) ; return result . round ( mathContext ) ; }
variations on asin()