Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

เลขคงที่และเลขจุดลอยนิ้วคงจุดทศนิยมใน Python (decimal)

ตัวเลขจุดลอยนิ้วถูกแทนในหน่วยความจำเป็นเศษส่วนฐานสอง (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