Java 源码 - java.lang.Math

517 阅读3分钟

概述

在java的使用过程中,Math类常被用于进行一些计算, 通常使用的方法包括了abs(), max(), min(), random(), 已经不常用的包括addExact(), substractExact() 和multiplyExact()方法等。

构造方法和静态变量

private Collections() {
}    

public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;

常用方法

三角函数

    public static double sin(double a) {
        return StrictMath.sin(a);
        // default impl. delegates to StrictMath
    }

    public static double cos(double a) {
        return StrictMath.cos(a);
        // default impl. delegates to StrictMath
    }

    public static double tan(double a) {
        return StrictMath.tan(a);
        // default impl. delegates to StrictMath
    }

    public static double asin(double a) {
        return StrictMath.asin(a);
        // default impl. delegates to StrictMath
    }

    public static double acos(double a) {
        return StrictMath.acos(a);
        // default impl. delegates to StrictMath
    }

    public static double atan(double a) {
        return StrictMath.atan(a);
        // default impl. delegates to StrictMath
    }    

    //Converts an angle measured in degrees to an approximately
    public static double toRadians(double angdeg) {
        return angdeg / 180.0 * PI;
    }

    //Converts an angle measured in radians to an approximately
    //* equivalent angle measured in degrees.
    public static double toDegrees(double angrad) {
        return angrad * 180.0 / PI;
    }

指数对数运算

    public static double exp(double a) {
        return StrictMath.exp(a);
        // default impl. delegates to StrictMath
    }

    public static double log(double a) {
        return StrictMath.log(a);
        // default impl. delegates to StrictMath
    }

    public static double log10(double a) {
        return StrictMath.log10(a);
        // default impl. delegates to StrictMath
    }

开方运算

    public static double sqrt(double a) {
        return StrictMath.sqrt(a); // default impl. delegates to StrictMath
        // Note that hardware sqrt instructions
        // frequently can be directly used by JITs
        // and should be much faster than doing
        // Math.sqrt in software.
    }

    public static double cbrt(double a) {
        return StrictMath.cbrt(a);
    }

ceiling()/floor()/pow()

    public static double ceil(double a) {
        return StrictMath.ceil(a);
        // default impl. delegates to StrictMath
    }

    public static double floor(double a) {
        return StrictMath.floor(a);
        // default impl. delegates to StrictMath
    }    

    public static double pow(double a, double b) {
        return StrictMath.pow(a, b);
        // default impl. delegates to StrictMath
    }

round 方法

    public static double pow(double a, double b) {
        return StrictMath.pow(a, b);
        // default impl. delegates to StrictMath
    }

    public static int round(float a) {
        int intBits = Float.floatToRawIntBits(a);
        int biasedExp = (intBits & FloatConsts.EXP_BIT_MASK)
                >> (FloatConsts.SIGNIFICAND_WIDTH - 1);
        int shift = (FloatConsts.SIGNIFICAND_WIDTH - 2
                + FloatConsts.EXP_BIAS) - biasedExp;
        if ((shift & -32) == 0) { // shift >= 0 && shift < 32
            // a is a finite number such that pow(2,-32) <= ulp(a) < 1
            int r = ((intBits & FloatConsts.SIGNIF_BIT_MASK)
                    | (FloatConsts.SIGNIF_BIT_MASK + 1));
            if (intBits < 0) {
                r = -r;
            }
            // In the comments below each Java expression evaluates to the value
            // the corresponding mathematical expression:
            // (r) evaluates to a / ulp(a)
            // (r >> shift) evaluates to floor(a * 2)
            // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
            // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
            return ((r >> shift) + 1) >> 1;
        } else {
            // a is either
            // - a finite number with abs(a) < exp(2,FloatConsts.SIGNIFICAND_WIDTH-32) < 1/2
            // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
            // - an infinity or NaN
            return (int) a;
        }
    }

    public static long round(double a) {
        long longBits = Double.doubleToRawLongBits(a);
        long biasedExp = (longBits & DoubleConsts.EXP_BIT_MASK)
                >> (DoubleConsts.SIGNIFICAND_WIDTH - 1);
        long shift = (DoubleConsts.SIGNIFICAND_WIDTH - 2
                + DoubleConsts.EXP_BIAS) - biasedExp;
        if ((shift & -64) == 0) { // shift >= 0 && shift < 64
            // a is a finite number such that pow(2,-64) <= ulp(a) < 1
            long r = ((longBits & DoubleConsts.SIGNIF_BIT_MASK)
                    | (DoubleConsts.SIGNIF_BIT_MASK + 1));
            if (longBits < 0) {
                r = -r;
            }
            // In the comments below each Java expression evaluates to the value
            // the corresponding mathematical expression:
            // (r) evaluates to a / ulp(a)
            // (r >> shift) evaluates to floor(a * 2)
            // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
            // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
            return ((r >> shift) + 1) >> 1;
        } else {
            // a is either
            // - a finite number with abs(a) < exp(2,DoubleConsts.SIGNIFICAND_WIDTH-64) < 1/2
            // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
            // - an infinity or NaN
            return (long) a;
        }
    }

random 方法

    private static final class RandomNumberGeneratorHolder {
        static final Random randomNumberGenerator = new Random();
    }

    public static double random() {
        return Math.RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
    }

add/substract 方法

    public static int addExact(int x, int y) {
        int r = x + y;
        if(((x ^ r) & (y ^ r)) < 0)
            throw new ArithmeticException("integer overflow");
        return r;
    }

    public static long addExact(long x, long y) {
        long r = x + y;
        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
        if (((x ^ r) & (y ^ r)) < 0) {
            throw new ArithmeticException("long overflow");
        }
        return r;
    }

    public static int subtractExact(int x, int y) {
        int r = x - y;
        // HD 2-12 Overflow iff the arguments have different signs and
        // the sign of the result is different than the sign of x
        if (((x ^ y) & (x ^ r)) < 0) {
            throw new ArithmeticException("integer overflow");
        }
        return r;
    }

    public static long subtractExact(long x, long y) {
        long r = x - y;
        // HD 2-12 Overflow iff the arguments have different signs and
        // the sign of the result is different than the sign of x
        if (((x ^ y) & (x ^ r)) < 0) {
            throw new ArithmeticException("long overflow");
        }
        return r;
    }

原理其实很简单。只有两个正数或者两个负数相加的时候才会溢出,一正一负是不会溢出的。并且,溢出后得到的结果一定是与原值的符号相反的。 ​ 

借用这个原理,(x ^ r) & (y ^ r)将用运算符算出来的r与x和y分别异或。异或的规则是同0异1。我们只看符号位,如果符号位不同,那么两个括号得到的都是1。而与运算又是只有1 & 1才是1,有一个为0都是0。因此,一旦溢出,无论是正溢出负溢出,(x ^ r) & (y ^ r)计算出的结果都应该小于0  

multiplyExact 方法 

    public static int multiplyExact(int x, int y) {
        long r = (long)x * (long)y;
        if ((int)r != r) {
            throw new ArithmeticException("integer overflow");
        }
        return (int)r;
    }

    public static long multiplyExact(long x, long y) {
        long r = x * y;
        long ax = Math.abs(x);
        long ay = Math.abs(y);
        if (((ax | ay) >>> 31 != 0)) {
            // Some bits greater than 2^31 that might cause overflow
            // Check the result using the divide operator
            // and check for the special case of Long.MIN_VALUE * -1
            if (((y != 0) && (r / y != x)) ||
                    (x == Long.MIN_VALUE && y == -1)) {
                throw new ArithmeticException("long overflow");
            }
        }
        return r;
    }

增减方法

    public static int incrementExact(int a) {
        if (a == Integer.MAX_VALUE) {
            throw new ArithmeticException("integer overflow");
        }

        return a + 1;
    }

    public static long incrementExact(long a) {
        if (a == Long.MAX_VALUE) {
            throw new ArithmeticException("long overflow");
        }

        return a + 1L;
    }

    public static int decrementExact(int a) {
        if (a == Integer.MIN_VALUE) {
            throw new ArithmeticException("integer overflow");
        }

        return a - 1;
    }

    public static long decrementExact(long a) {
        if (a == Long.MIN_VALUE) {
            throw new ArithmeticException("long overflow");
        }

        return a - 1L;
    }

    public static int negateExact(int a) {
        if (a == Integer.MIN_VALUE) {
            throw new ArithmeticException("integer overflow");
        }

        return -a;
    }

    public static long negateExact(long a) {
        if (a == Long.MIN_VALUE) {
            throw new ArithmeticException("long overflow");
        }

        return -a;
    }

abs方法

    public static int abs(int a) { return (a < 0) ? -a : a; }

    public static long abs(long a) { return (a < 0) ? -a : a; }

    /*
     * If the argument is not negative, the argument is returned.
     * If the argument is negative, the negation of the argument is returned.
     * Special cases:
     * <ul><li>If the argument is positive zero or negative zero, the
     * result is positive zero.
     * <li>If the argument is infinite, the result is positive infinity.
     * <li>If the argument is NaN, the result is NaN.</ul>
     */
    public static float abs(float a) { return (a <= 0.0F) ? 0.0F - a : a; }

    public static double abs(double a) {
        return (a <= 0.0D) ? 0.0D - a : a;
    }

max/min 方法

    public static int max(int a, int b) {
        return (a >= b) ? a : b;
    }

    public static long max(long a, long b) {
        return (a >= b) ? a : b;
    }

    private static long negativeZeroFloatBits  = Float.floatToRawIntBits(-0.0f);
    private static long negativeZeroDoubleBits = Double.doubleToRawLongBits(-0.0d);

    /*
     * Returns the greater of two {@code float} values.  That is,
     * the result is the argument closer to positive infinity.
     */
    public static float max(float a, float b) {
        if (a != a)
            return a;   // a is NaN
        if ((a == 0.0f) &&
                (b == 0.0f) &&
                (Float.floatToRawIntBits(a) == negativeZeroFloatBits)) {
            // Raw conversion ok since NaN can't map to -0.0.
            return b;
        }
        return (a >= b) ? a : b;
    }

    public static double max(double a, double b) {
        if (a != a)
            return a;   // a is NaN
        if ((a == 0.0d) &&
                (b == 0.0d) &&
                (Double.doubleToRawLongBits(a) == negativeZeroDoubleBits)) {
            // Raw conversion ok since NaN can't map to -0.0.
            return b;
        }
        return (a >= b) ? a : b;
    }

    public static int min(int a, int b) {
        return (a <= b) ? a : b;
    }

    public static long min(long a, long b) {
        return (a <= b) ? a : b;
    }

    /*
     * Returns the smaller of two {@code float} values.  That is,
     * the result is the value closer to negative infinity.
     */
    public static float min(float a, float b) {
        if (a != a)
            return a;   // a is NaN
        if ((a == 0.0f) &&
                (b == 0.0f) &&
                (Float.floatToRawIntBits(b) == negativeZeroFloatBits)) {
            // Raw conversion ok since NaN can't map to -0.0.
            return b;
        }
        return (a <= b) ? a : b;
    }

    public static double min(double a, double b) {
        if (a != a)
            return a;   // a is NaN
        if ((a == 0.0d) &&
                (b == 0.0d) &&
                (Double.doubleToRawLongBits(b) == negativeZeroDoubleBits)) {
            // Raw conversion ok since NaN can't map to -0.0.
            return b;
        }
        return (a <= b) ? a : b;
    }    

ulp方法

    public static double ulp(double d) {
        int exp = getExponent(d);

        switch(exp) {
            case DoubleConsts.MAX_EXPONENT+1:       // NaN or infinity
                return Math.abs(d);

            case DoubleConsts.MIN_EXPONENT-1:       // zero or subnormal
                return Double.MIN_VALUE;

            default:
                assert exp <= DoubleConsts.MAX_EXPONENT && exp >= DoubleConsts.MIN_EXPONENT;

                // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
                exp = exp - (DoubleConsts.SIGNIFICAND_WIDTH-1);
                if (exp >= DoubleConsts.MIN_EXPONENT) {
                    return powerOfTwoD(exp);
                }
                else {
                    // return a subnormal result; left shift integer
                    // representation of Double.MIN_VALUE appropriate
                    // number of positions
                    return Double.longBitsToDouble(1L <<
                            (exp - (DoubleConsts.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH-1)) ));
                }
        }
    }

    public static float ulp(float f) {
        int exp = getExponent(f);

        switch(exp) {
            case FloatConsts.MAX_EXPONENT+1:        // NaN or infinity
                return Math.abs(f);

            case FloatConsts.MIN_EXPONENT-1:        // zero or subnormal
                return FloatConsts.MIN_VALUE;

            default:
                assert exp <= FloatConsts.MAX_EXPONENT && exp >= FloatConsts.MIN_EXPONENT;

                // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
                exp = exp - (FloatConsts.SIGNIFICAND_WIDTH-1);
                if (exp >= FloatConsts.MIN_EXPONENT) {
                    return powerOfTwoF(exp);
                }
                else {
                    // return a subnormal result; left shift integer
                    // representation of FloatConsts.MIN_VALUE appropriate
                    // number of positions
                    return Float.intBitsToFloat(1 <<
                            (exp - (FloatConsts.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH-1)) ));
                }
        }
    }

    public static double signum(double d) {
        return (d == 0.0 || Double.isNaN(d))?d:copySign(1.0, d);
    }

    public static float signum(float f) {
        return (f == 0.0f || Float.isNaN(f))?f:copySign(1.0f, f);
    }