- 1 1. บทนำ
- 2 2. BigDecimal คืออะไร?
- 3 3. การใช้งานพื้นฐานของ BigDecimal
- 4 4. การใช้งานขั้นสูงของ BigDecimal
- 5 5. ข้อผิดพลาดทั่วไปและวิธีแก้ไข
- 6 6. ตัวอย่างการใช้งานจริง
- 7 7. Summary
- 8 8. FAQ: Frequently Asked Questions About BigDecimal
- 8.1 Q1. Why should I use BigDecimal instead of float or double?
- 8.2 Q2. What is the safest way to construct BigDecimal instances?
- 8.3 Q3. Why does divide() throw an exception?
- 8.4 Q4. What’s the difference between compareTo() and equals()?
- 8.5 Q5. How do I perform rounding?
- 8.6 Q6. Can I check decimal digits (scale)?
- 8.7 Q7. How should I handle null/empty input safely?
1. บทนำ
ปัญหาความแม่นยำในการคำนวณตัวเลขใน Java
ในโปรแกรมมิง Java การคำนวณตัวเลขจะถูกดำเนินการในแต่ละวัน ตัวอย่างเช่น การคำนวณราคาสินค้า การกำหนดภาษีหรือดอกเบี้ย — การดำเนินการเหล่านี้จำเป็นในแอปพลิเคชันหลายตัว อย่างไรก็ตาม เมื่อการคำนวณดังกล่าวถูกดำเนินการโดยใช้ประเภทจุดลอยตัวเช่น float หรือ double อาจเกิดข้อผิดพลาดที่ไม่คาดคิด
นี่เกิดขึ้นเพราะ float และ double แสดงค่าด้วย การประมาณแบบไบนารี ค่าดังกล่าวเช่น “0.1” หรือ “0.2” ซึ่งสามารถแสดงได้อย่างแม่นยำในทศนิยม ไม่สามารถแสดงได้อย่างแน่นอนในไบนารี — และผลลัพธ์คือ ข้อผิดพลาดเล็กน้อยสะสม
BigDecimal จำเป็นสำหรับการคำนวณทางการเงินหรือการคำนวณที่ต้องการความแม่นยำ
ข้อผิดพลาดดังกล่าวอาจร้ายแรงในสาขาเช่น การคำนวณทางการเงินและการคำนวณทางวิทยาศาสตร์/วิศวกรรมที่ต้องการความแม่นยำ ตัวอย่างเช่น ในการคำนวณบิล แม้แต่ความแตกต่าง 1 เยนก็สามารถนำไปสู่ปัญหาความน่าเชื่อถือ
นี่คือจุดที่คลาส BigDecimal ของ Java โดดเด่น BigDecimal สามารถ จัดการตัวเลขทศนิยมด้วยความแม่นยำที่กำหนดได้ และโดยการใช้แทน float หรือ double การคำนวณตัวเลขสามารถดำเนินการได้โดยไม่มีความผิดพลาด
สิ่งที่คุณจะได้รับจากบทความนี้
ในบทความนี้ เราจะอธิบายพื้นฐานของการใช้งาน BigDecimal ใน Java เทคนิคขั้นสูง รวมถึงข้อผิดพลาดทั่วไปและข้อควรระวังในลักษณะที่เป็นระบบ
นี่มีประโยชน์สำหรับผู้ที่ต้องการจัดการการคำนวณทางการเงินอย่างแม่นยำใน Java หรือกำลังพิจารณาการนำ BigDecimal มาใช้ในโครงการของตน
2. BigDecimal คืออะไร?
ภาพรวมของ BigDecimal
BigDecimal เป็นคลาสใน Java ที่ ช่วยให้ทำเลขคณิตศาสตร์ทศนิยมด้วยความแม่นยำสูง มันอยู่ในแพ็กเกจ java.math และถูกออกแบบมาโดยเฉพาะสำหรับ การคำนวณที่ไม่ยอมรับข้อผิดพลาด เช่น การคำนวณทางการเงิน/บัญชี/ภาษี
ด้วย float และ double ของ Java ค่าตัวเลขจะถูกเก็บไว้ในรูปแบบการประมาณแบบไบนารี — ซึ่งหมายความว่าทศนิยมเช่น “0.1” หรือ “0.2” ไม่สามารถแสดงได้อย่างแน่นอน ซึ่งเป็นแหล่งที่มาของข้อผิดพลาด ในทางตรงกันข้าม BigDecimal เก็บค่าด้วย การแสดงทศนิยมที่ใช้สตริง จึงยับยั้งข้อผิดพลาดจากการปัดเศษและการประมาณ
การจัดการตัวเลขด้วยความแม่นยำที่กำหนดได้
ลักษณะเด่นที่สุดของ BigDecimal คือ “ความแม่นยำที่กำหนดได้” ส่วนจำนวนเต็มและทศนิยมสามารถจัดการ ตัวเลขที่แทบจะไม่จำกัด ได้ในทางทฤษฎี โดยหลีกเลี่ยงการปัดเศษหรือการสูญเสียตัวเลขเนื่องจากข้อจำกัดของตัวเลข
ตัวอย่างเช่น ตัวเลขขนาดใหญ่ต่อไปนี้สามารถจัดการได้อย่างแม่นยำ:
BigDecimal bigValue = new BigDecimal("12345678901234567890.12345678901234567890");
การสามารถทำเลขคณิตศาสตร์ในขณะที่รักษาความแม่นยำเช่นนี้คือจุดแข็งหลักของ BigDecimal
กรณีการใช้งานหลัก
BigDecimal ถูกแนะนำในสถานการณ์เช่น:
- การคำนวณทางการเงิน — การคำนวณดอกเบี้ย อัตราภาษีในแอปทางการเงิน
- การประมวลผลจำนวนเงินในใบแจ้งหนี้ / ใบเสนอราคา
- การคำนวณทางวิทยาศาสตร์/วิศวกรรมที่ต้องการความแม่นยำสูง
- กระบวนการที่การสะสมระยะยาวทำให้เกิดการสะสมข้อผิดพลาด
ตัวอย่างเช่น ใน ระบบบัญชีและการคำนวณเงินเดือน — ซึ่งความแตกต่าง 1 เยนสามารถนำไปสู่ความสูญเสียใหญ่หรือข้อพิพาท — ความแม่นยำของ BigDecimal จำเป็น
3. การใช้งานพื้นฐานของ BigDecimal
วิธีสร้างอินสแตนซ์ BigDecimal
ต่างจากตัวเลขตัวอักษรตัวเลขปกติ BigDecimal ควรถูก สร้างจากสตริงโดยทั่วไป นี่เป็นเพราะค่าที่สร้างจาก double หรือ float อาจมีข้อผิดพลาดการประมาณแบบไบนารีอยู่แล้ว
แนะนำ (สร้างจาก String):
BigDecimal value = new BigDecimal("0.1");
หลีกเลี่ยง (สร้างจาก double):
BigDecimal value = new BigDecimal(0.1); // may contain error
วิธีการทำเลขคณิตศาสตร์
BigDecimal ไม่สามารถใช้กับตัวดำเนินการเลขคณิตศาสตร์ปกติ (+, -, *, /) แทนที่จะใช้ ต้องใช้วิธีการเฉพาะ
การบวก (add)
BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("2.3");
BigDecimal result = a.add(b); // 12.8
การลบ (ลบ)
BigDecimal result = a.subtract(b); // 8.2
การคูณ (คูณ)
BigDecimal result = a.multiply(b); // 24.15
การหาร (หาร) และโหมดการปัดเศษ
การหารต้องระมัดระวัง หากไม่สามารถหารลงตัวได้ ArithmeticException จะเกิดขึ้นเว้นแต่จะระบุโหมดการปัดเศษ
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP); // 3.33
ที่นี่เราระบุ “2 ตำแหน่งทศนิยม” และ “ปัดขึ้นเมื่อครึ่ง”
การตั้งค่าขนาดและโหมดการปัดเศษด้วย setScale
setScale สามารถใช้เพื่อปัดเศษไปยังจำนวนหลักที่ระบุได้
BigDecimal value = new Big BigDecimal("123.456789");
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP); // 123.46
ค่าทั่วไปของ RoundingMode:
| Mode Name | Description |
|---|---|
HALF_UP | Round half up (standard rounding) |
HALF_DOWN | Round half down |
HALF_EVEN | Banker’s rounding |
UP | Always round up |
DOWN | Always round down |
BigDecimal เป็น Immutable
BigDecimal เป็น immutable หมายความว่า — เมธอดทางคณิตศาสตร์ (บวก ลบ ฯลฯ) จะไม่แก้ไขค่าดั้งเดิม — พวกมัน คืนค่าอินสแตนซ์ใหม่
BigDecimal original = new BigDecimal("5.0");
BigDecimal result = original.add(new BigDecimal("1.0"));
System.out.println(original); // still 5.0
System.out.println(result); // 6.0
4. การใช้งานขั้นสูงของ BigDecimal
การเปรียบเทียบค่าความแตกต่างระหว่าง compareTo และ equals
ใน BigDecimal มีสองวิธีในการเปรียบเทียบค่า: compareTo() และ equals() และ ทั้งสองทำงานแตกต่างกัน
compareTo()เปรียบเทียบเฉพาะค่าตัวเลข (ไม่สนใจขนาด)equals()เปรียบเทียบรวมขนาด (จำนวนหลักทศนิยม)BigDecimal a = new BigDecimal("10.0"); BigDecimal b = new BigDecimal("10.00"); System.out.println(a.compareTo(b)); // 0 (values are equal) System.out.println(a.equals(b)); // false (scale differs)
จุดสำคัญ: สำหรับการตรวจสอบความเท่าเทียมทางตัวเลข — เช่น ความเท่าเทียมของเงิน — compareTo() มักจะถูกแนะนำ
การแปลงไป/จาก String
ในการป้อนข้อมูลผู้ใช้และการนำเข้าจากไฟล์ภายนอก การแปลงด้วยประเภท String เป็นเรื่องปกติ
String → BigDecimal
BigDecimal value = new Big BigDecimal("1234.56");
BigDecimal → String
String str = value.toString(); // "1234.56"
การใช้ valueOf
Java ยังมี BigDecimal.valueOf(double val) แต่สิ่งนี้ยัง มีข้อผิดพลาดของ double ภายใน ดังนั้นการสร้างจากสตริงยังคงปลอดภัยกว่า
BigDecimal unsafe = BigDecimal.valueOf(0.1); // contains internal error
กฎการกำหนดความแม่นยำและการปัดเศษผ่าน MathContext
MathContext ช่วยให้คุณควบคุมความแม่นยำและโหมดการปัดเศษพร้อมกัน — มีประโยชน์เมื่อใช้กฎทั่วไปในหลายการดำเนินการ
MathContext mc = new MathContext(4, RoundingMode.HALF_UP);
BigDecimal result = new BigDecimal("123.4567").round(mc); // 123.5
ยังสามารถใช้ในทางคณิตศาสตร์ได้:
BigDecimal a = new BigDecimal("10.456");
BigDecimal b = new BigDecimal("2.1");
BigDecimal result = a.multiply(b, mc); // 4-digit precision
การตรวจสอบ null และการเริ่มต้นอย่างปลอดภัย
ฟอร์มอาจส่งค่า null หรือค่าว่าง — โค้ดป้องกันเป็นมาตรฐาน
String input = ""; // empty
BigDecimal value = (input == null || input.isEmpty()) ? BigDecimal.ZERO : new BigDecimal(input);
การตรวจสอบขนาดของ BigDecimal
เพื่อทราบจำนวนหลักทศนิยม ใช้ scale():
BigDecimal value = new BigDecimal("123.45");
System.out.println(value.scale()); // 3
5. ข้อผิดพลาดทั่วไปและวิธีแก้ไข
ArithmeticException: ทศนิยมที่ไม่สิ้นสุด
ตัวอย่างข้อผิดพลาด:
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("3");
BigDecimal result = a.divide(b); // exception
นี่คือ “1 ÷ 3” — เนื่องจากกลายเป็นทศนิยมที่ไม่สิ้นสุด หากไม่ระบุโหมดการปัดเศษ/ขนาด จะเกิดข้อยกเว้น
แก้ไข: ระบุขนาด + โหมดการปัดเศษ
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP); // OK (3.33)
ข้อผิดพลาดเมื่อสร้างโดยตรงจาก double
การส่งค่า double โดยตรงอาจมีข้อผิดพลาดแบบไบนารีอยู่แล้ว — ทำให้เกิดค่าที่ไม่คาดคิด。
ตัวอย่างที่ไม่ดี:
BigDecimal val = new BigDecimal(0.1);
System.out.println(val); // 0.100000000000000005551115123...
ถูกต้อง: ใช้ String
BigDecimal val = new BigDecimal("0.1"); // exact 0.1
หมายเหตุ: BigDecimal.valueOf(0.1) ใช้ Double.toString() ภายใน ดังนั้นจึง “เกือบเหมือน” กับ new BigDecimal("0.1") — แต่การใช้ string ปลอดภัย 100%。

ความเข้าใจผิดเกี่ยวกับ equals เนื่องจาก Scale ไม่ตรงกัน
เพราะ equals() เปรียบเทียบ scale จึงอาจคืนค่า false แม้ว่าค่าจะเท่ากันทางตัวเลข。
BigDecimal a = new BigDecimal("10.0");
BigDecimal b = new BigDecimal("10.00");
System.out.println(a.equals(b)); // false
วิธีแก้ไข: ใช้ compareTo() สำหรับความเท่ากันทางตัวเลข
System.out.println(a.compareTo(b)); // 0
ผลลัพธ์ที่ไม่คาดคิดที่เกิดจากความแม่นยำไม่เพียงพอ
หากใช้ setScale โดยไม่ระบุโหมดการปัดเศษ — อาจเกิดข้อยกเว้น。
ตัวอย่างที่ไม่ดี:
BigDecimal value = new BigDecimal("1.2567");
BigDecimal rounded = value.setScale(2); // exception
วิธีแก้ไข:
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP); // OK
NumberFormatException เมื่อค่า Input ไม่ถูกต้อง
หากส่งข้อความที่ไม่ถูกต้องซึ่งไม่สามารถแยกวิเคราะห์เป็นตัวเลขได้ (เช่น, input จากผู้ใช้ / ช่อง CSV) จะเกิด NumberFormatException。
วิธีแก้ไข: ใช้การจัดการข้อยกเว้น
try {
BigDecimal value = new BigDecimal(userInput);
} catch (NumberFormatException e) {
// show error message or fallback logic
}
6. ตัวอย่างการใช้งานจริง
ที่นี่เรานำเสนอ สถานการณ์ในโลกจริง ที่แสดงให้เห็นวิธีที่ BigDecimal สามารถนำไปใช้ในทางปฏิบัติ โดยเฉพาะในการคำนวณทางการเงิน/บัญชี/ภาษี ความสำคัญของการจัดการตัวเลขที่แม่นยำจะชัดเจนยิ่งขึ้น。
การจัดการทศนิยมในการคำนวณราคา (การปัดเศษเศษส่วน)
ตัวอย่าง: การคำนวณราคารวมภาษีการบริโภค 10%
BigDecimal price = new BigDecimal("980"); // price w/o tax
BigDecimal taxRate = new BigDecimal("0.10");
BigDecimal tax = price.multiply(taxRate).setScale(0, RoundingMode.HALF_UP);
BigDecimal total = price.add(tax);
System.out.println("Tax: " + tax); // Tax: 98
System.out.println("Total: " + total); // Total: 1078
ประเด็น:
- ผลการคำนวณภาษีมักถูกประมวลผลเป็น ตัวเลขเต็ม โดยใช้
setScale(0, RoundingMode.HALF_UP)เพื่อปัดเศษ. doubleมักทำให้เกิดข้อผิดพลาด — แนะนำให้ใช้BigDecimal。
การคำนวณส่วนลด (% ลด)
ตัวอย่าง: ส่วนลด 20%
BigDecimal originalPrice = new BigDecimal("3500");
BigDecimal discountRate = new BigDecimal("0.20");
BigDecimal discount = originalPrice.multiply(discountRate).setScale(0, RoundingMode.HALF_UP);
BigDecimal discountedPrice = originalPrice.subtract(discount);
System.out.println("Discount: " + discount); // Discount: 700
System.out.println("After discount: " + discountedPrice); // 2800
ประเด็น: การคำนวณส่วนลดราคา ต้องไม่สูญเสียความแม่นยำ。
การคำนวณราคาต่อหน่วย × จำนวน (สถานการณ์แอปธุรกิจทั่วไป)
ตัวอย่าง: 298.5 เยน × 7 ชิ้น
BigDecimal unitPrice = new BigDecimal("298.5");
BigDecimal quantity = new BigDecimal("7");
BigDecimal total = unitPrice.multiply(quantity).setScale(2, RoundingMode.HALF_UP);
System.out.println("Total: " + total); // 2089.50
ประเด็น:
- ปรับการปัดเศษสำหรับการคูณเศษส่วน.
- สำคัญสำหรับระบบบัญชี / ระบบสั่งซื้อ。
การคำนวณดอกเบี้ยทบต้น (ตัวอย่างทางการเงิน)
ตัวอย่าง: ดอกเบี้ยรายปี 3% × 5 ปี
BigDecimal principal = new BigDecimal("1000000"); // base: 1,000,000
BigDecimal rate = new BigDecimal("0.03");
int years = 5;
BigDecimal finalAmount = principal;
for (int i = 0; i < years; i++) {
finalAmount = finalAmount.multiply(rate.add(BigDecimal.ONE)).setScale(2, RoundingMode.HALF_UP);
}
System.out.println("After 5 years: " + finalAmount); // approx 1,159,274.41
Point:
- Repeated calculations accumulate errors — BigDecimal avoids this.
Validation & Conversion of User Input
public static BigDecimal parseAmount(String input) {
try {
return new BigDecimal(input).setScale(2, RoundingMode.HALF_UP);
} catch (NumberFormatException e) {
return BigDecimal.ZERO; // treat invalid input as 0
}
}
Points:
- Safely convert user-provided numeric strings.
- Validation + error fallback improves robustness.
7. Summary
The Role of BigDecimal
In Java’s numeric processing — especially monetary or precision-required logic — the BigDecimal class is indispensable. Errors inherent in float / double can be dramatically avoided by using BigDecimal.
This article covered fundamentals, arithmetic, comparisons, rounding, error handling, and real-world examples.
Key Review Points
BigDecimalhandles arbitrary-precision decimal — ideal for money and precision math- Initialization should be via string literal , e.g.
new BigDecimal("0.1") - Use
add(),subtract(),multiply(),divide(), and always specify rounding mode when dividing - Use
compareTo()for equality — understand difference vsequals() setScale()/MathContextlet you finely control scale + rounding- Real business logic cases include money, tax, quantity × unit price etc.
For Those About to Use BigDecimal
Although “handling numbers in Java” looks simple — precision / rounding / numeric error problems always exist behind it. BigDecimal is a tool that directly addresses those problems — mastering it lets you write more reliable code.
At first you may struggle with rounding modes — but with real project usage, it becomes natural.
Next chapter is an FAQ section summarizing common questions about BigDecimal — useful for review and specific semantic searches.
8. FAQ: Frequently Asked Questions About BigDecimal
Q1. Why should I use BigDecimal instead of float or double?
A1.
Because float/double represent numbers as binary approximations — decimal fractions cannot be represented exactly. This causes results such as “0.1 + 0.2 ≠ 0.3.”
BigDecimal preserves decimal values exactly — ideal for money or precision-critical logic.
Q2. What is the safest way to construct BigDecimal instances?
A2.
Always construct from string.
Bad (error):
new BigDecimal(0.1)
Correct:
new BigDecimal("0.1")
BigDecimal.valueOf(0.1) uses Double.toString() internally, so it’s almost same — but string is the safest.
Q3. Why does divide() throw an exception?
A3.
Because BigDecimal.divide() throws ArithmeticException when result is a non-terminating decimal.
Solution: specify scale + rounding mode
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
Q4. What’s the difference between compareTo() and equals()?
A4.
compareTo()checks numeric equality (scale ignored)equals()checks exact equality including scalenew BigDecimal("10.0").compareTo(new BigDecimal("10.00")); // → 0 new BigDecimal("10.0").equals(new BigDecimal("10.00")); // → false
Q5. How do I perform rounding?
A5.
Use setScale() with explicit rounding mode.
BigDecimal value = new BigDecimal("123.4567");
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP); // 123.46
Main rounding modes:
RoundingMode.HALF_UP(round half up)RoundingMode.DOWN(round down)RoundingMode.UP(round up)
Q6. Can I check decimal digits (scale)?
A6.
Yes — use scale().
BigDecimal val = new BigDecimal("123.45");
System.out.println(val.scale()); // → 3
Q7. How should I handle null/empty input safely?
A7.
Always include null checks + exception handling.
public static BigDecimal parseSafe(String input) {
if (input == null || input.trim().isEmpty()) return BigDecimal.ZERO;
try {
return new BigDecimal(input.trim());
} catch (NumberFormatException e) {
return BigDecimal.ZERO;
}
}

