John Squirrels
ระดับ
San Francisco

BigDecimal ใน Java

เผยแพร่ในกลุ่ม
สวัสดี! ในบทเรียนวันนี้ เราจะพูดถึงตัวเลขจำนวนมาก ไม่ ฉันหมายถึงใหญ่จริงๆ ก่อนหน้านี้เราพบตารางช่วงค่าสำหรับประเภทข้อมูลดั้งเดิมซ้ำแล้วซ้ำอีก ดูเหมือนว่า:
ประเภทดึกดำบรรพ์ ขนาดในหน่วยความจำ ช่วงค่า
ไบต์ 8 บิต -128 ถึง 127
สั้น 16 บิต -32768 ถึง 32767
ถ่าน 16 บิต 0 ถึง 65536
นานาชาติ 32 บิต -2147483648 ถึง 2147483647
ยาว 64 บิต -9223372036854775808 ถึง 9223372036854775807
ลอย 32 บิต (2 ยกกำลัง -149) ถึง ((2 ยกกำลัง -23) * 2 ยกกำลัง 127)
สองเท่า 64 บิต (-2 ยกกำลัง 63) ถึง ((2 ยกกำลัง 63) - 1)
บูลีน 8 (เมื่อใช้ในอาร์เรย์), 32 (เมื่อไม่ได้ใช้ในอาร์เรย์) จริงหรือเท็จ
ชนิดข้อมูลจำนวนเต็มที่มากที่สุดคือlong เมื่อพูดถึงตัวเลขทศนิยม มันคือdouble . แต่ถ้าจำนวนที่เราต้องการมีขนาดใหญ่จนไม่พอดีกับความยาว ? ชนิดข้อมูลแบบยาวมีค่าที่เป็นไปได้ค่อนข้างมาก แต่ก็ยังจำกัดไว้ที่ 64 บิต เราต้องคิดอย่างไรหาก Very Large Number ของเราต้องใช้ 100 บิต โชคดีที่เราไม่ต้องคิดค้นอะไรเลย สำหรับกรณีเช่นนี้ Java มีคลาสพิเศษสองคลาส: BigInteger (สำหรับจำนวนเต็ม) และBigDecimal(สำหรับเลขทศนิยม). อะไรทำให้พวกเขาพิเศษ? ประการแรก ตามทฤษฎีแล้ว พวกมันไม่มีขนาดสูงสุด เราพูดว่า "ในทางทฤษฎี" เพราะไม่มีคอมพิวเตอร์ที่มีหน่วยความจำไม่สิ้นสุด และถ้าโปรแกรมของคุณสร้างตัวเลขที่มากกว่าจำนวนหน่วยความจำที่มีอยู่ แน่นอนว่าโปรแกรมจะไม่ทำงาน แต่กรณีดังกล่าวไม่น่าเป็นไปได้ ด้วยเหตุนี้ เราจึงสามารถพูดได้ว่าBigIntegerและBigDecimalสามารถแสดงจำนวนที่ไม่จำกัดขนาด คลาสเหล่านี้ใช้สำหรับอะไร ประการแรก สำหรับการคำนวณที่ต้องการความแม่นยำที่เข้มงวดมาก ตัวอย่างเช่น ชีวิตมนุษย์อาจขึ้นอยู่กับความแม่นยำของการคำนวณในบางโปรแกรม (เช่น ซอฟต์แวร์ที่ควบคุมเครื่องบิน จรวด หรืออุปกรณ์ทางการแพทย์) ดังนั้นหากทศนิยมตำแหน่งที่ 150 มีความสำคัญ ดังนั้นBigDecimalเป็นทางเลือกที่ดีที่สุด นอกจากนี้ วัตถุในชั้นนี้มักถูกใช้ในโลกของการเงิน ซึ่งการคำนวณที่ถูกต้องแม้แต่ค่าที่น้อยที่สุดก็มีความสำคัญอย่างยิ่งเช่นกัน คุณทำงานกับ วัตถุBigIntegerและBigDecimalอย่างไร และคุณจำเป็นต้องรู้เกี่ยวกับสิ่งเหล่านี้หรือไม่ วัตถุของคลาสเหล่านี้ถูกสร้างขึ้นดังนี้:
public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
การส่งสตริงไปยังตัวสร้างเป็นเพียงตัวเลือกเดียวที่เป็นไปได้ ที่นี่เราใช้สตริงเนื่องจากตัวเลขของเราเกินค่าสูงสุดสำหรับlongและdoubleและเราต้องการวิธีอธิบายให้คอมไพเลอร์ทราบว่าเราต้องการสร้างหมายเลขใด :) เพียงแค่ส่งหมายเลข 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 ให้กับตัวสร้างจะไม่ทำงาน: Java จะพยายามยัดหมายเลขที่ส่งผ่านไปยังหนึ่งในประเภทข้อมูลดั้งเดิม แต่จะไม่พอดีกับประเภทใดเลย นั่นเป็นเหตุผลที่การใช้สตริงเพื่อส่งหมายเลขที่ต้องการจึงเป็นตัวเลือกที่ดี ทั้งสองคลาสสามารถแยกค่าตัวเลขจากสตริงที่ส่งผ่านได้โดยอัตโนมัติ จุดสำคัญอีกประการที่ต้องจำเมื่อทำงานกับคลาสที่มีจำนวนมากคือ คุณคุ้นเคยกับการเปลี่ยนแปลงไม่ได้แล้ว เนื่องจากประสบการณ์ของคุณกับ คลาส Stringและคลาส wrapper สำหรับประเภทดั้งเดิม (Integer, Long เป็นต้น)
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
เอาต์พุตคอนโซล:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
อย่างที่คุณคาดไว้ หมายเลขของเราไม่เปลี่ยนแปลง คุณต้องสร้างวัตถุใหม่เพื่อรับผลลัพธ์ของการดำเนินการ
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
เอาต์พุตคอนโซล:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
ดูสิตอนนี้ทุกอย่างทำงานได้ตามปกติ :) คุณสังเกตเห็นว่าการดำเนินการเพิ่มมีลักษณะผิดปกติหรือไม่?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
นี่เป็นอีกจุดสำคัญ คลาสตัวเลขจำนวนมากไม่ใช้ตัวดำเนินการ + - * / แต่จะมีชุดของวิธีการแทน มาทำความคุ้นเคยกับวิธีหลัก (เช่นเคย คุณสามารถดูรายการวิธีการทั้งหมดได้ในเอกสารประกอบของ Oracle: ที่นี่และที่นี่ )
  1. วิธีการดำเนินการทางคณิตศาสตร์: บวก() , ลบ() , คูณ() , หาร( ) วิธีการเหล่านี้ใช้ในการบวก ลบ คูณ และหารตามลำดับ

  2. doubleValue() , intValue() , floatValue() , longValue()ฯลฯ ใช้เพื่อแปลงตัวเลขจำนวนมากเป็นประเภทดั้งเดิมของ Java ระมัดระวังเมื่อใช้วิธีการเหล่านี้ อย่าลืมเกี่ยวกับความแตกต่างของขนาดบิต!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }

    เอาต์พุตคอนโซล:

    8198552921648689607
  3. min()และmax()ช่วยให้คุณหาค่าต่ำสุดและค่าสูงสุดของตัวเลขขนาดใหญ่สองตัวได้
    โปรดทราบว่าวิธีการเหล่านี้ไม่คงที่!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }

    เอาต์พุตคอนโซล:

    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

ลักษณะการปัดเศษ BigDecimal

หัวข้อนี้มีส่วนแยกต่างหาก เนื่องจากการปัดเศษตัวเลขจำนวนมากและการกำหนดค่าลักษณะการปัดเศษนั้นไม่ง่ายนัก คุณสามารถใช้ เมธอด setScale ()เพื่อกำหนดจำนวนตำแหน่งทศนิยมสำหรับBigDecimal ตัวอย่างเช่น สมมติว่าเราต้องการให้หมายเลข111.5555555555มีตัวเลขหลังจุดทศนิยมสามหลัก อย่างไรก็ตาม เราไม่สามารถบรรลุสิ่งที่ต้องการได้โดยการส่งเลข 3 เป็นอาร์กิวเมนต์ไปยังเมธอดsetScale () ตามที่กล่าวไว้ข้างต้นBigDecimalมีไว้สำหรับแสดงตัวเลขที่มีข้อกำหนดเข้มงวดเกี่ยวกับความแม่นยำในการคำนวณ ในรูปแบบปัจจุบัน ตัวเลขของเรามี 10 หลักหลังจุดทศนิยม เราต้องการทิ้ง 7 รายการและเก็บไว้เพียง 3 ดังนั้นนอกเหนือจากหมายเลข 3 แล้วเราต้องผ่านโหมดการปัดเศษ BigDecimalมีโหมดการปัดเศษทั้งหมด 8 โหมด เยอะมาก! แต่ถ้าคุณต้องการปรับความแม่นยำของการคำนวณอย่างละเอียดจริงๆ คุณจะมีทุกสิ่งที่คุณต้องการ ดังนั้นนี่คือโหมดการปัดเศษ 8 โหมดที่นำเสนอโดยBigDecimal :
  1. ROUND_CEILING — ปัดขึ้น

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN — ปัดเศษเป็นศูนย์

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR — ปัดลง

    111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555

  4. ROUND_HALF_UP — ปัดขึ้นถ้าตัวเลขหลังจุดทศนิยม >= 0.5

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN — ปัดขึ้นถ้าตัวเลขหลังจุดทศนิยม > 0.5

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN — การปัดเศษขึ้นอยู่กับตัวเลขทางซ้ายของจุดทศนิยม หากตัวเลขทางซ้ายเป็นเลขคู่ การปัดเศษจะลดลง หากตัวเลขทางด้านซ้ายของจุดทศนิยมเป็นเลขคี่ การปัดเศษก็จะเพิ่มขึ้น

    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2

    ตัวเลขทางซ้ายของทศนิยมคือ 2 (เลขคู่) ตัวเลขจะถูกปัดเศษลง เราต้องการทศนิยม 0 ตำแหน่ง ดังนั้นผลลัพธ์คือ 2

    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4

    ตัวเลขทางด้านซ้ายของจุดทศนิยมคือ 3 (เลขคี่) ตัวเลขจะถูกปัดเศษขึ้น เราต้องการทศนิยม 0 ตำแหน่ง ดังนั้นผลลัพธ์คือ 4

  7. ROUND_UNNECCESSARY — โหมดนี้ใช้เมื่อคุณต้องผ่านโหมดการปัดเศษไปยังเมธอด แต่ตัวเลขไม่จำเป็นต้องปัดเศษ หากคุณพยายามปัดเศษตัวเลขด้วยชุดโหมด ROUND_UNNECCESSARY ระบบจะส่ง ArithmeticException

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP — ปัดเศษออกจากศูนย์

    111.5551 -> setScale(3, ROUND_UP) -> 111.556

เทียบเบอร์ใหญ่

นี่เป็นสิ่งสำคัญเช่นกัน คุณจะจำได้ว่าเราใช้เท่ากับ ()วิธีการเปรียบเทียบวัตถุใน Java การใช้งานนั้นมาจากตัวภาษาเอง (สำหรับคลาส Java มาตรฐาน) หรือถูกแทนที่โดยโปรแกรมเมอร์ แต่ในกรณีของวัตถุBigDecimalไม่แนะนำให้ใช้วิธีการเท่ากับ () สำหรับการเปรียบเทียบ นี่เป็นเพราะ เมธอด BigDecimal.equals()คืนค่าจริงก็ต่อเมื่อตัวเลข 2 ตัวมีค่าและสเกลเท่ากัน ลองเปรียบเทียบพฤติกรรมของเมธอดเท่ากับ()สำหรับ คลาส DoubleและBigDecimal :
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));

   }
}
เอาต์พุตคอนโซล:
true
false
อย่างที่คุณเห็นสำหรับBigDecimalตัวเลข 1.5 และ 1.50 ไม่เท่ากัน! นี่เป็นเพราะความเฉพาะเจาะจงของการใช้ วิธี เท่ากับ ()ในคลาสBigDecimal สำหรับการเปรียบเทียบ วัตถุ BigDecimal สองวัตถุที่แม่นยำยิ่งขึ้น ควรใช้ วิธี การเปรียบเทียบถึง() :
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
เอาต์พุตคอนโซล:
0
วิธี การ เปรียบเทียบ ()คืนค่า 0 ซึ่งหมายความว่า 1.5 และ 1.50 เท่ากัน และนี่คือผลลัพธ์ที่เราคาดไว้! :) นั่นคือการสรุปบทเรียนของเราในวันนี้ ตอนนี้ได้เวลากลับไปทำงานแล้ว! :)
ความคิดเห็น
  • เป็นที่นิยม
  • ใหม่
  • เก่า
คุณต้องลงชื่อเข้าใช้เพื่อแสดงความคิดเห็น
หน้านี้ยังไม่มีความคิดเห็นใด ๆ