เหตุใดตัวเลขจุดลอยตัวจึงไม่ถูกต้อง


198

ทำไมบางตัวเลขสูญเสียความแม่นยำเมื่อเก็บไว้เป็นตัวเลขทศนิยม?

ตัวอย่างเช่นตัวเลขทศนิยม9.2สามารถแสดงได้อย่างแม่นยำตามอัตราส่วนของจำนวนเต็มทศนิยมสองตัว ( 92/10) ซึ่งทั้งสองสามารถแสดงอย่างถูกต้องในรูปแบบไบนารี ( 0b1011100/0b1010) อย่างไรก็ตามอัตราส่วนเดียวกันที่เก็บไว้เป็นเลขทศนิยมจะไม่เท่ากับ9.2:

32-bit "single precision" float: 9.19999980926513671875
64-bit "double precision" float: 9.199999999999999289457264239899814128875732421875

หมายเลขธรรมดาอย่างเห็นได้ชัดว่าเป็นอย่างไร "ใหญ่เกินไป" ในการแสดงผลในหน่วยความจำ64 บิต ?




คำตอบ:


242

ในภาษาการเขียนโปรแกรมส่วนใหญ่จำนวนจุดลอยตัวจะมีจำนวนมากเช่นสัญกรณ์วิทยาศาสตร์ : ด้วยเลขชี้กำลังและแมนทิสซา (เรียกอีกอย่างว่าซิกนิฟิแคนด์) จำนวนที่ง่ายมากพูด9.2เป็นเศษส่วนนี้:

5179139571476070 * 2 -49

ที่ไหนเลขชี้กำลังเป็น-49และ mantissa 5179139571476070คือ เหตุผลที่เป็นไปไม่ได้ที่จะแสดงตัวเลขทศนิยมบางส่วนด้วยวิธีนี้คือทั้งเลขชี้กำลังและแมนทิสซาต้องเป็นจำนวนเต็ม ในคำอื่น ๆ ลอยทั้งหมดต้องเป็นจำนวนเต็มคูณโดยอำนาจจำนวนเต็มของ 2

9.2อาจจะง่าย92/10แต่10ไม่สามารถแสดงเป็น2 nหากnถูก จำกัด ด้วยค่าจำนวนเต็ม


เห็นข้อมูล

ครั้งแรกที่ฟังก์ชั่นบางอย่างเพื่อดูส่วนประกอบที่ทำให้ 32 และ float64 เงาเหนือสิ่งเหล่านี้หากคุณสนใจเฉพาะผลลัพธ์ (ตัวอย่างใน Python):

def float_to_bin_parts(number, bits=64):
    if bits == 32:          # single precision
        int_pack      = 'I'
        float_pack    = 'f'
        exponent_bits = 8
        mantissa_bits = 23
        exponent_bias = 127
    elif bits == 64:        # double precision. all python floats are this
        int_pack      = 'Q'
        float_pack    = 'd'
        exponent_bits = 11
        mantissa_bits = 52
        exponent_bias = 1023
    else:
        raise ValueError, 'bits argument must be 32 or 64'
    bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
    return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]

มีความซับซ้อนมากมายที่อยู่เบื้องหลังฟังก์ชั่นนั้นและมันก็ค่อนข้างจะแทนเจนต์ที่จะอธิบาย แต่ถ้าคุณสนใจทรัพยากรที่สำคัญสำหรับวัตถุประสงค์ของเราคือโมดูลstruct

Python floatเป็นหมายเลข 64 บิตความแม่นยำสองเท่า ในภาษาอื่นเช่น C, C ++, Java และ C #, double-precision มีประเภทที่แยกต่างหากdoubleซึ่งมักจะถูกนำมาใช้เป็น 64 บิต

เมื่อเราเรียกฟังก์ชันนั้นด้วยตัวอย่างของเรา9.2นี่คือสิ่งที่เราได้รับ:

>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']

การตีความข้อมูล

คุณจะเห็นว่าฉันแบ่งค่าตอบแทนเป็นสามองค์ประกอบ ส่วนประกอบเหล่านี้คือ:

  • สัญญาณ
  • ตัวแทน
  • Mantissa (เรียกอีกอย่างว่า Significand หรือเศษส่วน)

สัญญาณ

เครื่องหมายถูกเก็บไว้ในองค์ประกอบแรกเป็นบิตเดียว ง่ายต่อการอธิบาย: 0หมายความว่าจำนวนลอยเป็นจำนวนบวก 1หมายความว่ามันเป็นลบ เพราะเป็นบวกค่าสัญญาณของเราคือ9.20

ตัวแทน

เลขชี้กำลังจะถูกเก็บไว้ในองค์ประกอบกลางเป็น 11 บิต 0b10000000010ในกรณีของเรา 1026ในทศนิยมที่แสดงถึงความคุ้มค่า องค์ประกอบที่แปลกประหลาดขององค์ประกอบนี้คือคุณต้องลบจำนวนเท่ากับ2 (# ของบิต) - 1 - 1เพื่อให้ได้เลขชี้กำลังที่แท้จริง ในกรณีของเรานั่นหมายถึงการลบ 0b1111111111(เลขฐานสิบ1023) เพื่อให้ได้เลขชี้กำลังจริง0b00000000011(จำนวนทศนิยม 3)

เลขแม็นทีซซะ

mantissa ถูกเก็บไว้ในองค์ประกอบที่สามเป็น 52 bits อย่างไรก็ตามมีองค์ประกอบขององค์ประกอบนี้เช่นกัน หากต้องการทำความเข้าใจกับการเล่นโวหารนี้พิจารณาตัวเลขในสัญกรณ์ทางวิทยาศาสตร์เช่นนี้

6.0221413x10 23

mantissa 6.0221413จะเป็น จำได้ว่าแมนทิสซาในรูปแบบทางวิทยาศาสตร์มักจะเริ่มต้นด้วยตัวเลขที่ไม่ใช่ศูนย์เดียว เดียวกันถือเป็นจริงสำหรับไบนารียกเว้นไบนารีที่มีเพียงตัวเลขสองหลัก: และ0 1ดังนั้นไบนารีแมนทิสซาจึงเริ่มต้นด้วยเสมอ1 ! เมื่อโฟลว์ถูกเก็บไว้1ด้านหน้าของไบนารีแมนทิสซาจะถูกละเว้นเพื่อประหยัดพื้นที่ เราต้องวางมันกลับไปที่ด้านหน้าขององค์ประกอบที่สามของเราเพื่อรับแมนทิสซาที่แท้จริง :

1,0010011001100110011001100110011001100110011001100110

นี้เกี่ยวข้องกับการมากกว่าเพียงแค่นอกจากนี้ง่ายเพราะบิตที่เก็บไว้ในองค์ประกอบที่สามของเราจริงเป็นตัวแทนของเศษส่วนส่วนหนึ่งของ mantissa ทางด้านขวาของจุดฐาน

เมื่อจัดการกับตัวเลขทศนิยมเรา "ย้ายจุดทศนิยม" โดยการคูณหรือหารด้วยพลังของ 10 ในไบนารีเราสามารถทำสิ่งเดียวกันโดยการคูณหรือหารด้วยพลังของ 2 เนื่องจากองค์ประกอบที่สามของเรามี 52 บิตเราแบ่ง โดย2 52เพื่อย้าย 52 ตำแหน่งไปทางขวา:

0,0010011001100110011001100110011001100110011001100110

ในสัญกรณ์ทศนิยมที่เป็นเช่นเดียวกับการหาร675539944105574โดยที่จะได้รับ4503599627370496 0.1499999999999999(นี่คือตัวอย่างหนึ่งของอัตราส่วนที่สามารถแสดงได้อย่างชัดเจนในรูปแบบไบนารี แต่โดยประมาณเป็นทศนิยมเท่านั้นสำหรับรายละเอียดเพิ่มเติมดูที่: 675539944105574/4503599627370496 )

ตอนนี้เราได้เปลี่ยนองค์ประกอบที่สามเป็นตัวเลขเศษส่วนแล้วการเพิ่ม1จะทำให้ mantissa จริง

การจัดองค์ประกอบใหม่

  • เครื่องหมาย (องค์ประกอบแรก): 0สำหรับค่าบวก, 1ค่าลบ
  • เลขชี้กำลัง (องค์ประกอบกลาง): ลบ2 (# ของบิต) - 1 - 1เพื่อให้ได้เลขชี้กำลังที่แท้จริง
  • Mantissa (องค์ประกอบสุดท้าย): หารด้วย2 (# ของบิต)และเพิ่ม1เพื่อรับ mantissa จริง

การคำนวณจำนวน

การนำทั้งสามส่วนเข้าด้วยกันเราจะได้เลขฐานสองนี้:

1.00100110011001100110011001100110011001100110011001100110011001100 11

ซึ่งเราสามารถแปลงจากเลขฐานสองเป็นทศนิยม:

1.1499999999999999 x 2 3 (ไม่แน่นอน!)

และคูณเพื่อแสดงการแทนค่าสุดท้ายของหมายเลขที่เราเริ่มต้นด้วย ( 9.2) หลังจากถูกเก็บเป็นค่าทศนิยม

9.1999999999999993


แสดงว่าเป็นเศษส่วน

9.2

ตอนนี้เราได้สร้างตัวเลขแล้วมันเป็นไปได้ที่จะสร้างมันใหม่เป็นเศษส่วนง่ายๆ:

1.00100110011001100110011001100110011001100110011001100110011001100 11

เปลี่ยน mantissa เป็นจำนวนเต็ม:

10010011001100110011001100110011001100110011001100110011001100 x 10 11-110100

แปลงเป็นทศนิยม:

5179139571476070 x 2 3-52

ลบเลขชี้กำลัง:

5179139571476070 x 2 -49

เปลี่ยนเลขชี้กำลังเป็นค่าลบเป็นหมวด:

5179139571476070/2 49

ตัวแทนทวีคูณ:

5179139571476070/562949953421312

ซึ่งเท่ากับ:

9.1999999999999993

9.5

>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']

ตอนนี้คุณสามารถเห็นแมนทิสสาเป็นเพียงตัวเลข 4 หลักตามด้วยศูนย์ทั้งหมด แต่ขอผ่านก้าว

ประกอบสัญกรณ์ทางวิทยาศาสตร์ไบนารี:

1.0011 x 10 11

เลื่อนจุดทศนิยม:

10011 x 10 11-100

ลบเลขชี้กำลัง:

10011 x 10 -1

ไบนารีถึงทศนิยม:

19 x 2 -1

เลขชี้กำลังเป็นลบถึงส่วน:

19/2 1

ตัวแทนทวีคูณ:

19/2

เท่ากับ:

9.5



อ่านเพิ่มเติม


1
นอกจากนี้ยังมีบทช่วยสอนที่ดีที่แสดงวิธีไปในทางอื่น - ด้วยการแทนค่าทศนิยมของตัวเลขคุณจะสร้างจุดลอยที่เทียบเท่าได้อย่างไร วิธีการ "การหารแบบยาว" แสดงให้เห็นอย่างชัดเจนว่าคุณท้ายด้วย "ส่วนที่เหลือ" หลังจากพยายามแสดงตัวเลข ควรเพิ่มถ้าคุณต้องการ "ยอมรับ" อย่างแท้จริงพร้อมกับคำตอบของคุณ
Floris

1
หากคุณกำลังพูดถึง Python และ floating-point ฉันขอแนะนำอย่างน้อยรวมถึงการสอน Python ในลิงค์ของคุณ: docs.python.org/3.4/tutorial/floatingpoint.html นั่นควรจะเป็นแบบเบ็ดเสร็จ ทรัพยากรสำหรับปัญหาทศนิยมสำหรับโปรแกรมเมอร์ Python หากยังขาดอยู่บ้าง (และเกือบจะแน่นอน) โปรดเปิดปัญหาในตัวติดตามข้อผิดพลาดของ Python เพื่อรับการปรับปรุงหรือเปลี่ยนแปลง
Mark Dickinson

@mhlester หากสิ่งนี้กลายเป็นวิกิของชุมชนรู้สึกอิสระที่จะรวมคำตอบของฉันเป็นของคุณ
Nicu Stiurca

5
คำตอบนี้ควรเชื่อมโยงไปยังfloating-point-gui.deอย่างแน่นอนเนื่องจากอาจเป็นการแนะนำที่ดีที่สุดสำหรับผู้เริ่มต้น IMO มันควรจะอยู่เหนือ "สิ่งที่นักวิทยาศาสตร์คอมพิวเตอร์ทุกคนควรรู้ ... " - ทุกวันนี้ผู้คนที่สามารถเข้าใจกระดาษของ Goldberg อย่างมีเหตุผลมักจะตระหนักดีอยู่แล้ว
Daniel Pryden

1
"นี่เป็นตัวอย่างหนึ่งของอัตราส่วนที่สามารถแสดงได้อย่างชัดเจนในรูปแบบไบนารี แต่โดยประมาณเป็นทศนิยม" นี่ไม่เป็นความจริง. จำนวน 'ทั้งหมดเหล่านี้ที่มีกำลังมากกว่าสองเท่า' นั้นมีค่าเป็นทศนิยม การประมาณใด ๆ จะทำให้จำนวนทศนิยมสั้นลงเท่านั้นเพื่อความสะดวก
Rick Regan

29

นี่ไม่ใช่คำตอบที่สมบูรณ์ ( mhlesterครอบคลุมพื้นที่ที่ดีอยู่แล้วจำนวนมากที่ฉันจะไม่ทำซ้ำ) แต่ฉันอยากจะเน้นว่าการแสดงตัวเลขขึ้นอยู่กับฐานที่คุณทำงาน

พิจารณาเศษส่วน 2/3

ในฐาน 10 ที่ดีเรามักจะเขียนมันออกมาเหมือน

  • 0.666 ...
  • 0.666
  • 0.667

เมื่อเราดูการแทนค่าเหล่านั้นเรามักจะเชื่อมโยงแต่ละส่วนกับเศษส่วน 2/3 แม้ว่าการแทนครั้งแรกจะเท่ากับเศษส่วนทางคณิตศาสตร์ การรับรอง / การประมาณค่าที่สองและสามมีข้อผิดพลาดในลำดับ 0.001 ซึ่งอันที่จริงแล้วนั้นแย่กว่าข้อผิดพลาดระหว่าง 9.2 ถึง 9.1999999999999993 ในความเป็นจริงการแสดงที่สองนั้นไม่ได้ถูกต้องเลยแม้แต่ครั้งเดียว! แต่เราไม่ได้มีปัญหากับ 0.666 เป็นประมาณของจำนวน 2/3 แล้วดังนั้นเราจึงไม่ควรมีปัญหากับวิธีการที่ 9.2 เป็นห้วงในโปรแกรมส่วนใหญ่ (ใช่ในบางโปรแกรมเป็นเรื่องสำคัญ)

ฐานจำนวน

ดังนั้นนี่คือที่ฐานจำนวนเป็นสิ่งสำคัญ หากเราพยายามแสดง 2/3 ในฐาน 3 แล้ว

(2/3) 10 = 0.2 3

กล่าวอีกนัยหนึ่งเรามีจำนวน จำกัด แน่นอนแทนจำนวนเดียวกันโดยการเปลี่ยนฐาน! ใช้เวลาอยู่ห่างออกไปคือแม้ว่าคุณสามารถแปลงหมายเลขใด ๆ ไปยังฐานใด ๆสรุปตัวเลขทั้งหมดมีการแสดงขอบเขตที่แน่นอนในบางฐาน แต่ไม่ได้อยู่ในที่คนอื่น ๆ

เพื่อขับรถกลับบ้านจุดนี้ลองดูที่ 1/2 มันอาจทำให้คุณแปลกใจว่าแม้ว่าตัวเลขที่เรียบง่ายนี้มีตัวแทนที่แน่นอนในฐาน 10 และ 2 แต่ก็ต้องการตัวแทนที่ซ้ำกันในฐาน 3

(1/2) 10 = 0.5 10 = 0.1 2 = 0.1111 ... 3

เหตุใดตัวเลขจุดลอยตัวจึงไม่ถูกต้อง

เพราะบ่อยครั้งที่พวกเขาจะใกล้เคียงกับ rationals ที่ไม่สามารถเป็นตัวแทนของขอบเขตในฐาน 2 (ตัวเลขซ้ำ) และโดยทั่วไปพวกเขาจะใกล้เคียงกับของจริง (อาจจะไม่ลงตัว) หมายเลขซึ่งอาจจะไม่ซึ่งแสดงในตัวเลขหลายขีดในใด ๆฐาน


3
ดังนั้นในคำอื่น ๆ ที่ฐาน-3จะเหมาะสำหรับ1/3เช่นเดียวกับฐาน-101/10เหมาะสำหรับ เศษส่วนทั้งสองทำงานในฐาน -2
mhlester

2
@mhlester ใช่ และโดยทั่วไปbase-Nนั้นสมบูรณ์แบบสำหรับเศษส่วนใด ๆ ที่ตัวส่วนเป็นNหรือหลายตัว
Nicu Stiurca

2
และนี่คือเหตุผลหนึ่งว่าทำไมกล่องเครื่องมือเชิงตัวเลขบางตัวติดตาม "สิ่งที่หารด้วยอะไร" และในกระบวนการสามารถรักษา "ความแม่นยำไม่สิ้นสุด" สำหรับตัวเลขที่มีเหตุผลทั้งหมด เช่นเดียวกับนักฟิสิกส์ที่ต้องการรักษาสมการสัญลักษณ์ของพวกเขาจนถึงช่วงเวลาสุดท้ายที่เป็นไปได้ในกรณีที่ปัจจัยπอื่น ๆ ถูกยกเลิก
Floris

3
@ Floris ฉันเคยเห็นกรณีที่อัลกอริทึมที่ใช้งานการคำนวณทางคณิตศาสตร์ขั้นพื้นฐานเท่านั้น (นั่นคือรักษาความเป็นเหตุเป็นผลของการป้อนข้อมูล) ตรวจสอบว่าการป้อนข้อมูลเป็นไปได้ (มีแนวโน้ม) เหตุผลดำเนินการทางคณิตศาสตร์โดยใช้เลขทศนิยมปกติ การประมาณในตอนท้ายเพื่อแก้ไขข้อผิดพลาดในการปัดเศษ โดยเฉพาะอย่างยิ่งอัลกอริทึมแบบแถวแถวที่ลดลงของ Matlab จะทำสิ่งนี้และมันช่วยให้เกิดเสถียรภาพด้านตัวเลข
Nicu Stiurca

@SchighSchagh - น่าสนใจฉันไม่รู้ ฉันรู้ว่าเสถียรภาพเชิงตัวเลขเป็นสิ่งที่ไม่ได้รับการสอนอย่างเพียงพอในยุคสมัยที่มีความแม่นยำสองเท่า ซึ่งหมายความว่าหลายคนพลาดเรียนรู้เกี่ยวกับความงดงามของอัลกอริธึมที่สวยงามมากมาย ฉันชอบอัลกอริทึมที่คำนวณและแก้ไขข้อผิดพลาดของตนเอง
Floris

13

ในขณะที่คำตอบอื่น ๆ ทั้งหมดเป็นสิ่งที่ดี แต่ก็ยังมีสิ่งหนึ่งที่ขาดหายไป:

มันเป็นไปไม่ได้ที่จะเป็นตัวแทนตัวเลขไม่ลงตัว (เช่นπ, sqrt(2), log(3)ฯลฯ ) ได้อย่างแม่นยำ!

และนั่นคือเหตุผลที่พวกเขาถูกเรียกว่าไร้เหตุผล ไม่มีที่เก็บข้อมูลบิตในโลกที่จะเพียงพอที่จะเก็บแม้แต่หนึ่งในนั้น เฉพาะเลขคณิตเชิงสัญลักษณ์เท่านั้นที่สามารถรักษาความแม่นยำไว้ได้

แม้ว่าคุณจะ จำกัด คณิตศาสตร์ของคุณจำเป็นต้องใช้จำนวนตรรกยะเฉพาะปัญหาความแม่นยำเท่านั้นที่สามารถจัดการได้ คุณจะต้องเก็บคู่ (อาจจะใหญ่มาก) จำนวนเต็มaและจะถือจำนวนที่แสดงโดยเศษb a/bการคำนวณทางคณิตศาสตร์ทั้งหมดของคุณจะต้องทำในเศษส่วนเช่นเดียวกับในคณิตศาสตร์ระดับมัธยมศึกษาตอนปลาย (เช่นa/b * c/d = ac/bd)

แต่แน่นอนว่าคุณจะทำงานยังคงเข้ามาในชนิดเดียวกันของปัญหาเมื่อpi, sqrt, log, sinและอื่น ๆ ที่มีส่วนเกี่ยวข้อง

TL; DR

สำหรับฮาร์ดแวร์ทางคณิตศาสตร์ที่เร่งความเร็วสามารถแสดงจำนวนตรรกยะจำนวน จำกัด ได้อย่าง จำกัด ทุกหมายเลขที่ไม่สามารถแทนได้จะถูกประมาณ ตัวเลขบางตัว (เช่นไม่มีเหตุผล) ไม่สามารถแสดงได้ไม่ว่าระบบ


4
น่าสนใจมีฐานที่ไม่มีเหตุผล Phinaryยกตัวอย่างเช่น
Veedrac

5
ตัวเลขที่ไม่มีเหตุผลสามารถเป็น (เท่านั้น) ที่แสดงในฐานของพวกเขา ตัวอย่างเช่น pi คือ 10 ในฐานปี่
phuclv

4
คะแนนยังคงใช้ได้: ตัวเลขบางตัวไม่สามารถแสดงได้ไม่ว่าระบบจะเป็นอย่างไร คุณไม่ได้อะไรเลยด้วยการเปลี่ยนฐานเพราะตัวเลขอื่น ๆ ไม่สามารถแสดงได้อีกต่อไป
LumpNe

4

มีจำนวนจริงจำนวนอนันต์ (จำนวนมากจนคุณไม่สามารถระบุได้) และมีจำนวนตรรกยะจำนวนมากอย่างไม่ จำกัด (เป็นไปได้ที่จะแจกแจง)

การนำเสนอจุดลอยตัวเป็นจำนวน จำกัด (เหมือนสิ่งใด ๆ ในคอมพิวเตอร์) ดังนั้นตัวเลขจำนวนมากที่ไม่สามารถหลีกเลี่ยงได้ โดยเฉพาะอย่างยิ่ง 64 บิตอนุญาตให้คุณแยกความแตกต่างระหว่างค่าต่าง ๆ เพียง 18,446,744,073,709,551,616 เท่านั้น (ซึ่งไม่มีอะไรเทียบได้กับอินฟินิตี้) ด้วยการประชุมมาตรฐาน 9.2 ไม่ใช่หนึ่งในนั้น ที่สามารถอยู่ในรูปแบบ m.2 ^ e สำหรับจำนวนเต็มบาง m และ e


คุณอาจเกิดขึ้นกับระบบการนับที่แตกต่างกันเช่น 10 ตามที่ 9.2 จะมีการแสดงที่แน่นอน แต่ตัวเลขอื่น ๆ ก็บอกว่า 1/3 ยังคงเป็นไปไม่ได้ที่จะเป็นตัวแทน


นอกจากนี้ทราบว่าแม่นยำสองตัวเลขลอยจุดมากที่ถูกต้อง พวกเขาสามารถแสดงตัวเลขใด ๆ ในช่วงกว้างมากที่มี 15 หลักที่แน่นอน สำหรับการคำนวณชีวิตประจำวันตัวเลข 4 หรือ 5 หลักนั้นมากเกินพอ คุณจะไม่ต้องการ 15 เหล่านั้นจริงๆยกเว้นว่าคุณต้องการนับทุกๆมิลลิวินาทีของอายุการใช้งานของคุณ


1

เหตุใดเราจึงไม่สามารถแทน 9.2 ในทศนิยมเลขฐานสองได้?

หมายเลขจุดลอยตัวคือ (ลดความซับซ้อนเล็กน้อย) ระบบการระบุตำแหน่งด้วยจำนวนที่ จำกัด ของตัวเลขและจุดฐานที่เคลื่อนที่ได้

เศษส่วนสามารถแสดงได้อย่างแน่นอนโดยใช้จำนวน จำกัด ของตัวเลขในระบบการระบุตำแหน่งหากปัจจัยหลักของตัวหาร (เมื่อเศษส่วนแสดงในคำที่ต่ำที่สุด) เป็นปัจจัยของฐาน

ปัจจัยสำคัญของ 10 คือ 5 และ 2 ดังนั้นในฐาน 10 เราสามารถแทนเศษส่วนของรูปแบบ a / (2 b 5 c )

ในทางกลับกันตัวประกอบเฉพาะของ 2 คือ 2 ดังนั้นในฐาน 2 เราสามารถแสดงเศษส่วนของรูปแบบ a / (2 b )

เหตุใดคอมพิวเตอร์จึงใช้การเป็นตัวแทนนี้

เนื่องจากเป็นรูปแบบที่ใช้งานง่ายและมีความแม่นยำเพียงพอสำหรับวัตถุประสงค์ส่วนใหญ่ โดยพื้นฐานแล้วเหตุผลเดียวกับที่นักวิทยาศาสตร์ใช้ "สัญกรณ์ทางวิทยาศาสตร์" และปัดเศษผลลัพธ์เป็นตัวเลขที่สมเหตุสมผลในแต่ละขั้นตอน

แน่นอนว่าจะเป็นไปได้ที่จะกำหนดรูปแบบเศษส่วนด้วย (ตัวอย่าง) ตัวเศษแบบ 32 บิตและตัวส่วนแบบ 32 บิต มันจะสามารถแสดงตัวเลขที่จุดลอยตัวความแม่นยำสองเท่าของ IEEE ไม่สามารถทำได้ แต่จะมีตัวเลขจำนวนมากที่สามารถแทนด้วยจุดลอยตัวที่มีความแม่นยำสองเท่าซึ่งไม่สามารถแสดงในรูปแบบเศษส่วนขนาดคงที่ได้

อย่างไรก็ตามปัญหาใหญ่คือรูปแบบดังกล่าวเป็นความเจ็บปวดในการคำนวณ ด้วยเหตุผลสองประการ

  1. หากคุณต้องการให้มีการแสดงตัวเลขแต่ละตัวอย่างละหนึ่งครั้งหลังจากการคำนวณแต่ละครั้งคุณต้องลดเศษส่วนให้เหลือน้อยที่สุด นั่นหมายความว่าสำหรับการดำเนินการทุกครั้งคุณจำเป็นต้องทำการคำนวณตัวหารร่วมที่ยิ่งใหญ่ที่สุด
  2. หากหลังจากการคำนวณของคุณคุณจะได้ผลลัพธ์ที่ไม่สามารถคาดเดาได้เพราะตัวเศษหรือส่วนที่คุณต้องการเพื่อให้ได้ผลลัพธ์ที่ใกล้เคียงที่สุด นี่ไม่ใช่เรื่องไร้สาระ

ภาษาบางภาษาเสนอประเภทเศษส่วน แต่โดยปกติแล้วพวกเขาจะทำร่วมกับความแม่นยำทางโบราณคดีหลีกเลี่ยงการกังวลเกี่ยวกับเศษส่วนโดยประมาณ แต่มันสร้างปัญหาขึ้นมาเองเมื่อตัวเลขผ่านขั้นตอนการคำนวณจำนวนมากตามขนาดของตัวหารและ ดังนั้นการจัดเก็บข้อมูลที่จำเป็นสำหรับเศษส่วนสามารถระเบิดได้

บางภาษายังมีทศนิยมชนิดทศนิยมซึ่งส่วนใหญ่จะใช้ในสถานการณ์ที่สำคัญที่ผลลัพธ์ของคอมพิวเตอร์จะตรงกับกฎการปัดเศษที่มีอยู่ก่อนซึ่งเขียนโดยมนุษย์ในใจ (การคำนวณทางการเงินส่วนใหญ่) สิ่งเหล่านี้ทำงานได้ยากกว่าจุดลอยตัวไบนารี แต่ปัญหาที่ใหญ่ที่สุดคือคอมพิวเตอร์ส่วนใหญ่ไม่ให้การสนับสนุนฮาร์ดแวร์สำหรับพวกเขา


-4

ลองสิ่งนี้

DecimalFormat decimalFormat = new DecimalFormat("#.##");
String.valueOf(decimalFormat.format(decimalValue))));

' decimalValue' คือค่าของคุณที่จะแปลง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.