ฉันแนะนำ @Jens Gustedt วิธีแก้ปัญหาเลขฐานสิบหก: ใช้% a
OP ต้องการ "พิมพ์ด้วยความแม่นยำสูงสุด (หรืออย่างน้อยก็ถึงทศนิยมที่สำคัญที่สุด)"
ตัวอย่างง่ายๆคือการพิมพ์หนึ่งในเจ็ดใน:
#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01
แต่มาเจาะลึก ...
ในทางคณิตศาสตร์คำตอบคือ "0.142857 142857 142857 ... " แต่เราใช้ตัวเลขทศนิยมที่มีความแม่นยำ จำกัด สมมติIEEE 754 แม่นยำสองไบนารี ดังนั้นOneSeventh = 1.0/7.0
ผลลัพธ์ในค่าด้านล่าง นอกจากนี้ยังแสดงเป็นตัวเลขdouble
ทศนิยมที่แสดงก่อนหน้าและต่อไปนี้
OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after = 0.1428571428571428 769682682968777953647077083587646484375
การพิมพ์การแทนค่าทศนิยมที่แน่นอนdouble
มีการใช้งานที่ จำกัด
C มีมาโคร 2 ตระกูล<float.h>
เพื่อช่วยเรา
ชุดแรกคือจำนวนหลักสำคัญที่จะพิมพ์เป็นสตริงเป็นทศนิยมดังนั้นเมื่อสแกนสตริงกลับเราจะได้จุดลอยตัวเดิม มีการแสดงด้วยค่าต่ำสุดของข้อมูลจำเพาะ C และตัวอย่างคอมไพเลอร์ C11
FLT_DECIMAL_DIG 6, 9 (float) (C11)
DBL_DECIMAL_DIG 10, 17 (double) (C11)
LDBL_DECIMAL_DIG 10, 21 (long double) (C11)
DECIMAL_DIG 10, 21 (widest supported floating type) (C99)
ชุดที่สองคือจำนวนหลักสำคัญที่สตริงอาจถูกสแกนลงในทศนิยมแล้วพิมพ์ FP โดยยังคงนำเสนอสตริงเดิม มีการแสดงด้วยค่าต่ำสุดของข้อมูลจำเพาะ C และตัวอย่างคอมไพเลอร์ C11 ฉันเชื่อว่ามีจำหน่ายก่อน C99
FLT_DIG 6, 6 (float)
DBL_DIG 10, 15 (double)
LDBL_DIG 10, 18 (long double)
มาโครชุดแรกดูเหมือนจะตรงตามเป้าหมายของ OP ในเรื่องเลขนัยสำคัญ แต่มาโครนั้นไม่สามารถใช้ได้เสมอไป
#ifdef DBL_DECIMAL_DIG
#define OP_DBL_Digs (DBL_DECIMAL_DIG)
#else
#ifdef DECIMAL_DIG
#define OP_DBL_Digs (DECIMAL_DIG)
#else
#define OP_DBL_Digs (DBL_DIG + 3)
#endif
#endif
"+ 3" คือหัวใจสำคัญของคำตอบก่อนหน้านี้ของฉัน โดยเน้นที่การทราบสตริงการแปลงแบบไปกลับ - FP-string (ชุด # 2 มาโครที่มี C89) จะกำหนดตัวเลขสำหรับ FP-string-FP ได้อย่างไร (ตั้งค่ามาโคร # 1 ที่มีให้โพสต์ C89) โดยทั่วไปแล้วการบวก 3 คือผลลัพธ์
ตอนนี้วิธีการหลายอย่างมีนัยสำคัญ<float.h>
หลักในการพิมพ์เป็นที่รู้จักกันและขับรถผ่าน
ในการพิมพ์เลขทศนิยมที่มีนัยสำคัญ N หลักหนึ่งอาจใช้รูปแบบต่างๆ
ด้วยความ"%e"
ที่มีความแม่นยำฟิลด์คือจำนวนตัวเลขหลังหลักนำและจุดทศนิยม ดังนั้น- 1
ในการสั่งซื้อ หมายเหตุ: นี่-1
ไม่ได้อยู่ในการเริ่มต้นint Digs = DECIMAL_DIG;
printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01
ด้วยความ"%f"
ที่มีความแม่นยำฟิลด์คือจำนวนตัวเลขหลังจุดทศนิยม สำหรับตัวเลขเช่นOneSeventh/1000000.0
เราจะต้องOP_DBL_Digs + 6
เห็นเลขนัยสำคัญทั้งหมด
printf("%.*f\n", OP_DBL_Digs , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285
หมายเหตุ: "%f"
จำนวนมากที่มีการใช้งานเพื่อ ที่แสดง 6 หลักหลังจุดทศนิยม; 6 เป็นค่าเริ่มต้นของการแสดงผลไม่ใช่ความแม่นยำของตัวเลข