java.lang.Math

Math 计算的参数基本包含 double、float、int、long 等类型,下面方法以 int 为例(非 int 为特殊参数)。

常用静态方法:

  1. int abs(int a) :返回 a 的绝对值
  2. double ceil(double a) :大于 a 的最小整数(向上取整)
  3. double floor(double a) :小于 a 的最大整数(向下取整)
  4. int max(int a, int b)min(int a, int b) :返回 a, b 之间的较大或较小值
  5. double pow(double a, double b) :返回 a 的 b 次幂 ab
  6. double random():返回值为 0.0 到 1.0 的随机数
  7. long round(double a) :四舍五入的 long 值
  8. int round(float a) :四舍五入的 int 值
  9. double sqrt(double a) :平方根
    1. public class MathTests {
    2. public static void main(String[] args) {
    3. System.out.println(Math.abs(-1)); // 1
    4. System.out.println(Math.ceil(-1.8)); // -1.0
    5. System.out.println(Math.floor(-1.8)); // -2.0
    6. System.out.println(Math.pow(2.0, 3.0)); // 8.0
    7. System.out.println(Math.random()); // 0.0 - 1.0 随机数
    8. System.out.println(Math.random() * 10); // 1.0 - 10.0 随机数
    9. System.out.println(Math.round(24.3)); // 24
    10. System.out.println(Math.round(24.5F)); // 25
    11. System.out.println(Math.sqrt(64.0)); // 8.0
    12. }
    13. }

    java.util.Random

    专门用于生成随机数的类;使用java.lang.Math.random() 方法只能生成 double 类型的随机数,其原理是在底层创建了 Random 类调用了 nextDouble() 方法生成的一个 double 类型随机数。

java.util.Random 实例是线程安全的。 但是,跨线程并发使用同一个 java.util.Random 实例可能会遇到争用,从而导致性能不佳。考虑在多线程设计中使用 java.util.concurrent.ThreadLocalRandom

java.util.Random 实例不是加密安全的。 考虑改为使用 java.security.SecureRandom 来获取加密安全的伪随机数生成器,以供对安全敏感的应用程序使用。

常用方法:

  1. public class RandomTests {
  2. public static void main(String[] args) {
  3. Random rand = new Random();
  4. // 1. 随机生成[0,1)之间的 double 类型的数据
  5. System.out.println(rand.nextDouble());
  6. // 2. 随机生成int类型允许范围之内的 int 数据
  7. System.out.println(rand.nextInt());
  8. // 3. 随机生成[0,1)之间的 float 类型的数据
  9. System.out.println(rand.nextFloat());
  10. // 4. 随机生成[false,true]的 boolean 类型数据
  11. System.out.println(rand.nextBoolean());
  12. // 随机生成[0,10)之间的 int 类型的数据
  13. System.out.println(rand.nextInt(10));
  14. // 随机生成[20,30)之间的 int 类型的数据
  15. System.out.println(20 + rand.nextInt(10));
  16. // 随机生成[20,30)之间的 int 类型的数据(此种方法计算较为复杂)
  17. System.out.print(20 + (int) (rand.nextDouble() * 10));
  18. }
  19. }

java.math.BigDecimal

  1. 浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。
  2. BigDecimal 可以解决浮点型运算数据失真的精度问题。

引入:为什么要使用 BigDecimal?什么是精度丢失?

  1. System.out.println(0.2 + 0.1); // 0.30000000000000004
  2. System.out.println(0.3 - 0.1); // 0.19999999999999998
  3. System.out.println(0.2 * 0.1); // 0.020000000000000004
  4. System.out.println(0.3 / 0.1); // 2.9999999999999996

计算机只能识别二级制,在进行数学计算时,参与计算的数据都是二进制,所以我们输入的十进制计算数据都会先转换为二进制,计算机用二进制计算完成后,再由二进制转换为十进制返回。

在这过程中,十进制转二进制时,有些数字是无法完全转换的,小数在转换为二进制时并不一定能用一个精确的二进制表示,大多数时候都是取的一个近似值,这就造成了精度的丢失。如果再用这个二进制进行计算,明显计算结果的精度会进一步丢失。终极原因还是因为精度丢失。

浮点数二进制与十进制转换:https://www.bilibili.com/read/cv11242656/

针对这一问题,Java 语言提供了 java.math.BigDecimal 类专门用来进行精确计算。

阿里巴巴推荐创建对象方式

【强制】为了防止精度损失,禁止使用构造方法 BigDecimal(double) 的方式把 double 值转化为 BigDecimal 对象。

说明:BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
如:BigDecimal g = new BigDecimal(0.1f); 实际的存储值为:0.10000000149

正例:优先推荐入参为 String 的构造方法,或使用 BigDecimal 的 valueOf 方法,此方法内部其实执行了 Double 的 toString,而 Double 的 toString 按 double 的实际能表达的精度对尾数进行了截断。

  1. BigDecimal recommend1 = new BigDecimal("0.1");
  2. BigDecimal recommend2 = BigDecimal.valueOf(0.1);

算术操作

方法签名 方法描述
BigDecimal add(BigDecimal augend) 加法运算
BigDecimal subtract(BigDecimal subtrahend) 减法运算
BigDecimal multiply(BigDecimal multiplicand) 乘法运算
BigDecimal divide(BigDecimal divisor) 除法运算
  1. public class BigDecimalTests {
  2. public static void main(String[] args) {
  3. BigDecimal a = new BigDecimal("10.0");
  4. BigDecimal b = new BigDecimal("3.0");
  5. System.out.println(a.add(b)); // 13.0
  6. System.out.println(a.subtract(b)); // 7.0
  7. System.out.println(a.multiply(b)); // 30.00
  8. System.out.println(a.divide(b, 5, RoundingMode.HALF_UP)); // 3.33333
  9. }
  10. }

除了上述的四个基本的算术操作方法外,每种运算都还有中两个参数的重载方法:

  • BigDecimal add(BigDecimal augend, MathContext mc);
  • BigDecimal subtract(BigDecimal subtrahend, MathContext mc);
  • BigDecimal multiply(BigDecimal multiplicand, MathContext mc);
  • BigDecimal divide(BigDecimal divisor, MathContext mc);

这个多出来的参数主要用来约束计算结果的精度和舍入操作的算法。

java.math 工具类

MathContext - 计算精度

java.math.MathContext 是数值运算的上下文配置:

  1. precision:用于操作的位数; 结果四舍五入到这个精度;
  2. roundingMode:一个 RoundingMode 对象,指定舍入操作的算法;

RoundingMode 是 java.math 包下的枚举类型,指定能够舍弃精度的数值运算的舍入行为。

RoundingMode - 舍入算法

java.math.RoundingMode 用于指定能够舍弃精度的数值运算的舍入行为。

枚举值 枚举描述
RoundingMode.UP 不论正负,进1法舍入,向远离 0 的方向舍入
RoundingMode.DOWN 舍弃小数部分,向靠近 0 的方向舍入
RoundingMode.CEILING 正数进1法(UP),负数舍弃小数部分(DOWN),向正无穷方向舍入
RoundingMode.FLOOR 正数舍弃小数部分(DOWN),负数进1法(UP),向负无穷方向舍入
RoundingMode.HALF_UP 四舍五入法,大于等于5时进1,否则舍弃,向最近邻居的方向舍入
RoundingMode.HALF_DOWN 五舍六入,大于5时进1位,否则舍弃,向最近邻居的方向舍入
RoundingMode.HALF_EVEN 距离相等时向偶数邻居舍入,向最近邻居的方向舍入,银行家的四舍五入
RoundingMode.UNNECESSARY 不舍入
  1. public enum RoundingMode {
  2. /**
  3. * 5.5 6
  4. * 2.5 3
  5. * 1.6 2
  6. * 1.1 1
  7. * 1.0 1
  8. * -1.0 -1
  9. * -1.1 -2
  10. * -1.6 -2
  11. * -2.5 -3
  12. * -5.5 -6
  13. */
  14. UP(BigDecimal.ROUND_UP),
  15. /**
  16. * 5.5 5
  17. * 2.5 2
  18. * 1.6 1
  19. * 1.1 1
  20. * 1.0 1
  21. * -1.0 -1
  22. * -1.1 -1
  23. * -1.6 -1
  24. * -2.5 -2
  25. * -5.5 -5
  26. */
  27. DOWN(BigDecimal.ROUND_DOWN),
  28. /**
  29. * 5.5 6
  30. * 2.5 3
  31. * 1.6 2
  32. * 1.1 2
  33. * 1.0 1
  34. * -1.0 -1
  35. * -1.1 -1
  36. * -1.6 -1
  37. * -2.5 -2
  38. * -5.5 -5
  39. */
  40. CEILING(BigDecimal.ROUND_CEILING),
  41. /**
  42. * 5.5 5
  43. * 2.5 2
  44. * 1.6 1
  45. * 1.1 1
  46. * 1.0 1
  47. * -1.0 -1
  48. * -1.1 -2
  49. * -1.6 -2
  50. * -2.5 -3
  51. * -5.5 -6
  52. */
  53. FLOOR(BigDecimal.ROUND_FLOOR),
  54. /**
  55. * 5.5 6
  56. * 2.5 3
  57. * 1.6 2
  58. * 1.1 1
  59. * 1.0 1
  60. * -1.0 -1
  61. * -1.1 -1
  62. * -1.6 -2
  63. * -2.5 -3
  64. * -5.5 -6
  65. */
  66. HALF_UP(BigDecimal.ROUND_HALF_UP),
  67. /**
  68. * 5.5 5
  69. * 2.5 2
  70. * 1.6 2
  71. * 1.1 1
  72. * 1.0 1
  73. * -1.0 -1
  74. * -1.1 -1
  75. * -1.6 -2
  76. * -2.5 -2
  77. * -5.5 -5
  78. */
  79. HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
  80. /**
  81. * 5.5 6
  82. * 2.5 2
  83. * 1.6 2
  84. * 1.1 1
  85. * 1.0 1
  86. * -1.0 -1
  87. * -1.1 -1
  88. * -1.6 -2
  89. * -2.5 -2
  90. * -5.5 -6
  91. */
  92. HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
  93. /**
  94. * 5.5 抛出ArithmeticExceptio
  95. * 2.5 抛出ArithmeticExceptio
  96. * 1.6 抛出ArithmeticExceptio
  97. * 1.1 抛出ArithmeticExceptio
  98. * 1.0 1
  99. * -1.0 -1
  100. * -1.1 抛出ArithmeticExceptio
  101. * -1.6 抛出ArithmeticExceptio
  102. * -2.5 抛出ArithmeticExceptio
  103. * -5.5 抛出ArithmeticExceptio
  104. */
  105. UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
  106. }

参考: JDK 源码 Java 8 API:https://www.matools.com/api/java8 舍入操作:https://www.cnblogs.com/yezi-lu/p/9448864.html 用法:https://blog.csdn.net/qq_33619378/article/details/90408110