二十、数学和随机

数学和随机

本文为书籍《Java编程的逻辑》1和《剑指Java:核心原理与应用实践》2阅读笔记

6.1 Math类

JDK中的数学相关类有java.lang.Math类,包含了一些数学常量值,以及用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数等,其方法的参数和返回值类型一般为double类型。

属性:

Modifier and TypeField and Description
static doubleE
The double value that is closer than any other to e, the base of the natural logarithms.
static doublePI
The double value that is closer than any other to pi, the ratio of the circumference of a circle to its diameter.

常用方法:

Modifier and TypeMethod and Description
static doubleabs(double a)
Returns the absolute value of a double value.
static floatabs(float a)
Returns the absolute value of a float value.
static intabs(int a)
Returns the absolute value of an int value.
static longabs(long a)
Returns the absolute value of a long value.
static doubleacos(double a)
Returns the arc cosine of a value; the returned angle is in the range 0.0 through pi.
static intaddExact(int x, int y)
Returns the sum of its arguments, throwing an exception if the result overflows an int.
static longaddExact(long x, long y)
Returns the sum of its arguments, throwing an exception if the result overflows a long.
static doubleasin(double a)
Returns the arc sine of a value; the returned angle is in the range -pi/2 through pi/2.
static doubleatan(double a)
Returns the arc tangent of a value; the returned angle is in the range -pi/2 through pi/2.
static doubleatan2(double y, double x)
Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta).
static doublecbrt(double a)
Returns the cube root of a double value.
static doubleceil(double a)
Returns the smallest (closest to negative infinity) double value that is greater than or equal to the argument and is equal to a mathematical integer.
static doublecopySign(double magnitude, double sign)
Returns the first floating-point argument with the sign of the second floating-point argument.
static floatcopySign(float magnitude, float sign)
Returns the first floating-point argument with the sign of the second floating-point argument.
static doublecos(double a)
Returns the trigonometric cosine of an angle.
static doublecosh(double x)
Returns the hyperbolic cosine of a double value.
static intdecrementExact(int a)
Returns the argument decremented by one, throwing an exception if the result overflows an int.
static longdecrementExact(long a)
Returns the argument decremented by one, throwing an exception if the result overflows a long.
static doubleexp(double a)
Returns Euler’s number e raised to the power of a double value.
static doubleexpm1(double x)
Returns ex -1.
static doublefloor(double a)
Returns the largest (closest to positive infinity) double value that is less than or equal to the argument and is equal to a mathematical integer.
static intfloorDiv(int x, int y)
Returns the largest (closest to positive infinity) int value that is less than or equal to the algebraic quotient.
static longfloorDiv(long x, long y)
Returns the largest (closest to positive infinity) long value that is less than or equal to the algebraic quotient.
static intfloorMod(int x, int y)
Returns the floor modulus of the int arguments.
static longfloorMod(long x, long y)
Returns the floor modulus of the long arguments.
static intgetExponent(double d)
Returns the unbiased exponent used in the representation of a double.
static intgetExponent(float f)
Returns the unbiased exponent used in the representation of a float.
static doublehypot(double x, double y)
Returns sqrt(x2 +y2) without intermediate overflow or underflow.
static doubleIEEEremainder(double f1, double f2)
Computes the remainder operation on two arguments as prescribed by the IEEE 754 standard.
static intincrementExact(int a)
Returns the argument incremented by one, throwing an exception if the result overflows an int.
static longincrementExact(long a)
Returns the argument incremented by one, throwing an exception if the result overflows a long.
static doublelog(double a)
Returns the natural logarithm (base e) of a double value.
static doublelog10(double a)
Returns the base 10 logarithm of a double value.
static doublelog1p(double x)
Returns the natural logarithm of the sum of the argument and 1.
static doublemax(double a, double b)
Returns the greater of two double values.
static floatmax(float a, float b)
Returns the greater of two float values.
static intmax(int a, int b)
Returns the greater of two int values.
static longmax(long a, long b)
Returns the greater of two long values.
static doublemin(double a, double b)
Returns the smaller of two double values.
static floatmin(float a, float b)
Returns the smaller of two float values.
static intmin(int a, int b)
Returns the smaller of two int values.
static longmin(long a, long b)
Returns the smaller of two long values.
static intmultiplyExact(int x, int y)
Returns the product of the arguments, throwing an exception if the result overflows an int.
static longmultiplyExact(long x, long y)
Returns the product of the arguments, throwing an exception if the result overflows a long.
static intnegateExact(int a)
Returns the negation of the argument, throwing an exception if the result overflows an int.
static longnegateExact(long a)
Returns the negation of the argument, throwing an exception if the result overflows a long.
static doublenextAfter(double start, double direction)
Returns the floating-point number adjacent to the first argument in the direction of the second argument.
static floatnextAfter(float start, double direction)
Returns the floating-point number adjacent to the first argument in the direction of the second argument.
static doublenextDown(double d)
Returns the floating-point value adjacent to d in the direction of negative infinity.
static floatnextDown(float f)
Returns the floating-point value adjacent to f in the direction of negative infinity.
static doublenextUp(double d)
Returns the floating-point value adjacent to d in the direction of positive infinity.
static floatnextUp(float f)
Returns the floating-point value adjacent to f in the direction of positive infinity.
static doublepow(double a, double b)
Returns the value of the first argument raised to the power of the second argument.
static doublerandom()
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
static doublerint(double a)
Returns the double value that is closest in value to the argument and is equal to a mathematical integer.
static longround(double a)
Returns the closest long to the argument, with ties rounding to positive infinity.
static intround(float a)
Returns the closest int to the argument, with ties rounding to positive infinity.
static doublescalb(double d, int scaleFactor)
Returns d × 2scaleFactor rounded as if performed by a single correctly rounded floating-point multiply to a member of the double value set.
static floatscalb(float f, int scaleFactor)
Returns f × 2scaleFactor rounded as if performed by a single correctly rounded floating-point multiply to a member of the float value set.
static doublesignum(double d)
Returns the signum function of the argument; zero if the argument is zero, 1.0 if the argument is greater than zero, -1.0 if the argument is less than zero.
static floatsignum(float f)
Returns the signum function of the argument; zero if the argument is zero, 1.0f if the argument is greater than zero, -1.0f if the argument is less than zero.
static doublesin(double a)
Returns the trigonometric sine of an angle.
static doublesinh(double x)
Returns the hyperbolic sine of a double value.
static doublesqrt(double a)
Returns the correctly rounded positive square root of a double value.
static intsubtractExact(int x, int y)
Returns the difference of the arguments, throwing an exception if the result overflows an int.
static longsubtractExact(long x, long y)
Returns the difference of the arguments, throwing an exception if the result overflows a long.
static doubletan(double a)
Returns the trigonometric tangent of an angle.
static doubletanh(double x)
Returns the hyperbolic tangent of a double value.
static doubletoDegrees(double angrad)
Converts an angle measured in radians to an approximately equivalent angle measured in degrees.
static inttoIntExact(long value)
Returns the value of the long argument; throwing an exception if the value overflows an int.
static doubletoRadians(double angdeg)
Converts an angle measured in degrees to an approximately equivalent angle measured in radians.
static doubleulp(double d)
Returns the size of an ulp of the argument.
static floatulp(float f)
Returns the size of an ulp of the argument.

6.2 BigInteger类

Integer类作为int的包装类,能存储的数值范围为 − 2 31 ∼ 2 31 − 1 -2^{31}\sim2^{31}-1 2312311BigInteger类的数值范围较Integer类、Long类的数值范围要大得多,可以支持任意精度的整数。BigInteger类位于java.math包下,和数值包装类一样,继承了Number类。BigInteger类是引用数据类型,但不是包装类,不支持自动装箱与拆箱,因此如果需要用它来表示整数,则需要通过指定的构造器来创建它的对象。例如,BigInteger(String val)构造器可以将整数的十进制字符串表示形式转换为BigInteger对象,如下所示。

BigInteger bVal = new BigInteger("1234567890");

BigInteger类是引用数据类型,所以不支持直接使用 + − +- +等运算符进行算术运算,如果需要完成BigInteger对象的计算,必须调用相应的方法来完成,如下表所示:

方法定义描述
BigInteger add(BigInteger val)加,返回 this 和 value 的和
BigInterger subtract(BigInteger val)减,返回 this 和 value 的差
BigInterger multiply(BigInteger val)乘,返回 this 和 value 的乘积
BigInterger divide(BigInteger val)除,结果只保留整数部分
BigInterger remainder(BigInteger val)获取 this % val 的结果
BigInterger max(BigInteger val)获取较大值
BigInterger min(BigInteger val)获取较小值

6.3 BigDecimal类

一般的Float类和Double类可以用来做一般的科学计算或工程计算,但在商业计算等对求数字精度要求比较高的场合中,就不能使用Float类和Double类,可以考虑使用BigDecimal类。BigDecimal类支持任何精度的定点数。同样BigDecimal类不是包装类,故不支持自动装箱与拆箱,如果要用它表示数字,则只能通过对应的构造器来创建对象。

  • BigDecimal(String val):将数字的十进制字符串表示形式转换为BigDecimal对象。
  • BigDecimal(double val):将double类转换为BigDecimal类。

同样,要对BigDecimal对象进行数学运算,也要调用相应的方法来完成,如下表所示。

方法定义描述
BigDecimal add(BigDecimal val)加,返回 this 和 value 的和
BigDecimal subtract(BigDecimal val)减,返回 this 和 value 的差
BigDecimal multiply(BigDecimal val)乘,返回 this 和 value 的乘积
BigDecimal divide(BigDecimal val, int roundingMode)除,如果不能除尽,则需要指定舍人的模式,否则会导致 ArithmeticException
BigDecimal max(BigDecimal val)获取较大值
BigDecimal min(BigDecimal val)获取较小值

6.4 随机

1、Math.random

Java中,对随机最基本的支持是Math类中的静态方法random(),它生成一个 0 ∼ 1 0\sim1 01的随机数,类型为double,包括 0 0 0但不包括 1 1 1

2、java.util.Random

位于java.util下的Random类提供了更为丰富的随机方法,它的方法不是静态方法,使用前需要创建Random实例。

public void nextBytes(byte[] bytes);
public int nextInt();
public int nextInt(int bound);
public int nextInt(int origin, int bound);
public long nextLong();
public long nextLong(long bound);
public long nextLong(long origin, long bound);
public float nextFloat();
public float nextFloat(float bound);
public float nextFloat(float origin, float bound);
public double nextDouble();
public double nextDouble(double bound);
public double nextDouble(double origin, double bound);
public boolean nextBoolean();

除了无参默认构造函数外,Random类还有一个构造方法,可以接受一个long类型的种子参数:

public Random(long seed)

种子决定了随机产生的序列,种子相同,产生的随机数序列就是相同的。

    @Test
    public void testSeed() {
        long randomSeed = Double.valueOf(Math.random() * 1000000).longValue();

        Random firstRandom = new Random(randomSeed);
        Random secondRandom = new Random(randomSeed);

        int[] firstRandomIntArray = new int[10];
        int[] secondRandomIntArray = new int[10];

        for (int i = 0; i < firstRandomIntArray.length; i++) {
            firstRandomIntArray[i] = firstRandom.nextInt();
        }
        for (int i = 0; i < secondRandomIntArray.length; i++) {
            secondRandomIntArray[i] = secondRandom.nextInt();
        }

        assertArrayEquals(firstRandomIntArray, secondRandomIntArray);
    }

两个Random类,他们的种子一样,得到的随机数也是一样。

除了在构造方法中指定种子,Random类还有一个setter实例方法:public void setSeed(long seed)。其效果与在构造方法中指定种子是一样的。

为什么要指定种子呢?指定种子还是真正的随机吗?指定种子是为了实现可重复的随机。比如用于模拟测试程序中,模拟要求随机,但测试要求可重复。种子到底扮演了什么角色呢?随机到底是如何产生的呢?让我们看下随机的基本原理。

2、随机的基本原理

Random产生的随机数不是真正的随机数,相反,它产生的随机数一般称为伪随机数。真正的随机数比较难以产生,计算机程序中的随机数一般都是伪随机数。伪随机数都是基于一个种子数的,然后每需要一个随机数,都是对当前种子进行一些数学运算,得到一个数,基于这个数得到需要的随机数和新的种子。数学运算是固定的,所以种子确定后,产生的随机数序列就是确定的,确定的数字序列当然不是真正的随机数,但种子不同,序列就不同,每个序列中数字的分布也都是比较随机和均匀的,所以称之为伪随机数。Random的默认构造方法中没有传递种子,它会自动生成一个种子,这个种子数是一个真正的随机数,如下所示:

	public Random() {
        this(seedUniquifier() ^ System.nanoTime());
    }

    private static long seedUniquifier() {
        // L'Ecuyer, "Tables of Linear Congruential Generators of
        // Different Sizes and Good Lattice Structure", 1999
        for (;;) {
            long current = seedUniquifier.get();
            long next = current * 1181783497276652981L;
            if (seedUniquifier.compareAndSet(current, next))
                return next;
        }
    }

	private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);

种子是seedUniquifier()System.nanoTime()按位异或的结果,System.nanoTime()返回一个更高精度(纳秒)的当前时间。简单地说,就是返回当前seedUniquifiercurrent变量)与一个常数181783497276652981L相乘的结果(next变量),然后,设置seedUniquifier的值为next,使用循环和compareAndSet都是为了确保在多线程的环境下不会有两次调用返回相同的值,保证随机性。

有了种子数之后,其他数是怎么生成的呢?我们来看一些代码:

    public int nextInt() {
        return next(32);
    }

    public long nextLong() {
        // it's okay that the bottom word remains signed.
        return ((long)(next(32)) << 32) + next(32);
    }
    
    public float nextFloat() {
        return next(Float.PRECISION) * FLOAT_UNIT;
    }

    public boolean nextBoolean() {
        return next(1) != 0;
    }

它们都调用了next(int bits),生成指定位数的随机数,我们来看下它的代码:

    protected int next(int bits) {
        long oldseed, nextseed;
        AtomicLong seed = this.seed;
        do {
            oldseed = seed.get();
            nextseed = (oldseed * multiplier + addend) & mask;
        } while (!seed.compareAndSet(oldseed, nextseed));
        return (int)(nextseed >>> (48 - bits));
    }

简单地说,就是使用了如下公式:

nextseed = (oldseed * multiplier + addend) & mask;

旧的种子(oldseed)乘以一个数(multiplier),加上一个数addend,然后取低 48 48 48位作为结果(mask相与)。为什么采用这个方法?这个方法为什么可以产生随机数?这个方法的名称叫线性同余随机数生成器(linear congruential pseudorandom number generator)。

我们需要知道的基本原理是:随机数基于一个种子,种子固定,随机数序列就固定,默认构造方法中,种子是一个真正的随机数。


  1. 马俊昌.Java编程的逻辑[M].北京:机械工业出版社,2018. ↩︎

  2. 尚硅谷教育.剑指Java:核心原理与应用实践[M].北京:电子工业出版社,2023. ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值