ตัวเลขจุดลอยนิ้วถูกแทนในหน่วยความจำเป็นเศษส่วนฐานสอง (base 2 binary fraction) ผลส्वरूप การดำเนินการคณิตศาสตร์จุดลอยนิ้วอาจแปลกประหลาดบางครั้ง การบวก 0.1 และ 0.2 อาจให้ผลลัพธ์ที่น่ารำคาญดังนี้:
>>> 0.1 + 0.2 0.30000000000000004
ในความเป็นจริง นี่คือลักษณะของการแทนจุดลอยนิ้วฐานสอง นี่พบได้ในภาษาโปรแกรมมิ่งใดๆ Python มีโมดูล decimal เพื่อดำเนินการคณิตศาสตร์จุดลอยนิ้วที่รวดเร็วและปัดเศษอย่างถูกต้อง
โมดูล decimal ออกแบบมาเพื่อแทนจุดลอยนิ้วให้ตรงตามที่ต้องการ และผลลัพธ์ของการดำเนินการคณิตศาสตร์สอดคล้องกับคาดหมาย ระดับความแม่นยำของการแทนและดำเนินการสามารถตั้งค่าได้สูงสุด 28 ตำแหน่ง
โมดูล decimal กำหนดคลาส Decimal อ็อบเจ็กต์ Decimal สามารถประกาศได้โดยการให้จำนวนเต็ม, สตริงที่มีการแทนตัวเลข หรือทูเพิลเป็นพารามิเตอร์ให้คอนสตรัคเตอร์:
>>> from decimal import Decimal
>>> d1 = Decimal(10)
>>> d1
Decimal('10')
>>> d2 = Decimal('10')
>>> d2
Decimal('10')
พารามิเตอร์ทูเพิลประกอบด้วย 3 องค์ประกอบ เครื่องหมาย (0 สำหรับบวก, 1 สำหรับลบ), ทูเพิลของหลักเลข และเลขชี้กำลัง (exponent) ตัวอย่างเช่น:
>>> d3 = Decimal((1, (1, 2, 3, 4), 2))
>>> d3
Decimal('-1.234E+5')
วิธีที่สะดวกกว่าในการแทนตัวเลขจุดลอยนิ้วของความแม่นยำเฉพาะ คือการรับบริบทสภาพแวดล้อม (context environment) ของเธรดปัจจุบันโดยฟังก์ชัน getcontext() และตั้งค่าความแม่นยำสำหรับอ็อบเจ็กต์ Decimal:
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 5
>>> d3 = Decimal(10)
>>> d4 = Decimal(3)
>>> d3 / d4
Decimal('3.3333')
บริบท (Contexts) เป็นสภาพแวดล้อมสำหรับการดำเนินการคณิตศาสตร์ ใช้กำหนดความแม่นยำ และกำหนดกฎการปัดเศษ รวมถึงจำกัดช่วงสำหรับเลขชี้กำลัง
decimal.getcontext() - คืนค่าบริบทปัจจุบันสำหรับเธรดที่ใช้งานอยู่
decimal.setcontext(c) - ตั้งค่าบริบทปัจจุบันสำหรับเธรดที่ใช้งานอยู่เป็น c
ค่าคงที่โหมดการปัดเศษต่อไปนี้ถูกกำหนดในโมดูล decimal:
| ROUND_CEILING | ปัดเข้าหา Infinity |
| ROUND_DOWN | ปัดเข้าหาศูนย์ |
| ROUND_FLOOR | ปัดเข้าหา -Infinity |
| ROUND_HALF_DOWN | ปัดไปค่าที่ใกล้ที่สุด โดย ties ไปเข้าหาศูนย์ |
| ROUND_HALF_EVEN | ปัดไปค่าที่ใกล้ที่สุด โดย ties ไปที่เลขคู่ที่ใกล้ที่สุด |
| ROUND_HALF_UP | ปัดไปค่าที่ใกล้ที่สุด โดย ties ไปห่างจากศูนย์ |
| ROUND_UP | ปัดห่างจากศูนย์ |
| ROUND_05UP | ปัดห่างจากศูนย์ หากหลักสุดท้ายหลังปัดเข้าศูนย์จะเป็น 0 หรือ 5 มิฉะนั้นปัดเข้าศูนย์ |
ชุดโค้ดต่อไปนี้ใช้พารามิเตอร์ precision และ rounding ของอ็อบเจ็กต์บริบท:
>>> from decimal import *
>>> getcontext().prec = 5
>>> getcontext().rounding = ROUND_UP
>>> d1 = Decimal(100)
>>> d2 = Decimal(6)
>>> d1 / d2
Decimal('16.667')
การดำเนินการคณิตศาสตร์บนอ็อบเจ็กต์ Decimal:
การดำเนินการคณิตศาสตร์ทั่วไปทั้งหมดทำบนอ็อบเจ็กต์ Decimal ได้ คล้ายกับ float ปกติ:
>>> a = Decimal('2.4')
>>> b = Decimal('1.2')
>>> a + b
Decimal('3.6')
>>> a - b
Decimal('1.2')
>>> b - a
Decimal('-1.2')
>>> a * b
Decimal('2.88')
>>> a / b
Decimal('2')
การดำเนินการคณิตศาสตร์สามารถทำได้ระหว่างอ็อบเจ็กต์ Decimal หนึ่งและอ็อบเจ็กต์จำนวนเต็มหนึ่ง อย่างไรก็ตาม กับอ็อบเจ็กต์จุดลอยนิ้วปกติ การดำเนินการจะไม่ถูกต้อง:
>>> a = Decimal('2.4')
>>> c = 2.1
>>> a + c
Traceback (most recent call last):
File "", line 1, in
a + c
TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'
ข้อยกเว้นเดียวกันเกิดขึ้นสำหรับการดำเนินการคณิตศาสตร์ทั้งหมด
พฤติกรรมของออปเปอเรเตอร์เหลือ (%) กับอ็อบเจ็กต์ Decimal แตกต่างจากชนิดตัวเลขปกติเล็กน้อย ที่นี่ เครื่องหมายของผลลัพธ์เป็นของตัวถูกหาร (dividend) แทนที่จะเป็นของตัวหาร (divisor):
>>> -7 % 3
2
>>> 7 % -3
-2
>>> Decimal(-7) % Decimal(3)
Decimal('-1')
>>> Decimal(7) % Decimal(-3)
Decimal('1')
Decimal.from_float() - ฟังก์ชันนี้แปลง float ปกติเป็นอ็อบเจ็กต์ Decimal ด้วยการแทนไบนารีที่แม่นยำ ผลลัพธ์คือ from_float(0.1) และ Decimal('0.1') ไม่เหมือนกัน:
>>> d1 = Decimal('0.1')
>>> d2 = Decimal.from_float(0.1)
>>> d1, d2
(Decimal('0.1'), Decimal('0.1000000000000000055511151231257827021181583404541015625'))
บทความนี้อธิบายการใช้งานฟังก์ชันที่กำหนดในโมดูล decimal ของไลบรารีมาตรฐาน Python