当前位置:首页 > Java技术 > java 小数 乘法

java 小数 乘法

2022年11月09日 23:16:57Java技术7

java.math.BigDecimal

概述

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。

双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中.

如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。

​BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/ 等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

BigDecimal常用构造函数

BigDecimal(int)

创建一个具有参数所指定整数值的对象

BigDecimal(double)

创建一个具有参数所指定双精度值的对象

BigDecimal(long)

创建一个具有参数所指定长整数值的对象

BigDecimal(String) 常用

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

使用示例:

BigDecimal a =new BigDecimal(0.1);

System.out.println("a values is:"+a);

System.out.println("=====================");

BigDecimal b =new BigDecimal("0.1");

System.out.println("b values is:"+b);

结果示例:

a values is:0.1000000000000000055511151231257827021181583404541015625

=====================

b values is:0.1

原因分析:

1)参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

2)String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言, 通常建议优先使用String构造方法。

3)当double必须用作BigDecimal的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double)方法,然后使用BigDecimal(String)构造方法,将double转换为String。要获取该结果,请使用static valueOf(double)方法。

BigDecimal常用方法详解

常用方法

add(BigDecimal)

BigDecimal对象中的值相加,返回BigDecimal对象

subtract(BigDecimal)

BigDecimal对象中的值相减,返回BigDecimal对象

multiply(BigDecimal)

BigDecimal对象中的值相乘,返回BigDecimal对象

divide(BigDecimal)

BigDecimal对象中的值相除,返回BigDecimal对象

toString()

将BigDecimal对象中的值转换成字符串

doubleValue()

将BigDecimal对象中的值转换成双精度数

floatValue()

将BigDecimal对象中的值转换成单精度数

longValue()

将BigDecimal对象中的值转换成长整数

intValue()

将BigDecimal对象中的值转换成整数

除法特记:

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

divisor 除数, scale 精确小数位, roundingMode 舍入模式

BigDecimal的8种舍入模式

BigDecimal resVal = new BigDecimal("0");

舍入方法:setScale(0,BigDecimal.ROUND_UP)第一个参数0表示舍入之后的小数位数,第二个参数表示舍入方式

1、ROUND_UP向上取整(正负远离零的舍入模式)

BigDecimal bdNum = new BigDecimal("23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_UP);

结果:24

BigDecimal bdNum = new BigDecimal("-23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_UP);

结果:-24

2、ROUND_DOWN向下取整(正负接近零的舍入模式)

BigDecimal bdNum = new BigDecimal("23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_DOWN);

结果:23

BigDecimal bdNum = new BigDecimal("-23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_DOWN);

结果:-23

3、ROUND_CEILING向大取整(比原数值大的方向) 如果 BigDecimal 为正,则舍入行为与 ROUND_UP 相同; 如果为负,则舍入行为与 ROUND_DOWN 相同。

BigDecimal bdNum = new BigDecimal("23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_CEILING);

结果:24

BigDecimal bdNum = new BigDecimal("-23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_CEILING);

结果:-23

4、ROUND_FLOOR向小取整(比原数值小的方向)如果 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同; 如果为负,则舍入行为与 ROUND_UP 相同。

BigDecimal bdNum = new BigDecimal("23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_FLOOR);

结果:23

BigDecimal bdNum = new BigDecimal("-23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_FLOOR);

结果:-24

5、ROUND_HALF_UP(四舍五入) 向“最接近的”数字舍入,如果舍弃部分 >= 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。

BigDecimal bdNum = new BigDecimal("23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_UP);

结果:23

BigDecimal bdNum = new BigDecimal("23.6693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_UP);

结果:24

BigDecimal bdNum = new BigDecimal("23.5");

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_UP);

结果:24

6、ROUND_HALF_DOWN(五舍六入) 向“最接近的”数字舍入,如果舍弃部分 <= 0.5,则舍入行为与 ROUND_DOWN 相同; 否则舍入行为与 ROUND_UP 相同。

BigDecimal bdNum = new BigDecimal("23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_DOWN);

结果:23

BigDecimal bdNum = new BigDecimal("23.6693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_DOWN);

结果:24

BigDecimal bdNum = new BigDecimal("23.5");

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_DOWN);

结果:23

7、ROUND_HALF_EVEN

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。 如果舍弃部分左边的数字为奇数,则舍入行为与 ROUND_HALF_UP 相同; 如果为偶数,则舍入行为与 ROUND_HALF_DOWN 相同。

四舍六入,五分两种情况。 如果前一位为奇数,则入位,否则舍去。

BigDecimal bdNum = new BigDecimal("23.3693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_EVEN);

结果:23

BigDecimal bdNum = new BigDecimal("23.6693");

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_EVEN);

结果:24

BigDecimal bdNum = new BigDecimal("23.5");// 如果与两个相邻数字的距离相等,则向相邻的偶数舍入

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_EVEN);

结果:24

BigDecimal bdNum = new BigDecimal("22.5");// 如果与两个相邻数字的距离相等,则向相邻的偶数舍入

resVal = bdNum.setScale(0, BigDecimal.ROUND_HALF_EVEN);

结果:22

8、ROUND_UNNECESSARY 断言请求的操作具有精确的结果,因此不需要舍入。 如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

BigDecimal bdNum = new BigDecimal("22.3368");

resVal = bdNum.setScale(4, BigDecimal.ROUND_UNNECESSARY);

结果:22.3368

BigDecimal bdNum = new BigDecimal("22.3368");

resVal = bdNum.setScale(0, BigDecimal.ROUND_UNNECESSARY);

结果:

Exception in thread "main" java.lang.ArithmeticException: Rounding necessary

at java.math.BigDecimal.commonNeedIncrement(BigDecimal.java:4148)

at java.math.BigDecimal.needIncrement(BigDecimal.java:4204)

at java.math.BigDecimal.divideAndRound(BigDecimal.java:4112)

at java.math.BigDecimal.setScale(BigDecimal.java:2452)

at com.example.demo622.Demo622ApplicationTests.main(Demo622ApplicationTests.java:213)

BigDecimal 平方根

BigDecimal bdNum1 = new BigDecimal(String.valueOf(Math.sqrt(4)));

结果:2.0

BigDecimal 幂次方

BigDecimal res = new BigDecimal("3").pow(2); // 3的2次方

结果: res = 9;

BigDecimal大小比较

java中对BigDecimal比较大小一般用的是bigdemical的compareTo方法

BigDecimal a = new BigDecimal ("1");

BigDecimal b = new BigDecimal ("2");

int val = a.compareTo(b);

System.out.println(val);

返回结果分析:

val = -1,表示a小于b;

若 val = 0 ,表示a等于b;

若 val = 1 ,表示a大于b;

BigDecimal总结

6.1、总结

在需要精确的小数计算时再使用BigDecimal,BigDecimal的性能比double和float差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用BigDecimal。

尽量使用参数类型为String的构造函数。

BigDecimal都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。

/**

* BigDecimal高精度数学计算

*/

public class ArithmeticUtils {

//默认除法运算精度

private static final int DEF_DIV_SCALE = 10;

/**

* 提供精确的加法运算

*

* @param v1 被加数

* @param v2 加数

* @return 两个参数的和

*/

public static double add(double v1, double v2) {

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

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

}

/**

* 提供精确的加法运算

*

* @param v1 被加数

* @param v2 加数

* @return 两个参数的和

*/

public static BigDecimal add(String v1, String v2) {

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v2);

return b1.add(b2);

}

/**

* 提供精确的加法运算

*

* @param v1 被加数

* @param v2 加数

* @param scale 保留scale 位小数

* @return 两个参数的和

*/

public static String add(String v1, String v2, int scale) {

if (scale < 0) {

throw new IllegalArgumentException(

"The scale must be a positive integer or zero");

}

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v2);

return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();

}

/**

* 提供精确的减法运算

*

* @param v1 被减数

* @param v2 减数

* @return 两个参数的差

*/

public static double sub(double v1, double v2) {

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

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

}

/**

* 提供精确的减法运算。

*

* @param v1 被减数

* @param v2 减数

* @return 两个参数的差

*/

public static BigDecimal sub(String v1, String v2) {

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v2);

return b1.subtract(b2);

}

/**

* 提供精确的减法运算

*

* @param v1 被减数

* @param v2 减数

* @param scale 保留scale 位小数

* @return 两个参数的差

*/

public static String sub(String v1, String v2, int scale) {

if (scale < 0) {

throw new IllegalArgumentException(

"The scale must be a positive integer or zero");

}

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v2);

return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();

}

/**

* 提供精确的乘法运算

*

* @param v1 被乘数

* @param v2 乘数

* @return 两个参数的积

*/

public static double mul(double v1, double v2) {

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

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

}

/**

* 提供精确的乘法运算

*

* @param v1 被乘数

* @param v2 乘数

* @return 两个参数的积

*/

public static BigDecimal mul(String v1, String v2) {

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v2);

return b1.multiply(b2);

}

/**

* 提供精确的乘法运算

*

* @param v1 被乘数

* @param v2 乘数

* @param scale 保留scale 位小数

* @return 两个参数的积

*/

public static double mul(double v1, double v2, int scale) {

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

return round(b1.multiply(b2).doubleValue(), scale);

}

/**

* 提供精确的乘法运算

*

* @param v1 被乘数

* @param v2 乘数

* @param scale 保留scale 位小数

* @return 两个参数的积

*/

public static String mul(String v1, String v2, int scale) {

if (scale < 0) {

throw new IllegalArgumentException(

"The scale must be a positive integer or zero");

}

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v2);

return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();

}

/**

* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到

* 小数点以后10位,以后的数字四舍五入

*

* @param v1 被除数

* @param v2 除数

* @return 两个参数的商

*/

public static double div(double v1, double v2) {

return div(v1, v2, DEF_DIV_SCALE);

}

/**

* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指

* 定精度,以后的数字四舍五入

*

* @param v1 被除数

* @param v2 除数

* @param scale 表示表示需要精确到小数点以后几位。

* @return 两个参数的商

*/

public static double div(double v1, double v2, int scale) {

if (scale < 0) {

throw new IllegalArgumentException("The scale must be a positive integer or zero");

}

BigDecimal b1 = new BigDecimal(Double.toString(v1));

BigDecimal b2 = new BigDecimal(Double.toString(v2));

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

}

/**

* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指

* 定精度,以后的数字四舍五入

*

* @param v1 被除数

* @param v2 除数

* @param scale 表示需要精确到小数点以后几位

* @return 两个参数的商

*/

public static String div(String v1, String v2, int scale) {

if (scale < 0) {

throw new IllegalArgumentException("The scale must be a positive integer or zero");

}

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v1);

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

}

/**

* 提供精确的小数位四舍五入处理

*

* @param v 需要四舍五入的数字

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

* @return 四舍五入后的结果

*/

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

if (scale < 0) {

throw new IllegalArgumentException("The scale must be a positive integer or zero");

}

BigDecimal b = new BigDecimal(Double.toString(v));

return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();

}

/**

* 提供精确的小数位四舍五入处理

*

* @param v 需要四舍五入的数字

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

* @return 四舍五入后的结果

*/

public static String round(String v, int scale) {

if (scale < 0) {

throw new IllegalArgumentException(

"The scale must be a positive integer or zero");

}

BigDecimal b = new BigDecimal(v);

return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();

}

/**

* 取余数

*

* @param v1 被除数

* @param v2 除数

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

* @return 余数

*/

public static String remainder(String v1, String v2, int scale) {

if (scale < 0) {

throw new IllegalArgumentException(

"The scale must be a positive integer or zero");

}

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v2);

return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();

}

/**

* 取余数 BigDecimal

*

* @param v1 被除数

* @param v2 除数

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

* @return 余数

*/

public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {

if (scale < 0) {

throw new IllegalArgumentException(

"The scale must be a positive integer or zero");

}

return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP);

}

/**

* 比较大小

*

* @param v1 被比较数

* @param v2 比较数

* @return 如果v1 大于v2 则 返回true 否则false

*/

public static boolean compare(String v1, String v2) {

BigDecimal b1 = new BigDecimal(v1);

BigDecimal b2 = new BigDecimal(v2);

int bj = b1.compareTo(b2);

boolean res;

if (bj > 0)

res = true;

else

res = false;

return res;

}

}

作者:weixin_39860636
来源链接:https://blog.csdn.net/weixin_39860636/article/details/114114886

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/69176.html

标签: BigDecimalJava
分享给朋友:

“java 小数 乘法” 的相关文章

Java空指针异常解决java.lang.NullPointerException解决心得

Java空指针异常解决java.lang.NullPointerException解决心得

今天做课设的时候运行程序报出以下错误 java.lang.NullPointerException 首先要理解的是此错误并不会在 程序中报错,只会在运行的时候报错。 是由于某个参数(集合,数组等数据)可能出现一个null值而导致后面的程序不能运行时...

Java 内存模型

Java 内存模型

📦 本文以及示例源码已归档在 javacore Java 内存模型(Java Memory Model),简称 JMM。 JVM 中试图定义一种 JMM 来屏蔽各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。...

JDBC连接时所犯错误1.字符集设置不合适2.连接MySQL8.0社区版时时区不一致3..包名不能以Java.命名4.驱动被弃用

Microsoft JDBC Driver 的主页为:https://msdn.microsoft.com/en-us/data/aa937724.aspx 下载所需驱动 今天连接时报了四次错,记录下来 1.java.sql.SQLException:...

冒泡排序的原理,思路,以及算法分析(Java实现)

冒泡排序的原理,思路,以及算法分析(Java实现)

冒泡排序 如果遇到相等的值不进行交换,那这种排序方式是稳定的排序方式。 1.原理:比较两个相邻的元素,将值大的元素交换到右边 2.思路:依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。 (1)第一次比较:首先比较第...

Java Web 工作技巧总结 16.8

Java Web 工作技巧总结 16.8

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! 四时不谢之兰,百节长青之竹,万古不败之石,千秋不变之人。 1. AOP – LOG 项目中,一个请求过来,一个响应回去。...

初探设计:Java继承何时用?怎么用?

初探设计:Java继承何时用?怎么用?

Writer      :BYSocket(泥沙砖瓦浆木匠) 一、回顾继承 常见的如下: 1、依赖(”uses-a“) 2、聚合(”has-a“) 3、继承(”is-a“)类...

java泛型通配符详解

java泛型通配符详解

前言 泛型带来的好处 泛型中通配符 常用的 T,E,K,V,? ?无界通配符 上界通配符 < ? extends E> 下界通配符 < ? super E>...

Java实现ModbusTCP通信

Java实现ModbusTCP通信

使用ModbusTCP实现和硬件设备通信 有问题可以私信和评论,看到会回复。 一个项目,需要用Java实现使用ModbusTCP和硬件设备通信 视频地址:https://www.bilibili.com/video/BV1cz4y1R7cg...

java synchronized详解

记下来,很重要。 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。      一、当两个并发线程访问同一个对象object中的这个synchronized(this)同...

Java反射机制

  往往当我们面对一项新的知识时,我们往往需要知道三个方面,它是什么,它能做什么,它比原有知识强在哪里,我们该怎么使用它。当你能够解决这些问题时,便意味着你已经对这项知识入门了。 一、是什么   Java Reflaction in Action有这么一句话,可以解释。反射...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。