Java BigDecimal詳解

1.引言

  float和double類型的主要設計目標是為了科學計算和工程計算。他們執行二進制浮點運算,這是為了在廣域數值范圍上提供較為精確的快速近似計算而精心設計的。然而,它們沒有提供完全精確的結果,所以不應該被用于要求精確結果的場合。但是,商業計算往往要求結果精確,這時候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.2 * 0.1);System.out.println(0.3 / 0.1);}

運行結果如下

? ?你認為你看錯了,但結果卻是是這樣的。問題在哪里呢?原因在于我們的計算機是二進制的。浮點數沒有辦法是用二進制進行精確表示。我們的CPU表示浮點數由兩個部分組成:指數和尾數,這樣的表示方法一般都會失去一定的精確度,有些浮點數運算也會產生一定的誤差。如:2.4的二進制表示并非就是精確的2.4。反而最為接近的二進制表示是?2.3999999999999999。浮點數的值實際上是由一個特定的數學公式計算得到的。

??????????其實java的float只能用來進行科學計算或工程計算,在大多數的商業計算中,一般采用java.math.BigDecimal類來進行精確計算。

2.BigDecimal構造方法

  1.public BigDecimal(double val) ???將double表示形式轉換為BigDecimal *不建議使用

  2.public BigDecimal(int val)  將int表示形式轉換成BigDecimal

  3.public BigDecimal(String val)  將String表示形式轉換成BigDecimal

為什么不建議采用第一種構造方法呢?來看例子

  public static void main(String[] args){BigDecimal bigDecimal = new BigDecimal(2);BigDecimal bDouble = new BigDecimal(2.3);BigDecimal bString = new BigDecimal("2.3");System.out.println("bigDecimal=" + bigDecimal);System.out.println("bDouble=" + bDouble);System.out.println("bString=" + bString);}

運行結果如下

為什么會出現這種情況呢?

?JDK的描述: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構造方法

?

double必須用作BigDecimal的源時,請使用Double.toString(double)轉成String,然后使用String構造方法,或使用BigDecimal的靜態方法valueOf,如下

public static void main(String[] args){BigDecimal bDouble1 = BigDecimal.valueOf(2.3);BigDecimal bDouble2 = new BigDecimal(Double.toString(2.3));System.out.println("bDouble1=" + bDouble1);System.out.println("bDouble2=" + bDouble2);}

結果如下

?

3.BigDecimal加減乘除運算

對于常用的加,減,乘,除,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 a = new BigDecimal("4.5");BigDecimal b = new BigDecimal("1.5");System.out.println("a + b =" + a.add(b));System.out.println("a - b =" + a.subtract(b));System.out.println("a * b =" + a.multiply(b));System.out.println("a / b =" + a.divide(b));}

運行結果

這里有一點需要注意的是除法運算divide.

?BigDecimal除法可能出現不能整除的情況,比如 4.5/1.3,這時會報錯java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

其實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的方向舍入

按照各自的需要,可傳入合適的第三個參數。四舍五入采用?ROUND_HALF_UP

?

需要對BigDecimal進行截斷和四舍五入可用setScale方法,例:

   public static void main(String[] args){BigDecimal a = new BigDecimal("4.5635");a = a.setScale(3, RoundingMode.HALF_UP);    //保留3位小數,且四舍五入
        System.out.println(a);}

*減乘除其實最終都返回的是一個新的BigDecimal對象,因為BigInteger與BigDecimal都是不可變的(immutable)的,在進行每一步運算時,都會產生一個新的對象
   public static void main(String[] args){BigDecimal a = new BigDecimal("4.5");BigDecimal b = new BigDecimal("1.5");a.add(b);System.out.println(a);  //輸出4.5. 加減乘除方法會返回一個新的BigDecimal對象,原來的a不變
}
 

4.總結

   (1)商業計算使用BigDecimal。

??????? (2)盡量使用參數類型為String的構造函數。

??????? (3)?BigDecimal都是不可變的(immutable)的,在進行每一步運算時,都會產生一個新的對象,所以在做加減乘除運算時千萬要保存操作后的值。

??????? (4)我們往往容易忽略JDK底層的一些實現細節,導致出現錯誤,需要多加注意。

?

?

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

轉載于:https://www.cnblogs.com/LeoBoy/p/6056394.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/397432.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/397432.shtml
英文地址,請注明出處:http://en.pswp.cn/news/397432.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Erlang庫 -- 有意思的庫匯總

抄自這里 首先,庫存在的目的大致可分為:1、提供便利2、盡可能解決一些痛點首先,我們先明確一下Erlang編程語言的一些痛點(偽痛點):1,單進程問題Erlang虛擬機屬于搶占式調度,搶占式調…

windows 串口編程 c語言,windows下C語言版串口發送程序(基于VS2017)

#include "tchar.h"#include int main(){/*****************************打開串口*************************************/HANDLE hCom;//全局變量,串口句柄hCom CreateFile(_T("COM3"),//COM3口GENERIC_READ | GENERIC_WRITE,//允許讀和寫0,/…

scikit-learn決策樹算法類庫使用小結

之前對決策樹的算法原理做了總結,包括決策樹算法原理(上)和決策樹算法原理(下)。今天就從實踐的角度來介紹決策樹算法,主要是講解使用scikit-learn來跑決策樹算法,結果的可視化以及一些參數調參的關鍵點。 1. scikit-learn決策樹算法類庫介紹…

3.js模式-策略模式

1. 策略模式 策略模式定義一系列的算法&#xff0c;把它們封裝起來&#xff0c;并且可以互相替換。 var strategies { isNonEmpty: function(value,errMsg){ if(value ){ return errMsg; } }, minLength:function(value,length,errMsg){ if(value.length < length){ retur…

c語言編寫程序求8,使用c語言編寫程式,實現計算1*2*3+4*5*6+7*8*9+……+28*29*30的值...

使用c語言編寫程式&#xff0c;實現計算1*2*34*5*67*8*9……28*29*30的值以下文字資料是由(歷史新知網www.lishixinzhi.com)小編為大家搜集整理后發布的內容&#xff0c;讓我們趕快一起來看一下吧&#xff01;使用c語言編寫程式&#xff0c;實現計算1*2*34*5*67*8*9……28*29*3…

PHP 正則表達式分割 preg_split 與 split 函數

為什么80%的碼農都做不了架構師&#xff1f;>>> preg_split() preg_ split() 函數用于正則表達式分割字符串。 語法&#xff1a; array preg_split( string pattern, string subject [, int limit [, int flags]] ) 返回一個數組&#xff0c;包含 subject 中沿著與…

簡單學C——第五天

結構體 首先明確&#xff0c;結構體是一種構造的數據類型&#xff0c;是一種由多個數據類型如 int&#xff0c;char&#xff0c;double&#xff0c;數組或者結構體......組成的類型,現在告訴大家如何定義一個結構體。在定義int整型變量時&#xff0c;大家肯定都知道 int a; 即…

C語言二叉樹實驗報告流程圖,二叉樹的建立與遍歷實驗報告(c語言編寫,附源代碼).doc...

二叉樹的建立與遍歷實驗報告(c語言編寫,附源代碼).doc第 1 頁&#xff0c;共 9 頁二叉樹的建立與遍歷實驗報告級 班 年 月 日 姓名 學號_ 1實驗題目建立一棵二叉樹&#xff0c;并對其進行遍歷(先序、中序、后序)&#xff0c;打印輸出遍歷結果。2需求分析本程序用 VC 編寫&#…

三角函數泰勒展開C語言,第六章-函數作業 ---三角函數泰勒級數展開式計算正弦函數值...

E201_06_02_正弦函數題目要求&#xff1a;按照三角函數泰勒級數展開式計算正弦函數值&#xff1a;,直到最后一項的絕對值小于106解題思路&#xff1a;1. 輸入弧度2. 確定初始化值3. 求階梯函數代碼&#xff1a;public class E201_06_02_正弦函數 {public static void main(Stri…

Codeforces Round #325 (Div. 2) B. Laurenty and Shop 前綴和

B. Laurenty and Shop Time Limit: 1 Sec Memory Limit: 256 MB 題目連接 http://codeforces.com/contest/586/problem/BDescription A little boy Laurenty has been playing his favourite game Nota for quite a while and is now very hungry. The boy wants to make sau…

python學習感悟第3節

在繼列表的學習之后&#xff0c;進行了元組的學習。元組和列表功能相似&#xff0c;只是元組不能進行修改&#xff0c;所以元組又叫只讀列表。 下面列舉的是一系列的字符串操作&#xff1a; name.capitalize() #首字母大寫 name.count("a") #數列表中有幾個a name…

MyBatis_ibatis和mybatis的區別【轉】

1. ibatis3.*版本以后正式改名為mybaits&#xff0c;它也從apache轉到了google code下&#xff1b;也就是說ibatis2.*&#xff0c;mybatis3.*。2. 映射文件的不同ibatis的配置文件如下<?xml version"1.0" encoding"UTF-8" ?><!DOCTYPE sqlMapCo…

android gallery自動播放,可循環顯示圖像的Android Gallery組件

類型&#xff1a;源碼相關大小&#xff1a;23.6M語言&#xff1a;中文 評分&#xff1a;9.1標簽&#xff1a;立即下載第 4 頁 實現循環顯示圖像的Gallery組件實現循環顯示圖像的Gallery組件在本節將組出與循環顯示圖像相關的ImageAdapter類的完整代碼。讀者可以從中看到上一節介…

docker內程序如何讀取dockerfile和compose.yml中設置的環境變量

docker內程序如何讀取dockerfile和compose.yml中設置的環境變量 背景 compose文件中配置了服務A和服務B&#xff0c;其中B服務調用了A服務的接口&#xff0c;那么B的實現代碼中該如何調用A的服務呢&#xff1f; 解決 compose文件中&#xff0c;服務B的配置加入A的接口&#xff…

2015年10月13日

關于掙錢&#xff0c;我覺得&#xff0c;只要興趣所在&#xff0c;能把事做好&#xff0c;錢自己就會來。收入上不去&#xff0c;往往是做的事情就不在高收入的那個區間&#xff0c;寫程序很難出富翁。說實話&#xff0c;外圍一天的消費可能就是你工資的好幾倍&#xff0c;不用…

Spring Boot Servlet

上一篇我們對如何創建Controller 來響應JSON 以及如何顯示數據到頁面中&#xff0c;已經有了初步的了解。 Web開發使用 Controller 基本上可以完成大部分需求&#xff0c;但是我們還可能會用到 Servlet、Filter、Listener、Interceptor 等等。 當使用spring-Boot時&#xff0c;…

基于相關性分析系統性能瓶頸

測試的過程中&#xff0c;難免需要會遇到一些性能瓶頸&#xff0c;那么就要求我們能夠分析出性能瓶頸&#xff0c;并給出解決方案。性能瓶頸很抽象&#xff0c;我們可以通過數據使其具象。以我工作內容為例&#xff0c;服務器處理數據的能力是有限的&#xff0c;那么其處理的邊…

curl網站開發指南

curl網站開發指南 作者&#xff1a; 阮一峰 日期&#xff1a; 2011年9月 4日 我一向以為&#xff0c;curl只是一個編程用的函數庫。 最近才發現&#xff0c;這個命令本身&#xff0c;就是一個無比有用的網站開發工具&#xff0c;請看我整理的它的用法。 curl網站開發指南 阮一…

android格式化時間中文版,Android 仿微信聊天時間格式化顯示功能

本文給大家分享android仿微信聊天時間格式化顯示功能。在同一年的顯示規則&#xff1a;如果是當天顯示格式為 HH:mm 例&#xff1a;14:45如果是昨天,顯示格式為 昨天 HH:mm 例&#xff1a;昨天 13:12如果是在同一周 顯示格式為 周一 HH:mm 例&#xff1a;周一14:05如果不是同一…

java分享第十七天-01(封裝操作xml類)

做自動化測試的人&#xff0c;都應該對XPATH很熟悉了&#xff0c;但是在用JAVA解析XML時&#xff0c;我們通常是一層層的遍歷進去&#xff0c;這樣的代碼的局限性很大&#xff0c;也不方便&#xff0c;于是我們結合一下XPATH&#xff0c;來解決這個問題。所需要的JAR包&#xf…