วิธีป้องกันไม่ให้ ostringstream (หรือคล้ายกัน) ส่งออกสัญกรณ์ทางวิทยาศาสตร์โดยไม่ต้องตั้งค่าความแม่นยำ

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

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

นี่คือตัวอย่างสิ่งที่ฉันตามหา:

let: tau = 6.2831

tau * 0.000001 -> 0.0000062831
tau * 0.001    -> 0.0062831
tau            -> 6.2831
tau * 1000     -> 6283.1
tau * 1000000  -> 6283100

ในขณะนี้ฉันได้รับ:

tau * 0.000001 -> 6.2831e-006
tau * 0.001    -> 0.0062831
tau            -> 6.2831
tau * 1000     -> 6283.1
tau * 1000000  -> 6.2831e+006

สิ่งเดียวที่ฉันทำได้คือแยกเลขชี้กำลังของค่าสองเท่าออก ถ้าเลขชี้กำลังเป็นบวก 'แก้ไข' ความแม่นยำให้เป็นศูนย์ ไม่อย่างนั้นก็ตั้งค่าความแม่นยำเป็น '-1 * exp'; แต่นี่ดูเหมือนเป็นวิธีที่ซับซ้อนอย่างยิ่งในการ 'ปิด' สัญกรณ์ทางวิทยาศาสตร์ มีใครรู้วิธีที่ดีกว่านี้บ้างไหม?


person user1277997    schedule 19.03.2012    source แหล่งที่มา
comment
เห็นได้ชัดว่าคุณมีปัญหากับเช่น tau * 1e-80 นั่นอาจเป็นสาเหตุที่ไม่มีวิธีแก้ปัญหาง่ายๆ — BTW เกิดอะไรขึ้นกับ tau * 1000000 -> 6.2831e-006?   -  person leftaroundabout    schedule 19.03.2012
comment
ปัญหาคือเศษส่วนทศนิยมส่วนใหญ่ไม่สามารถแสดงด้วยเลขทศนิยมแบบไบนารี่ได้ทั้งหมด (ซึ่งการใช้งาน C++ แทบทุกครั้งจะใช้สำหรับประเภทจุดลอยตัวในตัว) ตัวอย่างเช่น บนคอมพิวเตอร์ของฉัน ถ้าฉันกำหนด float tau = 6.2831 ค่าจริงจะเป็น 6.283100128173828125 ตัวจัดรูปแบบไม่มีทางรู้ได้ว่าตัวเลข 14 หลักสุดท้ายเกิดจากข้อผิดพลาดในการปัดเศษ   -  person Mike Seymour    schedule 19.03.2012
comment
ในความเป็นจริง แม้มันจะ สามารถ แทน 6.2831 เป๊ะๆ ได้ แต่ก็ยังเท่ากับ 6.28310 ไม่มีสิ่งที่เรียกว่าศูนย์ที่ไม่จำเป็นในการแสดงขนาดคงที่ หากคุณต้องการแยกความแตกต่างระหว่าง 6.2831 และ 6.28310 คุณจะต้องใช้ std::string   -  person MSalters    schedule 19.03.2012
comment
ขออภัย ฉันมี -006 ตอนที่ฉันหมายถึง +006 ที่นั่น ขอโทษด้วยกับเรื่องนั้น.   -  person user1277997    schedule 19.03.2012
comment
ตอนนี้การขยาย tau * 1e-80 อาจก่อให้เกิดปัญหา แต่ฉันรับรองได้ว่ามันจะทำให้เกิดปัญหาน้อยกว่าการเขียน ...e+80 เนื่องจาก parser ที่ใช้เอาต์พุต chuck จะสั่นคลอนอย่างมากทุกครั้งที่พบ e เท่าที่ฉันรู้มันจะแยกวิเคราะห์ 0.0000...001 ได้ดี   -  person user1277997    schedule 19.03.2012


คำตอบ (1)


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

น่าเศร้าที่ IO ที่จัดรูปแบบใน C++ (และใน C) ไม่มีวิธีที่จะขอให้ใช้อัลกอริธึมเหล่านั้น %g ของ printf และการตั้งค่าเริ่มต้นของ IOStream นั้นใกล้เคียงที่สุด แต่ควบคู่ไปกับตัวเลือกอัตโนมัติระหว่างสัญกรณ์แบบตายตัวและแบบวิทยาศาสตร์ พวกเขาต้องการความแม่นยำสูงสุดและการกำจัดจุดสิ้นสุด 0 นั้นไม่เหมือนกันจริงๆ (พวกมันทำหน้าที่ การแสดงทศนิยมที่แน่นอน พวกเขาไม่ได้พยายามค้นหารูปแบบที่ง่ายที่สุด)

โปรดทราบว่าอัลกอริธึมเหล่านี้ไม่ง่ายนัก แต่ต้องใช้เลขคณิตแบบหลายความแม่นยำ

person AProgrammer    schedule 19.03.2012