Java 高精度计算 BigDecimal 和 BigInteger

举报
陈皮的JavaLib 发表于 2022/03/26 10:45:26 2022/03/26
【摘要】 在 Java 中,表示小数值一般使用 float 或者 double 类型,可以用于科学计算或者工程计算等。数学意义上的小数是连续的,但 float 和 double 只能表示其中的一些离散点,如果我们要表示的数值刚好无法用 float 或者 double 精确表示的话,那么它会找一个最近的值来近似表示。float 类型的有效精度为6到7位。double 类型的有效精度为16位。

我是陈皮,一个在互联网 Coding 的 ITer,个人微信公众号「陈皮的JavaLib」关注第一时间阅读最新文章。

BigDecimal

在 Java 中,表示小数值一般使用 float 或者 double 类型,可以用于科学计算或者工程计算等。数学意义上的小数是连续的,但 float 和 double 只能表示其中的一些离散点,如果我们要表示的数值刚好无法用 float 或者 double 精确表示的话,那么它会找一个最近的值来近似表示。float 类型的有效精度为6到7位。double 类型的有效精度为16位。

如下所示,float 和 double 类型的计算结果可能出乎我们的预料。

package com.chenpi;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/25
 */
public class ChenPi {

  public static void main(String[] args) {

    double d1 = 0.2;
    double d2 = 0.1;
    double d3 = d1 + d2;
    System.out.println(d3);

    float f1 = 0.1f;
    float f2 = 0.2f;
    float f3 = f1 * f2;
    System.out.println(f3);
  }
}

// 输出结果如下
0.30000000000000004
0.020000001

在商业计算,银行金融等领域,要求数字的精度非常高。推荐使用 BigDecimal 类,它能支持任何精度的定点数。

package com.chenpi;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/25
 */
public class ChenPi {

  public static void main(String[] args) {

    BigDecimal bigDecimal1 = new BigDecimal("0.1");
    BigDecimal bigDecimal2 = new BigDecimal("0.2");

    // 加法
    System.out.println(bigDecimal1.add(bigDecimal2));
    // 减法
    System.out.println(bigDecimal1.subtract(bigDecimal2));
    // 乘法
    System.out.println(bigDecimal1.multiply(bigDecimal2));
    // 除法,保留2位小数,向上取舍
    System.out.println(bigDecimal1.divide(bigDecimal2, 2, RoundingMode.HALF_UP));
    // 小数点往左移2位
    System.out.println(bigDecimal1.movePointLeft(2));
    // 小数点往右移1位
    System.out.println(bigDecimal1.movePointRight(1));
    // 转为double值
    System.out.println(bigDecimal1.doubleValue());
    // 2次方
    System.out.println(bigDecimal1.pow(2));

  }
}

注意,不要使用 double 参数的构造方法,因为传入的 double 值可能就不准确的,如下所示。

package com.chenpi;

import java.math.BigDecimal;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/25
 */
public class ChenPi {

  public static void main(String[] args) {
    BigDecimal bigDecimal1 = new BigDecimal(0.1);
    System.out.println(bigDecimal1);
  }
}

// 输出结果如下
0.1000000000000000055511151231257827021181583404541015625

在对两个 BigDecimal 对象进行比较时,不要使用 equals,推荐使用 compareTo。因为 equals 方法会比较小数的位数,这样对于 0.1 和 0.10 就会返回 false。

package com.chenpi;

import java.math.BigDecimal;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/25
 */
public class ChenPi {

  public static void main(String[] args) {
    BigDecimal bigDecimal1 = new BigDecimal("21.1");
    BigDecimal bigDecimal2 = new BigDecimal("21.10");

    // 数值相等,但是小数位不相等,导致结果为false
    System.out.println("equals:" + bigDecimal1.equals(bigDecimal2));

    // 比较的推荐用法
    System.out.println("compareTo:" + bigDecimal1.compareTo(bigDecimal2));

    // 比较是否等于0的用法
    BigDecimal bigDecimal3 = new BigDecimal("0.0");
    if (BigDecimal.ZERO.compareTo(bigDecimal3) == 0) {
      System.out.println("bigDecimal3 等于0");
    }
  }
}

// 输出结果如下
equals:false
compareTo:0
bigDecimal3 等于0

BigInteger

在 Java 中,Integer 和 Long 的最大值和最小值范围如下所示。

package com.chenpi;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/25
 */
public class ChenPi {

  public static void main(String[] args) {

    int mini = Integer.MIN_VALUE;
    int maxi = Integer.MAX_VALUE;
    System.out.println(mini + " ~ " + maxi);
    System.out.println(Integer.toBinaryString(mini) + " ~ " + Integer.toBinaryString(maxi));

    long minl = Long.MAX_VALUE;
    long maxl = Long.MIN_VALUE;
    System.out.println(minl + " ~ " + maxl);
    System.out.println(Long.toBinaryString(minl) + " ~ " + Long.toBinaryString(maxl));
  }
}

// 输出结果如下
-2147483648 ~ 2147483647
10000000000000000000000000000000 ~ 1111111111111111111111111111111

9223372036854775807 ~ -9223372036854775808
111111111111111111111111111111111111111111111111111111111111111 ~ 1000000000000000000000000000000000000000000000000000000000000000

但如果我们想表示的数字超过这个范围的话,可以使用 BigInteger 类型,它可以表示更大范围的整数。

package com.chenpi;

import java.math.BigInteger;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/25
 */
public class ChenPi {

  public static void main(String[] args) {

    BigInteger bigInteger1 = new BigInteger("922337203685477580711");
    BigInteger bigInteger2 = new BigInteger("922337203685477580722");

    // 加
    System.out.println(bigInteger1.add(bigInteger2));
    // 减
    System.out.println(bigInteger1.subtract(bigInteger2));
    // 乘
    System.out.println(bigInteger1.multiply(bigInteger2));
    // 除
    System.out.println(bigInteger1.divide(bigInteger2));

  }
}

// 输出结果如下
1844674407370955161433
-11
850705917302346158504406205563945772653342
0

本次分享到此结束啦~~

如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。