public static double sqrt(double a) throws IllegalArgumentException {

		if(a == 0) {
			return 0;
		}

		if (a < 0) {
			throw new IllegalArgumentException("Can not sqrt a negative number!");
		}

		// write  a  as  m * 10^2n  where  1 < m < 100
		// then  sqrt(a)  is around  1.8 * 10^n  or  5.6 * 10^n  depending on  m
		// 1.8 ~ geometric mean of sqrt(1) and sqrt(10). (when m is between 1 and 10)
		// 5.6 ~ geometric mean of sqrt(10) and sqrt(100).  (when m is between 10 and 100)
		// see http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Rough_estimation for more info

		double mantissa = a;
		double tenToTheN = 1;

		if (a >= 100) {
			while (mantissa / 100 > 1) {
				mantissa /= 100;
				tenToTheN = tenToTheN * 10;
			}
		} else if (a < 1) {
			while (mantissa * 100 <= 1) {
				mantissa *= 100;
				tenToTheN = tenToTheN / 10;
			}
		}

		double roughEstimation;
		if (mantissa < 10) {
			roughEstimation = 1.8 * tenToTheN;
		} else {
			roughEstimation = 5.6 * tenToTheN;
		}

		// newton's method
		// sqrt(a) is same as solving for x in the following:
		// x^2 - a = 0

		// f(x) = x^2 - a
		// f'(x) = 2x
		// see http://en.wikipedia.org/wiki/Methods_of_computing_square_roots for more info

		// loop should break well before max_iteration_count
		final int max_iteration_count = 40;
		double x = roughEstimation;
		for (int i = 1; i < max_iteration_count; i++) {
			double x_n = 0.5 * (x + (a / x));
			if(abs(x_n - x) < Double.MIN_VALUE) {
				x = x_n;
				return x;
			}
			x = x_n;
		}
		return x;
	}