java 基礎--8 種基本數據類型:整型、浮點型、布爾型、字符型 整型中 byte、short、int、long 的取值范圍 什么是浮點型?什么是單精度和雙精度?為什么不能用浮點型表示金額?


 一、8種基本數據類型(4整,2浮,1符,1布):

    整型:byte(最小的數據類型)、short(短整型)、int(整型)、long(長整型);

    浮點型:float(浮點型)、double(雙精度浮點型);

    字符型:char(字符型);

    布爾型:boolean(布爾型)。

二、整型中 byte、short、int、long 取值范圍

    byte:一個字節有8位,去掉符號位還有7位,正數為避免進位還要減1,因此byte的取值范圍為:-2^7 ~ (2^7-1),也就是 -128~127 之間。

    short:short用16位存儲,去掉符號位還有15位,正數為避免進位還要減1,因此short的取值范圍是:-2^15 ~ (2^15-1)。

    int:整型用32位存儲,去掉符號位還有31位,正數為避免進位還要減1,因此整型的取值范圍是 -2^31 ~ (2^31-1)。

    long:長整型用64位存儲,去掉符號位還有63位,正數為避免進位還要減1,因此長整型的取值范圍是 -2^63 ~ (2^63-1)。

三:浮點型數據

   浮點類型是指用於表示小數的數據類型。

單精度和雙精度的區別

    單精度浮點型float,用32位存儲,1位為符號位, 指數8位, 尾數23位,即:float的精度是23位,能精確表達23位的數,超過就被截取。

    雙精度浮點型double,用64位存儲,1位符號位,11位指數,52位尾數,即:double的精度是52位,能精確表達52位的數,超過就被截取。

    雙精度類型double比單精度類型float具有更高的精度,和更大的表示范圍,常常用於科學計算等高精度場合。

   浮點數與小數的區別:

    1)在賦值或者存儲中浮點類型的精度有限,float是23位,double是52位。

    2)在計算機實際處理和運算過程中,浮點數本質上是以二進制形式存在的。

    3)二進制所能表示的兩個相鄰的浮點值之間存在一定的間隙,浮點值越大,這個間隙也會越大。如果此時對較大的浮點數進行操作時,浮點數的精度問題就會產生,甚至出現一些“不正常"的現象。

 

為什么不能用浮點數來表示金額

先給出結論:金額用BigDecimal !!!

   1)精度丟失問題  

    從上面我們可以知道,float的精度是23位,double精度是63位。在存儲或運算過程中,當超出精度時,超出部分會被截掉,由此就會造成誤差。

    對於金額而言,舍去不能表示的部分,損失也就產生了。 

32位的浮點數由3部分組成:1比特的符號位,8比特的階碼(exponent,指數),23比特的尾數(Mantissa,尾數)。這個結構會表示成一個小數點左邊為1,以底數為2的科學計數法表示的二進制小數。浮點數的能表示的數據大小范圍由階碼決定,但是能夠表示的精度完全取決於尾數的長度。long的最大值是2的64次方減1,需要63個二進制位表示,即便是double,52位的尾數也無法完整的表示long的最大值。不能表示的部分也就只能被舍去了。對於金額,舍去不能表示的部分,損失也就產生了。
  了解了浮點數表示機制后,丟失精度的現象也就不難理解了。但是,這只是浮點數不能表示金額的原因之一。還有一個深刻的原因與進制轉換有關。十進制的0.1在二進制下將是一個無線循環小數。

eg:

public class MyTest {  
    public static void main(String[] args) {  
        float increment = 0.1f;  
        float expected = 1;  
        float sum = 0;  
        for (int i = 0; i < 10; i++) {  
            sum += increment;  
            System.out.println(sum);  
        }  

        if (expected == sum) {  
            System.out.println("equal");  
        } else {  
            System.out.println("not equal ");  
        }  
    }  
}  

輸出結果:

0.1  
0.2  
0.3  
0.4  
0.5  
0.6  
0.70000005  
0.8000001  
0.9000001  
1.0000001  
not equal   

 

   

2)進制轉換誤差

    從上面我們可以知道,在計算機實際處理和運算過程中,浮點數本質上是以二進制形式存在的。

    而十進制的0.1在二進制下將是一個無限循環小數,這就會導致誤差的出現。

    如果一個小數不是2的負整數次冪,用浮點數表示必然產生浮點誤差。

    換言之:A進制下的有限小數,轉換到B進制下極有可能是無限小數,誤差也由此產生。

金額計算不能用doube!!!!

金額計算不能用doube!!!!

金額計算不能用doube!!!!
金額計算必須用BigDecimal

    浮點數不精確的根本原因在於:尾數部分的位數是固定的,一旦需要表示的數字的精度高於浮點數的精度,那么必然產生誤差

    解決這個問題的方法是BigDecimal的類,這個類可以表示任意精度的數字,其原理是:用字符串存儲數字,轉換為數組來模擬大數,實現兩個數組的數學運算並將結果返回。

 

BigDecimal的使用要點:

    1、BigDecimal變量初始化——必須用傳入String的構造方法

BigDecimal num1 = new BigDecimal(0.005);//用數值轉換成大數,有誤差
BigDecimal num12 = new BigDecimal("0.005");//用字符串轉換成大數,無誤差

      因為:不是所有的浮點數都能夠被精確的表示成一個double 類型值,有些浮點數值不能夠被精確的表示成 double 類型值時,它會被表示成與它最接近的 double 類型的值,此時用它來初始化一個大數,會“先造成了誤差,再用產生了誤差的值生成大數”,也就是“將錯就錯”。

    2、使用除法函數在divide的時候要設置各種參數,要精確的小數位數和舍入模式,其中有8種舍入模式:

 

1、ROUND_UP

遠離零的舍入模式。

在丟棄非零部分之前始終增加數字(始終對非零舍棄部分前面的數字加1)。

注意,此舍入模式始終不會減少計算值的大小。


2、ROUND_DOWN

接近零的舍入模式。

在丟棄某部分之前始終不增加數字(從不對舍棄部分前面的數字加1,即截短)。

注意,此舍入模式始終不會增加計算值的大小。


3、ROUND_CEILING

接近正無窮大的舍入模式。

如果 BigDecimal 為正,則舍入行為與 ROUND_UP 相同;

如果為負,則舍入行為與 ROUND_DOWN 相同。

注意,此舍入模式始終不會減少計算值。


4、ROUND_FLOOR

接近負無窮大的舍入模式。

如果 BigDecimal 為正,則舍入行為與 ROUND_DOWN 相同;

如果為負,則舍入行為與 ROUND_UP 相同。

注意,此舍入模式始終不會增加計算值。


5、ROUND_HALF_UP

向“最接近的”數字舍入,如果與兩個相鄰數字的距離相等,則為向上舍入的舍入模式。

如果舍棄部分 >= 0.5,則舍入行為與 ROUND_UP 相同;否則舍入行為與 ROUND_DOWN 相同。

注意,這是我們大多數人在小學時就學過的舍入模式(四舍五入)。


6、ROUND_HALF_DOWN

向“最接近的”數字舍入,如果與兩個相鄰數字的距離相等,則為上舍入的舍入模式。

如果舍棄部分 > 0.5,則舍入行為與 ROUND_UP 相同;否則舍入行為與 ROUND_DOWN 相同(五舍六入)。


7、ROUND_HALF_EVEN

向“最接近的”數字舍入,如果與兩個相鄰數字的距離相等,則向相鄰的偶數舍入。

如果舍棄部分左邊的數字為奇數,則舍入行為與 ROUND_HALF_UP 相同;

如果為偶數,則舍入行為與 ROUND_HALF_DOWN 相同。

注意,在重復進行一系列計算時,此舍入模式可以將累加錯誤減到最小。

此舍入模式也稱為“銀行家舍入法”,主要在美國使用。

如果前一位為奇數,則入位,否則舍去。

以下例子為保留小數點1位,那么這種舍入方式下的結果。

1.15>1.2 1.25>1.2


8、ROUND_UNNECESSARY

斷言請求的操作具有精確的結果,因此不需要舍入。

如果對獲得精確結果的操作指定此舍入模式,則拋出ArithmeticException。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM