float、double类型的问题

我们都知道,计算机是使用二进制存储数据的。而平常生活中,大多数情况下我们都是使用的十进制,因此计算机显示给我们看的内容大多数也是十进制的,这就使得很多时候数据需要在二进制与十进制之间进行转换。对于整数来说,两种进制可以做到一一对应。而对于小数来讲就不是这样的啦。

我们先来看看十进制小数转二进制小数的方法

对小数点以后的数乘以2,会得到一个结果,取结果的整数部分(不是1就是0),然后再用小数部分再乘以2,再取结果的整数部分……以此类推,直到小数部分为0或者位数已经够了。顺序取每次运算得到的整数部分,即为转换后的小数部分。

演示:

0.125 ×2=0.25 .......................0

0.25×2=0.5.............................0

0.5×2=1.0................................1

即 0.125的二进制表示为小数部分为0.001

其实我们可以看出,这种方法实质上就是用1/2,1/4,8/1...来组合加出我们要转换的数据值,但显然不是所有的数都能够组合出来的。如0.1。

0.1×2=0.2 .....................0

0.2×2=0.4 ......................0

0.4×2=0.8 .....................0

0.8×2=1.6.......................1

0.6×2=1.2.......................1

0.2×2=0.4.......................0

.....

从上述计算过程我们可以看出,这是个无限小数,所以在这种情况下我们的float、double只能舍去一些位。

那为什么我们在直接给float赋值在输出时没有看到精度损失而在运算时却会出现呢?

确实是这样,如下

float a = 0.2f;

System.out.println(a);

//输出0.2

对于上述情况我只是查了资料,好像是因为编译器会进行优化,当我们存储的数据特别接近的时候,编译器会很贴心的返回我们想看到的数值(即二进制浮点数并不能准确的表示0.1这个十进制小数,它使用了0.100000001490116119384765625来代替0.1。),至于到了运算中,就会出现精度损失较大从而看到了真相。如果这块说的不对欢迎小伙伴们在评论区指正!

解决方法

BigDecimal 原理

我们一般会使用

BigDecimal 来避免出现精度丢失问题,至于为什么BigDecimal 可以避免,而float或double不行,我们在此不详细讨论,简单来说就是BigDecimal 通过借助整数来表示小数的方式,因为对于整数而言,二进制和十进制是完全一一对应的,用整数来表示小数,再记录下小数的位数,就可以完美的解决该问题。

BigDecimal 用法

java.math.BinInteger 类和 java.math.BigDecimal 类都是Java提供的用于高精度计算的类.其中 BigInteger 类是针对大整数的处理类,而 BigDecimal 类则是针对大小数的处理类.

BigDecimal构造方法

BigDecimal BigDecimal(double d); //不允许使用

BigDecimal BigDecimal(String s); //常用,推荐使用

static BigDecimal valueOf(double d); //常用,推荐使用

double 参数的构造方法,不允许使用!!!!因为它不能精确的得到相应的值;

String 构造方法是完全可预知的: 写入 new BigDecimal("0.1") 将创建一个 BigDecimal,它正好等于预期的0.1; 因此,通常建议优先使用 String 构造方法;

静态方法 valueOf(double val) 内部实现,仍是将 double 类型转为 String 类型; 这通常是将 double(或float)转化为 BigDecimal 的首选方法;

测试

System.out.println(new BigDecimal(0.1));

System.out.println(BigDecimal.valueOf(0.1));

\\输出*****************************************

0.1000000000000000055511151231257827021181583404541015625

0.1

BigDecimal常用操作

我们通过一个工具类源码来体会BigDecimal的常规用法

package com.util;

import java.math.BigDecimal;

/**

* 提供精确的浮点数运算(包括加、减、乘、除、四舍五入)工具类

*/

public class ArithUtil {

// 除法运算默认精度

private static final int DEF_DIV_SCALE = 10;

private ArithUtil() {

}

/**

* 精确加法

*/

public static double add(double value1, double value2) {

BigDecimal b1 = BigDecimal.valueOf(value1);

BigDecimal b2 = BigDecimal.valueOf(value2);

return b1.add(b2).doubleValue();

}

/**

* 精确减法

*/

public static double sub(double value1, double value2) {

BigDecimal b1 = BigDecimal.valueOf(value1);

BigDecimal b2 = BigDecimal.valueOf(value2);

return b1.subtract(b2).doubleValue();

}

/**

* 精确乘法

*/

public static double mul(double value1, double value2) {

BigDecimal b1 = BigDecimal.valueOf(value1);

BigDecimal b2 = BigDecimal.valueOf(value2);

return b1.multiply(b2).doubleValue();

}

/**

* 精确除法 使用默认精度

*/

public static double div(double value1, double value2) throws IllegalAccessException {

return div(value1, value2, DEF_DIV_SCALE);

}

/**

* 精确除法

* @param scale 精度

*/

public static double div(double value1, double value2, int scale) throws IllegalAccessException {

if(scale < 0) {

throw new IllegalAccessException("精确度不能小于0");

}

BigDecimal b1 = BigDecimal.valueOf(value1);

BigDecimal b2 = BigDecimal.valueOf(value2);

// return b1.divide(b2, scale).doubleValue();

return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();

}

/**

* 四舍五入

* @param scale 小数点后保留几位

*/

public static double round(double v, int scale) throws IllegalAccessException {

return div(v, 1, scale);

}

/**

* 比较大小

*/

public static boolean equalTo(BigDecimal b1, BigDecimal b2) {

if(b1 == null || b2 == null) {

return false;

}

return 0 == b1.compareTo(b2);

}

}

标签:Java,运算,double,valueOf,b1,b2,小数,BigDecimal

来源: https://www.cnblogs.com/wunsiang/p/12811661.html

java小数丢失精度_Java中的小数运算与精度损失相关推荐

  1. Java程序和MySQL数据库中关于小数的保存问题

    文章目录 MySQL 中的小数类型 decimal double float Java 中的小数类型 float double BigDecimal 金额的计算 MySQL 中的小数类型 decima ...

  2. java string 精度_Java 中的浮点数取精度方法

    1 packagecn.com.cxsw.utils;2 3 importjava.math.BigDecimal;4 5 /** 6 * 与小数位精度(四舍五入等)相关的一些常用工具方法.7 *8 ...

  3. java取模负数_JAVA中取模的问题

    ## Java取模(%)运算 > [上篇文章](https://yebukong.com/article/1101070795486109697.html "上篇文章") 提 ...

  4. java中大数开方_Java中的大数运算

    # 一:大数运算出现的背景 java里面整型int与浮点型float,double它们存放数据的范围是有限的,当出行更大的数值时会发生溢出. 最典型的场景是金融行业,直接使用单精度或者双精浮点数来表示 ...

  5. java double 取余_java中double除法和取余的若干注意

    1 整数除法中,除数为0,抛出一个算术异常ArithmeticException.整数取余运算中,除数为0,抛出一个ArithmeticException异常. 如: class Test { pub ...

  6. java的原生数据类型_Java中的8种原生数据类型(Primitive Data Types)分析

    八种数据类型 类型 int short long byte float double char boolean 字节数 4 2 8 1 4 8 4 JVM相关 大小 -2147483648~21474 ...

  7. java可以多重继承吗_Java中的多重继承与组合vs继承

    java可以多重继承吗 有时我写了几篇有关Java继承,接口和组成的文章. 在这篇文章中,我们将研究多重继承,然后了解组成优于继承的好处. Java中的多重继承 多重继承是创建具有多个超类的单个类的能 ...

  8. java中有没有栈_Java中堆和栈有什么区别

    stack 和 heep 都是内存的一部分stack 空间小,速度比较快, 用来放对象的引用heep 大,一般所有创建的对象都放在这里.栈(stack):是一个先进后出的数据结构,通常用于保存方法(函 ...

  9. java 基本类型 引用_java中 引用类型 和 基本类型 有何区别?

    栈与堆都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. Java的堆是一个运行时数据区,类的(对象从中分配空间.这些对象通过new.newa ...

最新文章

  1. Linux设备驱动Hello World程序介绍
  2. 零基础Java学习之this关键字
  3. 好品山东谋定产业扶贫-农业大健康·万祥军:乡村振兴行动
  4. 全国人工智能大赛 行人重识别(Person ReID)赛项 季军团队方案分享
  5. 查看oracle连接客户端
  6. html修改图片宽度高度,HTML基础 img width height 设置显示图片的高度和宽度
  7. sql not exists用法_SQL Server 2012 高级用法(一)
  8. 极光推送 java api_JPush极光推送Java服务器端API
  9. 关于redis的持久化
  10. 白板推导系列Pytorch-隐马尔可夫模型(HMM)
  11. ies文件 vray_光域网ies文件免费
  12. 2022年jsonpath的超详细介绍以及在爬取移动端app上的灵活运用
  13. reg类型变量综合电路_Verilog中 reg和wire 用法和区别以及always和assign的区别
  14. 简单易用的C/C++ 图像库 stb_image stb_image_write
  15. pyth命令_如何:在Windows上设置用于从命令行运行.py文件的Python可执行文件
  16. 人工智能如何改变联络中心座席
  17. dolphinschedule2.0.5升级dolphinschedule3.1.1
  18. java的自省机制_JAVA内省(自省)机制 ( Introspector , BeanInfo, PropertyDescriptor )
  19. html中repeat的作用,repeat-y
  20. 2PC、3PC、TCC

热门文章

  1. 运营商数据治理实践-郭岳
  2. 使用nagios监控某进程的运行状态
  3. Android 给TextView中的字体加上“中间线”
  4. 转载构造函数与拷贝构造函数
  5. Basic Oracle Net Services Client-Side Configuration
  6. Linux 生产者消费者简单例子学习
  7. Spring结合Quartz实现多任务定时调用(转载)
  8. Windows一些操作
  9. 『教程』笔记本win7下自建Wifi热点–便于手机Wifi上网 (转 )
  10. 一本计划中的WPF图书目录