public static double log(double a){                
        // migrated from jWMMG - the origin of the algorithm is not known.
        if (Double.isNaN(a) || a < 0) {
            return Double.NaN;
        } else if (a == Double.POSITIVE_INFINITY) {
            return Double.POSITIVE_INFINITY;
        } else if (a == 0) {
            return Double.NEGATIVE_INFINITY;
        }
        
        long lx;
        if (a > 1) {
            lx = (long)(0.75*a); // 3/4*x
        } else {
            lx = (long)(0.6666666666666666666666666666666/a); // 2/3/x
        }
        
        int ix;
        int power;
        if (lx > Integer.MAX_VALUE) {
            ix = (int) (lx >> 31);
            power = 31;
        } else {
            ix = (int) lx;
            power = 0;
        }
        
        while (ix != 0) {
            ix >>= 1;
            power++;
        }
        
        double ret;
        if (a > 1) {
            ret = lnInternal(a / ((long) 1<<power)) + power * LN_2;
        } else {
            ret = lnInternal(a * ((long) 1<<power)) - power * LN_2;
        }
        return ret;
    }