五、常用类(三)Math & Number类 & BigDecimal类

今天的博客主题

      基础篇 --》常用类 --》Math & Number类


Math类

Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。

Math 的方法都被定义为 static 形式,通过 Math 类可以直接调用。

官方文档:https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html

Math常用方法

public class MathDemo {
    public static void main(String[] args) {
         //随机数(取出来的是小于1的 double 型随机数字)
         System.out.println(Math.random());

         //向上取整(不管小数点后面是多少,直接进1)
         System.out.println(Math.ceil(11.01)); // 12.0
         System.out.println(Math.ceil(11.99)); // 12.0

         //向下取整(不管小数点后面是多少,直接舍去)
         System.out.println(Math.floor(11.01)); // 11.0
         System.out.println(Math.floor(11.99)); // 11.0

         //四舍五入(正常数学里的四舍五入)
         System.out.println(Math.round(11.51)); // 12
         System.out.println(Math.round(11.49)); // 11

         //获取圆周率
         System.out.println(Math.PI); // 3.141592653589793

         //绝对值(不管正负,得到的总是正数,0比较特殊,得到的就是0)
         System.out.println(Math.abs(-10.11)); // 10.11
         System.out.println(Math.abs(10.11)); // 10.11

         // 计算平方根
         System.out.println(Math.sqrt(16)); // 4.0

         //计算立方根
         System.out.println(Math.cbrt(8));  // 2.0

         //计算a的b次方
         System.out.println(Math.pow(3,2)); // 9.0

         //取出最大值
         System.out.println(Math.max(11.99, 12.0)); // 12.0

         //取出最小值
         System.out.println(Math.min(11.99, 12.0)); // 11.99
    }
}

 

Number类

Number类是java.lang包下的一个抽象类,提供了将包装类型拆箱成基本类型的方法,所有基本类型的包装类型都继承了该抽象类,并且是final声明不可继承改变

需要使用数字的时候,我们通常使用内置数据类型,如:byte、int、long、double 等。

然而,在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情形。为了解决这个问题,Java 语言为每一个内置数据类型提供了对应的包装类。

Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类。

是由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类。相似的,编译器也可以把一个对象拆箱为内置类型。

对于包装数据类型的理解参考《02.编程基础-->3.Java数据类型》

 

BigDecimal类

BigDecimal类是在java.math包中提供的API,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。通过结论可看出float和double只能用来做科学计算或者是工程计算,在商业计算中还是要用java.math.BigDecimal。

public class BigDecimal extends Number implements Comparable<BigDecimal> { ... }   

 

源码比较多没有全贴出了,但是从类名上可以看到 BigDecimal extends Number 万变不离其宗呢这是。

BigDecimal有4个构造方法:

BigDecimal(int) 创建一个具有参数所指定整数值的对象。

BigDecimal(double) 创建一个具有参数所指定双精度值的对象。(不建议采用)

BigDecimal(long) 创建一个具有参数所指定长整数值的对象。

BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象

官方文档:https://docs.oracle.com/javase/6/docs/api/java/math/BigDecimal.html

 

代码分析

在正式对BigDecimal分析之前先看一段代码

public static void main(String[] args) {   
    System.out.println(0.2 + 0.1);
    System.out.println(0.3 - 0.1);
    System.out.println(0.4 * 0.1);
    System.out.println(0.6 / 0.1);
    System.out.println(0.6 / 0.2);
    System.out.println(0.7 / 0.1);
    System.out.println(0.7 / 0.2);
}
输出结果
0.30000000000000004
0.19999999999999998
0.04000000000000001
5.999999999999999
2.9999999999999996
6.999999999999999
3.4999999999999996

 

为什么会出现这种情况?什么原因导致的呢?

是因为我们的计算机是二进制的。浮点数没有办法是用二进制进行精确表示。我们的CPU表示浮点数由两个部分组成:指数和尾数,这样的表示方法一般都会失去一定的精确度,有些浮点数运算也会产生一定的误差。如:3.5的二进制表示并非就是精确的3.5。反而最为接近的二进制表示是3.4999999999999996。浮点数的值实际上是由一个特定的数学公式计算得到的。

 

看下BigDecimal的用法

public static void main(String[] args) {
    BigDecimal bigInt = new BigDecimal(1);
    BigDecimal bigDouble = new BigDecimal(0.1);
    BigDecimal bigString = new BigDecimal("0.1");
    System.out.println("bigInt = " + bigInt);
    System.out.println("bigDouble = " + bigDouble);
    System.out.println("bigString = " + bigString);
}
输出结果
bigInt = 1
bigDouble = 0.1000000000000000055511151231257827021181583404541015625
bigString = 0.1

会发现bigDouble的结果是这样的。为什么呢?

原因啊在《public BigDecimal(double val) {...}》这个构造方法上已经解释了。这个构造函数的结果可能有些不可预测,有人可能会认为,将@code new bigdecimal(0.1)写入Java创建了一个{代码BigDeMix},它完全等于0.1(非比例值为1,比例为1),但它是实际上等于10000000000000055511151231257827021181583404541015625。这是因为0.1不能精确表示为。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)另一方面,String 构造方法是完全可预知的:写入 newBigDecimal("0.1") 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法。还说了如果想用这个方法,double必须用作BigDecimal的源时,请使用Double.toString(double)转成String,然后使用String构造方法,或使用BigDecimal的静态方法valueOf,如下

 

public static void main(String[] args) {
    BigDecimal bigDouble = new BigDecimal(0.1);
    System.out.println("bigDouble = " + bigDouble);
    System.out.println("两种方法转换后");
    BigDecimal bigDouble1 = BigDecimal.valueOf(0.1);
    BigDecimal bigDouble2 = new BigDecimal(Double.toString(0.1));
    System.out.println("bigDouble1 = " + bigDouble1);
    System.out.println("bigDouble2 = " + bigDouble2);
}
输出结果
bigDouble = 0.1000000000000000055511151231257827021181583404541015625
两种方法转换后
bigDouble1 = 0.1
bigDouble2 = 0.1	

这样就可以了。

在看下BigDecimal的加减乘除,这可不是运算符的(+ - * /)了,而是提供了方法的。

public BigDecimal add(BigDecimal value);                      //加法
public BigDecimal subtract(BigDecimal value);                //减法 
public BigDecimal multiply(BigDecimal value);                 //乘法
public BigDecimal divide(BigDecimal value);                   //除法
===========用一下呗
public static void main(String[] args) {
    BigDecimal b1 = new BigDecimal("3.3");
    BigDecimal b2 = new BigDecimal("2.2");
    System.out.println("b1 + b2 = " + b1.add(b2));
    System.out.println("b1 - b2 = " + b1.subtract(b2));
    System.out.println("b1 * b2 = " + b1.multiply(b2));
    System.out.println("b1 / b2 = " + b1.divide(b2));
}
输出结果
b1 + b2 = 5.5
b1 - b2 = 1.1
b1 * b2 = 7.26
b1 / b2 = 1.5

注意

除法divide在不能整除的情况下会抛出一个异常:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

at java.math.BigDecimal.divide(BigDecimal.java:1690)

其实divide方法有可以传三个参数:

public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

第一参数表示除数, 第二个参数表示小数点后保留位数,

第三个参数表示舍入模式,只有在作除法运算或四舍五入时才用到舍入模式,有下面这几种

ROUND_CEILING //向上取整

ROUND_DOWN //向零方向舍入

ROUND_FLOOR //向下取整

ROUND_HALF_DOWN //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5

ROUND_HALF_EVEN //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP,如果是偶数,使用ROUND_HALF_DOWN

ROUND_HALF_UP //向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6

ROUND_UNNECESSARY //计算结果是精确的,不需要舍入模式

ROUND_UP //向远离0的方向舍入

都试一下看看会怎样

 

public static void main(String[] args) {
    BigDecimal b1 = new BigDecimal("3.3");
    BigDecimal b2 = new BigDecimal("1.9");

    System.out.println("b1 / b2 = ROUND_CEILING " + b1.divide(b2,2,BigDecimal.ROUND_CEILING));
    System.out.println("b1 / b2 = ROUND_DOWN " + b1.divide(b2,2,BigDecimal.ROUND_DOWN));
    System.out.println("b1 / b2 = ROUND_FLOOR " + b1.divide(b2,2,BigDecimal.ROUND_FLOOR));
    System.out.println("b1 / b2 = ROUND_HALF_DOWN " + b1.divide(b2,2,BigDecimal.ROUND_HALF_DOWN));
    System.out.println("b1 / b2 = ROUND_HALF_EVEN " + b1.divide(b2,2,BigDecimal.ROUND_HALF_EVEN));
    System.out.println("b1 / b2 = ROUND_HALF_UP " + b1.divide(b2,2,BigDecimal.ROUND_HALF_UP));
    // System.out.println("b1 / b2 = ROUND_UNNECESSARY " + b1.divide(b2,2,BigDecimal.ROUND_UNNECESSARY));计算结果是精确的,不需要舍入
    System.out.println("b1 / b2 = ROUND_UP " + b1.divide(b2,2,BigDecimal.ROUND_UP));
}
输出结果
b1 / b2 = ROUND_CEILING 1.74
b1 / b2 = ROUND_DOWN 1.73
b1 / b2 = ROUND_FLOOR 1.73
b1 / b2 = ROUND_HALF_DOWN 1.74
b1 / b2 = ROUND_HALF_EVEN 1.74
b1 / b2 = ROUND_HALF_UP 1.74
b1 / b2 = ROUND_UP 1.74

基本上这些都是会在工作中比较常用的类。

熟能生巧

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
`BigDecimal` 是 Java 中用于处理任意精度的十进制数的一种数据型,它适用于需要高精度计算的应用场景,比如财务计算、科学应用等。当涉及到货币或其他不允许有精确度损失的情况时,`BigDecimal` 就显得尤为重要。 ### `BigDecimal` 和整数(包括零)比较大小 当你使用 `BigDecimal` 对比零时,可以使用标准的比较操作符如 `<`, `<=`, `==`, `>=`, `>` 或 `.compareTo()` 方法来进行。下面是几个例子说明如何将 `BigDecimal` 与零进行比较: #### 示例代码: ```java import java.math.BigDecimal; public class BigDecimalComparison { public static void main(String[] args) { // 创建 BigDecimal 实例 BigDecimal number = new BigDecimal("0.5"); // 使用 == 进行比较 if (number.equals(BigDecimal.ZERO)) { System.out.println("The number is equal to zero."); } else { System.out.println("The number is not equal to zero."); } // 使用 .compareTo() 进行比较 int result = number.compareTo(BigDecimal.ZERO); if (result > 0) { System.out.println("The number is greater than zero."); } else if (result < 0) { System.out.println("The number is less than zero."); } else { System.out.println("The number is equal to zero."); } } } ``` ### 相关问题: 1. **如何安全地进行浮点数和 `BigDecimal` 的转换?** 当从其他型的数字(如 `double` 或 `float`)获取数值时,直接构造 `BigDecimal` 可能会丢失精度。为了避免这种情况,可以先通过 `new BigDecimal(Double.toString(value))` 或 `new BigDecimal(Float.toString(value))` 来创建 `BigDecimal`,这样可以尽量保留原始值的精度。 2. **为何 `BigDecimal` 比 `double` 更适合处理货币金额?** 货币金额通常需要非常精确,并且对小数点后的位数有严格的控制。`BigDecimal` 支持任意精度并允许设置小数点后有效数字的数量,因此更适合货币计算,避免了浮点数运算常见的精度损失问题。 3. **何时应该使用 `BigDecimal` 而不是 `double`?** 应该使用 `BigDecimal` 在任何时候需要保证数学计算结果的绝对准确性和避免浮点数运算中的误差,特别是在涉及金融、会计和其他需要高度精确计算的领域。例如,在银行系统、电子商务交易、财务报告中都应该优先考虑使用 `BigDecimal`。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值