คุณใช้โฟลตเมื่อใดและเมื่อไหร่ที่คุณจะใช้สองครั้ง


194

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

คุณใช้โฟลตเมื่อใดและเมื่อไหร่ที่คุณจะใช้สองเท่า คุณมักจะใช้สองครั้งต่อเมื่อมีข้อ จำกัด ของหน่วยความจำเกิดขึ้นและคุณจะต้องลอยตัว หรือคุณใช้งานแบบลอยตลอดเว้นแต่ความต้องการความแม่นยำต้องการให้คุณใช้สองเท่าหรือไม่ มีความแตกต่างอย่างมากเกี่ยวกับความซับซ้อนในการคำนวณของเลขคณิตพื้นฐานระหว่าง float และ double หรือไม่? ข้อดีและข้อเสียของการใช้ float หรือ double คืออะไร และคุณยังใช้คู่ยาวหรือไม่


28
ในหลายกรณีคุณไม่ต้องการใช้ แต่เป็นทศนิยมชนิดทศนิยมหรือทศนิยม ชนิดทศนิยมชนิดไบนารีไม่สามารถแสดงทศนิยมได้อย่างแน่นอน
CodesInChaos

3
เกี่ยวข้องกับสิ่งที่ทำให้เกิดข้อผิดพลาดในการปัดเศษทศนิยม? . @CodesInChaos คำตอบของฉันมีแนะนำแหล่งข้อมูลเพื่อช่วยให้คุณตัดสินใจได้ว่าไม่มีวิธีแก้ปัญหาที่เหมาะกับทุกขนาด
Mark Booth

พบคำตอบที่ดีมากที่: Stack Overflow
Haris

5
คุณหมายถึงอะไรโดย "ทศนิยม" หากคุณต้องการแสดงค่าเช่น 0.01 อย่างแน่นอน (พูดเพื่อเงิน) ดังนั้น (ไบนารี) floating-point ไม่ใช่คำตอบ หากคุณเพียงหมายถึงตัวเลขที่ไม่ใช่จำนวนเต็มจุดลอยตัวก็น่าจะพอแล้ว แต่ "ทศนิยม" ไม่ใช่คำที่ดีที่สุดในการอธิบายสิ่งที่คุณต้องการ
Keith Thompson

1
คุณไม่มีทางเลือกเสมอไป ตัวอย่างเช่นบนแพลตฟอร์ม Arduino ทั้งคู่และลอยเท่ากับที่จะลอย คุณต้องหาไลบรารี Add-in เพื่อจัดการคู่ผสมจริง
kiwiron

คำตอบ:


187

doubleทางเลือกเริ่มต้นสำหรับชนิดลอยจุดที่ควรจะเป็น และนี่ก็เป็นประเภทที่คุณได้รับกับตัวอักษรลอยจุดโดยไม่ต้องต่อท้ายหรือ (ใน C) ฟังก์ชั่นมาตรฐานที่ดำเนินการเกี่ยวกับตัวเลขทศนิยม (เช่นexp, sinฯลฯ )

float ควรใช้หากคุณจำเป็นต้องดำเนินการกับจำนวนจุดลอยตัวจำนวนมาก (คิดตามลำดับหลักพันหรือมากกว่า) และการวิเคราะห์อัลกอริทึมได้แสดงให้เห็นว่าช่วงที่ลดลงและความแม่นยำนั้นไม่ได้เป็นปัญหา

long doubleสามารถใช้งานได้หากคุณต้องการช่วงหรือความแม่นยำมากกว่าdoubleและหากให้สิ่งนี้ในแพลตฟอร์มเป้าหมายของคุณ

โดยสรุปfloatและlong doubleควรสงวนไว้สำหรับการใช้งานโดยผู้เชี่ยวชาญพร้อมdoubleสำหรับการใช้ "ทุกวัน"


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

4
ภาคผนวกหากคุณต้องการความเข้ากันได้กับระบบอื่น ๆ มันจะเป็นประโยชน์ในการใช้ชนิดข้อมูลเดียวกัน
zzzzBov

15
ฉันจะใช้จำนวนลอยหลายล้านไม่ใช่พัน นอกจากนี้ GPU บางตัวยังทำได้ดีกว่าด้วยการลอยในกรณีพิเศษนั้นใช้การลอย อย่างที่คุณพูดให้ใช้คู่ผสม
user949300

4
@PatriciaShanahan - 'ปัญหาประสิทธิภาพที่เกี่ยวข้องกับ .. ' ตัวอย่างที่ดีคือถ้าคุณวางแผนที่จะใช้ SSE2 หรือคำแนะนำเวกเตอร์ที่คล้ายกันคุณสามารถทำได้ 4 ops / vector ใน float (vs 2 ต่อคู่) ซึ่งสามารถปรับปรุงความเร็วได้อย่างมีนัยสำคัญ ( ครึ่งหนึ่งเป็นจำนวนมากและมีข้อมูลให้อ่านและเขียนมากถึงครึ่งหนึ่ง) สิ่งนี้สามารถลดเพดานที่ใช้ลอยได้อย่างมีนัยสำคัญและคุ้มค่ากับปัญหาในการเรียงลำดับปัญหาที่เป็นตัวเลข
greggo

12
ฉันรับรองคำตอบนี้ด้วยคำแนะนำเพิ่มเติมหนึ่งข้อ: เมื่อมีการใช้งานด้วยค่า RGB สำหรับการแสดงผลก็เป็นที่ยอมรับได้ที่จะใช้float(และบางครั้งความแม่นยำครึ่งหนึ่ง) เพราะทั้งสายตามนุษย์จอแสดงผลหรือระบบสีมีความแม่นยำหลายบิต . คำแนะนำนี้ใช้สำหรับพูด OpenGL เป็นต้นคำแนะนำเพิ่มเติมนี้ไม่สามารถใช้ได้กับภาพทางการแพทย์ซึ่งมีข้อกำหนดด้านความแม่นยำที่เข้มงวดมากขึ้น

42

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

เหตุผลหลักที่ฉันคิดว่าจะใช้ลอยคือ:

  1. คุณกำลังจัดเก็บตัวเลขจำนวนมากและจำเป็นต้องลดปริมาณการใช้หน่วยความจำของโปรแกรม
  2. คุณกำลังกำหนดเป้าหมายระบบที่ไม่สนับสนุนจุดลอยตัวที่มีความแม่นยำเป็นสองเท่า จนกระทั่งเมื่อเร็ว ๆ นี้การ์ดกราฟิกจำนวนมากรองรับจุดลอยน้ำที่มีความแม่นยำเพียงจุดเดียว ฉันแน่ใจว่ามีโปรเซสเซอร์พลังงานต่ำและฝังตัวมากมายที่มีข้อ จำกัด ในการรองรับจุดลอยตัวเช่นกัน
  3. คุณกำลังกำหนดเป้าหมายฮาร์ดแวร์ที่มีความแม่นยำเดียวเร็วกว่าความแม่นยำสองเท่าและแอปพลิเคชันของคุณใช้เลขคณิตจุดลอยตัวจำนวนมาก สำหรับซีพียู Intel รุ่นใหม่ฉันเชื่อว่าการคำนวณจุดลอยตัวทั้งหมดทำได้อย่างแม่นยำเป็นสองเท่าดังนั้นคุณจะไม่ได้อะไรเลยที่นี่
  4. คุณกำลังเพิ่มประสิทธิภาพในระดับต่ำเช่นใช้คำสั่ง CPU พิเศษที่ทำงานกับหลายหมายเลขในเวลาเดียวกัน

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


2
"คอมพิวเตอร์สมัยใหม่" หมายถึงโปรเซสเซอร์ Intel x86 เครื่องจักรบางประเภทที่คนโบราณใช้ให้นั้นมีความแม่นยำเพียงพออย่างสมบูรณ์แบบสำหรับประเภทลอยขั้นพื้นฐาน (CDC 6600 ใช้คำ 60 บิต, 48 บิตของ mantissa เลขทศนิยมปกติ 12 บิตของเลขชี้กำลังนั่นเกือบจะเป็นสิ่งที่ x86 ให้คุณเพื่อความแม่นยำสองครั้ง)
จอห์นอาร์ Strohm

@ John.R.Strohm: เห็นด้วย แต่ตัวแปลภาษา C ไม่มีอยู่ใน CDC6600 มันเป็น Fortran IV ...
Basile Starynkevitch

โดย "คอมพิวเตอร์ที่ทันสมัย" ฉันหมายถึงโปรเซสเซอร์ใด ๆ ที่สร้างขึ้นในช่วงสิบหรือสองปีที่ผ่านมาหรือจริงๆแล้วเนื่องจากมาตรฐาน IEEE ของจุดลอยตัวถูกนำมาใช้อย่างกว้างขวาง ฉันตระหนักดีว่ามีสถาปัตยกรรมที่ไม่ใช่ x86 อยู่และคำนึงถึงคำตอบของฉัน - ฉันพูดถึง GPU และตัวประมวลผลแบบฝังซึ่งโดยทั่วไปจะไม่ใช่ x86
user611910

แต่นั่นไม่ใช่ความจริง SSE2 สามารถจัดการ 4 Floats หรือ 2 doubles ในการดำเนินการหนึ่ง AVX สามารถจัดการ 8 Floats หรือ 4 doubles AVX-512 สามารถจัดการ 16 Floats หรือ 8 doubles สำหรับการคำนวณที่มีประสิทธิภาพสูงใด ๆ คณิตศาสตร์เกี่ยวกับการลอยตัวนั้นควรพิจารณาเป็นสองเท่าของความเร็วของการดำเนินการเดียวกันในคู่ที่ x86
Larry Gritz

1
และยิ่งแย่ไปกว่านั้นเนื่องจากคุณสามารถใส่แคชโปรเซสเซอร์ได้สองเท่าตามที่คุณทำได้ด้วยการเพิ่มเป็นสองเท่าและเวลาแฝงหน่วยความจำน่าจะเป็นปัญหาคอขวดหลักในหลาย ๆ โปรแกรม การรักษาชุดการทำงานของโฟลตให้อบอุ่นในแคชอาจเป็นลำดับความสำคัญได้เร็วกว่าการใช้สองเท่าและทำให้มันหกลงบน RAM
Larry Gritz

10

ใช้doubleสำหรับการคำนวณและตัวแปรชั่วคราวทั้งหมดของคุณ ใช้floatเมื่อคุณต้องการที่จะรักษาอาร์เรย์ของตัวเลข - การfloat[](ถ้ามีความแม่นยำก็เพียงพอ) และคุณจะจัดการกับกว่านับหมื่นของfloatตัวเลข

ฟังก์ชันหรือตัวดำเนินการทางคณิตศาสตร์ส่วนใหญ่หรือตัวดำเนินการแปลง / คืนdoubleและคุณไม่ต้องการแปลงตัวเลขกลับไปfloatเป็นขั้นตอนกลาง

เช่นถ้าคุณมีการป้อนข้อมูลของ 100,000 float[]ตัวเลขจากไฟล์หรือกระแสและต้องจัดเรียงพวกเขาใส่ตัวเลขใน


5

บางแพลตฟอร์ม (ARM Cortex-M2, Cortex-M4 และอื่น ๆ ) ไม่รองรับสองครั้ง (สามารถตรวจสอบได้ในคู่มืออ้างอิงสำหรับโปรเซสเซอร์ของคุณหากไม่มีคำเตือนในการรวบรวมหรือข้อผิดพลาดก็ไม่ได้หมายความว่ารหัสนั้นเหมาะสมที่สุดคู่สามารถเทิดทูน.) นั่นคือเหตุผลที่คุณอาจต้องติดintหรือลอย

หากเป็นกรณีที่ไม่ได้ผมจะใช้คู่

คุณสามารถตรวจสอบบทความที่มีชื่อเสียงโดย D. Goldberg ("สิ่งที่นักวิทยาศาสตร์คอมพิวเตอร์ทุกคนควรรู้เกี่ยวกับเลขทศนิยม") คุณควรคิดให้รอบคอบก่อนใช้เลขคณิตทศนิยม มีโอกาสที่ค่อนข้างใหญ่ที่พวกเขาไม่ต้องการเลยในสถานการณ์เฉพาะของคุณ

http://perso.ens-lyon.fr/jean-michel.muller/goldberg.pdf


3
คำถามนี้ได้รับคำตอบค่อนข้างดีเมื่อหนึ่งปีที่แล้ว ... แต่ไม่ว่าในกรณีใดฉันจะบอกว่าเมื่อใดก็ตามที่คุณใช้ double บนแพลตฟอร์มที่มีการเร่งความเร็ว FPU ที่มีความแม่นยำสองเท่าคุณควรจะใช้มันในที่อื่น ๆ ปล่อยให้คอมไพเลอร์เลียนแบบแทนที่จะใช้ประโยชน์จาก FPU ด้วยจุดลอยตัวเท่านั้น (โปรดทราบว่า FPU ไม่จำเป็นต้องใช้บนแพลตฟอร์มทั้งหมดเช่นกันในความเป็นจริงสถาปัตยกรรม Cortex-M4 กำหนดไว้เป็นคุณสมบัติเสริม [M2 เป็นตัวพิมพ์ผิดหรือไม่?] )
Selali Adobor

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

2
เมื่อรวมลิงค์ไปยังหน้าเว็บไซต์หรือเอกสารกรุณาคัดลอกข้อมูลที่เกี่ยวข้องหรือข้อมูลสรุปจากเอกสารไปยังคำตอบของคุณ การเชื่อมโยงนอกไซต์มีแนวโน้มที่จะหายไปเมื่อเวลาผ่านไป
Adam Zuckerman

3

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

ตัวอย่างโลกแห่งความจริงส่วนใหญ่ จำกัด ไว้ที่ 24 บิต DAC s แนะนำว่าความแม่นยำ 32 บิตสำหรับการคำนวณในโลกแห่งความเป็นจริงควรจะเพียงพอโดยที่ซิกนิฟิแคนด์นั้นมีความแม่นยำ 24 บิต

ความแม่นยำสองเท่านั้นมาพร้อมกับหน่วยความจำ 2x ดังนั้นการ จำกัด การใช้งานของคู่มากกว่าลอยสามารถตัดรอยหน่วยความจำ / แบนด์วิดธ์ของการใช้งานอย่างมาก


-3

ทางเลือกของตัวแปรที่จะใช้ระหว่างการลอยตัวและการดับเบิลขึ้นอยู่กับความถูกต้องของข้อมูลที่ต้องการ หากคำตอบจำเป็นต้องมีความแตกต่างเล็กน้อยจากคำตอบจริงจำนวนตำแหน่งทศนิยมที่ต้องการจะมีจำนวนมากดังนั้นจะกำหนดให้ใช้เป็นสองเท่า


3
คำตอบนี้ไม่ได้เพิ่มอะไรใหม่ให้กับคำถามและไม่สามารถพูดสิ่งที่ใช้จริงได้
Martijn Pieters

-5

โดยปกติแล้วฉันใช้floatประเภทเมื่อฉันไม่ต้องการความแม่นยำมาก - ตัวอย่างเช่นสำหรับเงิน - ซึ่งผิด แต่เป็นสิ่งที่ฉันเคยทำผิด

ในทางตรงกันข้ามฉันใช้doubleเมื่อฉันต้องการความแม่นยำมากขึ้นเช่นอัลกอริทึมทางคณิตศาสตร์ที่ซับซ้อน

มาตรฐาน C99 บอกสิ่งนี้:

จุดลอยมีสามประเภท: ลอยคู่และยาว ประเภทคู่ให้ความแม่นยำอย่างน้อยเท่ากับลอยและประเภทยาวคู่ให้ความแม่นยำเท่ากับคู่อย่างน้อย ชุดของค่าของประเภทลอยเป็นส่วนย่อยของชุดค่าของประเภทคู่; ชุดของค่าของ type double เป็นชุดย่อยของชุดค่าของ type long double

ฉันไม่เคยใช้จริง ๆlong doubleแต่ฉันไม่ได้ใช้ C / C ++ มากนัก ฉันมักจะใช้ภาษาที่พิมพ์แบบไดนามิกเช่น Python ที่คุณไม่ต้องสนใจเกี่ยวกับประเภท

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคู่ VS ลอยดูคำถามนี้ที่ SO


25
การใช้จุดลอยตัวสำหรับการคำนวณเงินอย่างจริงจังอาจเป็นความผิดพลาด
Bart van Ingen Schenau

17
ลอยเป็นประเภทที่ผิดสำหรับเงิน คุณต้องใช้ความแม่นยำสูงสุดเท่าที่จะทำได้
ChrisF

8
@BartvanIngenSchenau จุดลอยเงินมักจะไม่เป็นไรจุดลอยตัวไบนารีไม่ได้ ตัวอย่างเช่น. net Decimalเป็นประเภททศนิยมและโดยทั่วไปจะเป็นทางเลือกที่ดีสำหรับการคำนวณเงิน
CodesInChaos

13
@ChrisF คุณไม่ต้องการ "ความแม่นยำสูง" สำหรับเงินคุณต้องมีค่าที่แน่นอน
Sean McSomething

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