首页 > 编程语言 >【Java基础面试题043】BigDecimal为什么能保证精度不丢失?

【Java基础面试题043】BigDecimal为什么能保证精度不丢失?

时间:2024-12-25 09:27:37浏览次数:6  
标签:舍入 面试题 scale Java BigDecimal 0.1 浮点数 0.2

回答重点

BigDecimal使用十进制来表示数值,而不是二进制浮点数表示法,这使得它能够精确地表示所有十进制数值,不需要任何转换或舍入。

而且BigDecimal是无限精度,可以表示任意精度的小数(受限于内存),因此不会动不动被舍入截断,也可以手动设置精度和舍入模式来控制计算的精度

BigDecimal内部使用两个字段存储数字,一个是整数部分intVal,另一个用来表示小数点的位置scale,避免了浮点数转化过程中可能的精度丢失

计算时通过整数计算,再结合小数点位置和设置的精度与舍入行为,控制结果精度,避免了有默认浮点数舍入导致的误差

简化版:

public class BigDecimal extends Number implements Comparable<BigDecimal> {
    private final BigInteger intVal;  // 存储整数部分
    private final int scale;          // 存储小数点的位置

    public BigDecimal(String val) {
        // 使用 BigInteger 来表示数值
        intVal = new BigInteger(val.replace(".", ""));
        scale = val.contains(".") ? val.length() - val.indexOf(".") - 1 : 0;
    }
}

例如:

BigDecimal bigDecimal = new BigDecimal(11.123);

inVal存储11122999999999332 ...

scale存储49,因为小数后有49位

如果是另外两种创建对象的方式,经过断点调试,inVal的值是null,scale是3

扩展知识

浮点数精度丢失的原因

  • 二进制浮点数表示:
    • Java使用IEEE 754标准来表示浮点数,这个标准用二进制来表示小数
    • 但有些十进制小数在二进制下是无限不循环小数(例如0.1在二进制中是0.0001100110011...),因此需要被截断或四舍五入
  • 有限的表示范围:
    • floatdouble都有固定的大小(float是32位,double是64位),这限制了它们能表示的精度和范围。有些数字在这些有限的位数内无法精确表示。
  • 舍入误差:
    • 由于浮点数的表示方式,进行算术运算时,可能会产生舍入误差。例如,0.1 + 0.2在理论上应该等于0.3,但在浮点数运算中可能得到0.30000000000000004

0.1 * 0.2

public class FloatPrecisionExample {
    public static void main(String[] args) {
        double a = 0.1;
        double b = 0.2;
        System.out.println(a * b); // 输出 0.020000000000000004
    }
}

由于double底层是二进制来表示十进制小数,不过double并不能精确表示0.1,0.2,所以0.1 * 0.2自然就产生了微笑的误差

使用BigDecimal

import java.math.BigDecimal;

public class BigDecimalPrecisionExample {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("0.1");
        BigDecimal b = new BigDecimal("0.2");
        System.out.println(a.multiply(b));  // 输出 0.02
    }
}

0.1 * 0.2底层大概是这么处理的:

0.1:intVal = 1        scale = 1

0.2:intVal = 2        scale = 1

先1 x 2 = 2

再标小数点位置2 -> 0.02

标签:舍入,面试题,scale,Java,BigDecimal,0.1,浮点数,0.2
From: https://blog.csdn.net/lklalmq/article/details/144706756

相关文章

  • 【Java基础面试题046】Java中的注解原理是什么?
    注解其实就是一个标记,是一种提供元数据的机制,用于给代码添加说明信息。可以标记在类上、方法上、属性上等,标记自身也可以设置一些值。注解本身不影响程序的逻辑执行,但可以通过工具或框架来利用这些信息进行特定的处理,如代码生成、编译时检查、运行时处理等。扩展知识自定义......
  • 面向对象程序设计JAVA学习总结
    第一章“初识JAVA与面向对象程序设计”廖利凯1、JAVA概述1.1计算机编程语言发展史机器语言:由微处理器理解和使用的二进制代码,是第一代编程语言,如0001111111101111等,直接控制硬件操作,但难记且不通用。汇编语言:用英文单词指令编写程序,是第二代编程语言,如MOVAX,1等,相比机......
  • JAVA期末通讯录
    写了挺久的,来CSDN记录一下应用软件:mysql,idea--------------------------------------------------------第一步:连接数据库直接去哔哩哔哩上面找mysql下载,下载完了之后我自身没有配什么环境,直接找的mysql怎么跟idea连接视频先用idea把mysql连接了之后再去看的mysql......
  • Java多态--上转型对象
    Java多态概念实现方式上转型对象概念多态:面向对象的三大特性之一多态一句话概括就是,一个类下面的不同子类的实例,对同一个参数输入,得到不同的输出举例:动物类下的小猫、小狗,两只动物分别拍一下,小猫输出“喵喵喵”,小狗输出“汪汪汪”。实现方式多态的方式:类的继承,方......
  • Java 变量和运算符
    Java变量和运算符1.变量(Variable)1.1何为变量1.2数据类型(DataTypes)1.2.1整型:byte、short、int、long1.2.2浮点类型:float、double1.2.3字符类型:char1.2.4布尔类型:boolean1.3变量的使用1.3.1步骤1:变量的声明1.3.2步骤2:变量的赋值1.4.基本数据类型变......
  • 直击要害!Java反序列化
                                 免责声明本系列工具仅供安全专业人员进行已授权环境使用,此工具所提供的功能只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用工具中的......
  • Java设计模式 —— 【结构型模式】组合模式(透明组合模式、安全组合模式)详解
    文章目录一、概述二、结构三、案例实现四、安全组合模式五、优缺点一、概述组合模式又名整体-部分模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形......
  • Java中的五种引用方式底层详解
        在GC算法的可达性算法中描述的对象引用,一般指的是强引用,即是GCRoot对象对普通对象有引用关系,只要这层关系存在,普通对象就不会被回收,而在Java中一共有五种引用关系。目录 强引用 (Strong Reference)软引用 (SoftReference)使用软引用实现简单缓存 一个实......
  • JAVA面向对象(二)封装
    数据的守护者封装是面向对象编程的重要特性之一,它将数据和操作数据的方法紧密地结合在一起,并对外部隐藏了数据的具体实现细节。这样做的好处是多方面的。一方面,它保护了数据的完整性。例如,在Person类中,如果我们直接将age成员变量暴露给外部,那么可能会出现不合理的赋值情况,比如设......
  • JavaDay2
    JavaDay2选择结构Switchpackageshujia.day02.ketang;importjava.util.Scanner;/*Switch选择语句:语句定义格式:switch(表达式){case常量值1:表达式1;break;case......