ดังนั้นฉันจึงได้คำตอบสำหรับคำถามสุดท้ายของฉัน(ฉันไม่รู้ว่าทำไมฉันไม่คิดอย่างนั้น) ฉันกำลังพิมพ์การdouble
ใช้cout
ที่ปัดเศษเมื่อฉันไม่ได้คาดหวัง ฉันจะcout
พิมพ์double
ด้วยความแม่นยำได้อย่างไร
ดังนั้นฉันจึงได้คำตอบสำหรับคำถามสุดท้ายของฉัน(ฉันไม่รู้ว่าทำไมฉันไม่คิดอย่างนั้น) ฉันกำลังพิมพ์การdouble
ใช้cout
ที่ปัดเศษเมื่อฉันไม่ได้คาดหวัง ฉันจะcout
พิมพ์double
ด้วยความแม่นยำได้อย่างไร
คำตอบ:
คุณสามารถตั้งค่าความแม่นยำได้โดยตรงstd::cout
และใช้ตัวstd::fixed
ระบุรูปแบบ
double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;
คุณสามารถที่#include <limits>
จะได้รับความแม่นยำสูงสุดของการลอยหรือสองครั้ง
#include <limits>
typedef std::numeric_limits< double > dbl;
double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
cout.precision(numeric_limits<double>::digits10 + 2);
ฉันจะได้รับเพียง 16 ....
max_digits10
เพื่อแสดงถึงสิ่งเดียวกัน แก้ไขคำตอบเพื่อสะท้อนสิ่งนี้
การใช้std::setprecision
:
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
std::setprecision (17)
สองเท่าดูความคิดเห็นเกี่ยวกับคำตอบของ @Bill The Lizard
นี่คือสิ่งที่ฉันจะใช้:
std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
<< 3.14159265358979
<< std::endl;
โดยทั่วไปแพคเกจ จำกัด มีลักษณะสำหรับการสร้างในทุกประเภท
หนึ่งในลักษณะของเลขทศนิยม (ลอย / สองครั้ง / ยาวคู่) คือคุณลักษณะ สิ่งนี้กำหนดความถูกต้อง (ฉันลืมคำศัพท์ที่แน่นอน) ของเลขทศนิยมในฐาน 10
ดู: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
สำหรับรายละเอียดเกี่ยวกับคุณลักษณะอื่น ๆ
std::setprecision()
: #include <iomanip>
std::numeric_limits<double>
เป็นnumberic_limits<double>
1
ไปstd::numeric_limits<double>::digits10
?
max_digits10
digits10+2
มิฉะนั้นในกรณีของfloat
, long double
, boost::multiprecision::float128
นี้จะล้มเหลวเนื่องจากมีคุณจะต้องแทน+3
+2
วิธี iostreams เป็นประเภทของ clunky ฉันชอบที่จะใช้boost::lexical_cast
เพราะมันคำนวณความแม่นยำที่เหมาะสมสำหรับฉัน และมันก็เร็วเช่นกัน
#include <string>
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;
using std::string;
double d = 3.14159265358979;
cout << "Pi: " << lexical_cast<string>(d) << endl;
เอาท์พุท:
Pi: 3.14159265358979
โดยความแม่นยำเต็มที่ฉันถือว่าความแม่นยำเพียงพอที่จะแสดงการประมาณค่าที่ดีที่สุด แต่ควรชี้ให้เห็นว่าdouble
ถูกเก็บไว้โดยใช้การแสดงฐาน 2 และฐาน 2 ไม่สามารถแสดงสิ่งที่เล็กน้อยได้อย่าง1.1
แน่นอน วิธีเดียวที่จะได้รับความแม่นยำเต็มรูปแบบของ double double (ไม่มีข้อผิดพลาดรอบนอก) คือการพิมพ์บิตไบนารี่ (หรือ hex nybbles) วิธีหนึ่งในการทำเช่นนั้นคือการเขียนdouble
a ไปยังunion
จากนั้นพิมพ์ค่าจำนวนเต็มของบิต
union {
double d;
uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;
สิ่งนี้จะให้ความแม่นยำที่ถูกต้อง 100% ของ double ... และไม่สามารถอ่านได้อย่างเต็มที่เนื่องจากมนุษย์ไม่สามารถอ่านรูปแบบ double IEEE ได้! Wikipediaมีการเขียนที่ดีเกี่ยวกับวิธีตีความบิตไบนารี่
ใน C ++ ที่ใหม่กว่าคุณสามารถทำได้
std::cout << std::hexfloat << 1.1;
นี่คือวิธีการแสดงสองครั้งด้วยความแม่นยำเต็มรูปแบบ:
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;
สิ่งนี้แสดง:
100.0000000000005
max_digits10 เป็นจำนวนหลักที่จำเป็นในการแสดงค่าสองเท่าที่แตกต่างกันโดยเฉพาะ max_digits10 หมายถึงจำนวนหลักก่อนและหลังจุดทศนิยม
อย่าใช้ set_precision (max_digits10) กับ std :: fixed
สัญกรณ์คงที่ set_precision () ตั้งค่าจำนวนหลักหลังจุดทศนิยม สิ่งนี้ไม่ถูกต้องเนื่องจาก max_digits10 แสดงถึงจำนวนหลักก่อนและหลังจุดทศนิยม
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;
สิ่งนี้แสดงผลลัพธ์ที่ไม่ถูกต้อง:
100.00000000000049738
หมายเหตุ: จำเป็นต้องใช้ไฟล์ส่วนหัว
#include <iomanip>
#include <limits>
100.0000000000005
double
(อาจดูเหมือนควร แต่ไม่เพราะได้รับมาตรฐานคือการแสดงไบนารีของมัน) 100.0000000000005 - 100
ที่เห็นนี้ลอง: 4.973799150320701e-13
เราได้รับ
ฉันจะพิมพ์
double
ค่าด้วยความแม่นยำเต็มที่ใช้ cout ได้อย่างไร
ใช้hexfloat
หรือ
ใช้scientific
และตั้งค่าความแม่นยำ
std::cout.precision(std::numeric_limits<double>::max_digits10 - 1);
std::cout << std::scientific << 1.0/7.0 << '\n';
// C++11 Typical output
1.4285714285714285e-01
มีคำตอบมากเกินไปที่จะระบุเพียงหนึ่งใน 1) ฐาน 2) รูปแบบคงที่ / วิทยาศาสตร์หรือ 3) ความแม่นยำ คำตอบที่มากเกินไปอย่างแม่นยำไม่ได้ให้ค่าที่เหมาะสม ดังนั้นคำตอบนี้เป็นคำถามเก่า
double
มีการเข้ารหัสอย่างแน่นอนโดยใช้ฐาน 2. วิธีการโดยตรงกับ C ++ 11 std::hexfloat
คือการพิมพ์โดยใช้
หากยอมรับเอาต์พุตที่ไม่ใช่ทศนิยมเราจะเสร็จสิ้น
std::cout << "hexfloat: " << std::hexfloat << exp (-100) << '\n';
std::cout << "hexfloat: " << std::hexfloat << exp (+100) << '\n';
// output
hexfloat: 0x1.a8c1f14e2af5dp-145
hexfloat: 0x1.3494a9b171bf5p+144
fixed
หรือscientific
?double
เป็นจุดลอยชนิดไม่จุดคงที่
อย่าได้ใช้std::fixed
เป็นที่ล้มเหลวในการพิมพ์ขนาดเล็กdouble
เป็นอะไร 0.000...000
แต่ สำหรับขนาดใหญ่double
มันพิมพ์ตัวเลขจำนวนมากบางทีหลายร้อยข้อมูลที่น่าสงสัย
std::cout << "std::fixed: " << std::fixed << exp (-100) << '\n';
std::cout << "std::fixed: " << std::fixed << exp (+100) << '\n';
// output
std::fixed: 0.000000
std::fixed: 26881171418161356094253400435962903554686976.000000
หากต้องการพิมพ์ด้วยความแม่นยำอย่างสมบูรณ์ให้ใช้งานครั้งแรกstd::scientific
ซึ่งจะ "เขียนค่าทศนิยมในเครื่องหมายทางวิทยาศาสตร์" สังเกตุค่าเริ่มต้นของตัวเลข 6 หลักหลังจากจุดทศนิยมซึ่งเป็นจำนวนที่ไม่เพียงพอจะถูกจัดการในจุดถัดไป
std::cout << "std::scientific: " << std::scientific << exp (-100) << '\n';
std::cout << "std::scientific: " << std::scientific << exp (+100) << '\n';
// output
std::scientific: 3.720076e-44
std::scientific: 2.688117e+43
การdouble
เข้ารหัสโดยใช้ฐานฐาน 2 เข้ารหัสความแม่นยำเดียวกันระหว่างอำนาจต่าง ๆ ของ 2 ซึ่งมักเป็น 53 บิต
[1.0 ... 2.0) มี 2 53ที่แตกต่างกันdouble
,
[2.0 ... 4.0) มี 2 53ที่แตกต่างกันdouble
,
[4.0 ... 8.0) มี 2 53ที่แตกต่างกันdouble
,
[8.0 ... 10.0) มี 2 / 8 * 2 53double
ที่แตกต่างกัน
แต่ถ้าพิมพ์รหัสในทศนิยมกับN
เลขนัยสำคัญจำนวนรวมกัน [1.0 ... 10.0) เป็น 9/10 * 10 N
สิ่งที่เลือกN
(ความแม่นยำ) จะไม่มีการแมปแบบหนึ่งต่อหนึ่งระหว่างdouble
ข้อความทศนิยม หากเลือกค่าคงที่N
บางครั้งมันจะมากหรือน้อยกว่าที่จำเป็นจริงๆสำหรับdouble
ค่าบางอย่าง เราอาจผิดพลาดน้อยเกินไป ( a)
ด้านล่าง) หรือมากเกินไป ( b)
ด้านล่าง)
3 ผู้สมัครN
:
ก) ใช้N
ดังนั้นเมื่อมีการแปลงจากแอปรับส่งข้อความdouble
-text double
เรามาถึงข้อความเดียวกันทั้งหมด
std::cout << dbl::digits10 << '\n';
// Typical output
15
ข) ใช้N
ดังนั้นเมื่อมีการแปลงจากdouble
-text- double
เรามาถึงในเวลาเดียวกันทั้งหมดdouble
double
// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17
เมื่อmax_digits10
ไม่สามารถใช้งานได้โปรดทราบว่าเนื่องจากแอตทริบิวต์ 2 ฐานและ 10 ฐานdigits10 + 2 <= max_digits10 <= digits10 + 3
เราสามารถใช้digits10 + 3
เพื่อพิมพ์ตัวเลขทศนิยมให้เพียงพอ
c) ใช้สิ่งN
ที่แตกต่างกันไปตามค่า
สิ่งนี้มีประโยชน์เมื่อโค้ดต้องการแสดงข้อความน้อยที่สุด ( N == 1
) หรือค่าที่แน่นอนของ a double
( N == 1000-ish
ในกรณีของdenorm_min
) แต่เนื่องจากนี่คือ "งาน" และไม่น่าจะเป็นเป้าหมายของ OP ก็จะถูกตั้งสำรอง
โดยปกติจะเป็น b) ที่ใช้เพื่อ "พิมพ์double
ค่าด้วยความแม่นยำเต็มที่" แอปพลิเคชันบางอย่างอาจต้องการ a) ข้อผิดพลาดในการไม่ให้ข้อมูลมากเกินไป
ด้วย.scientific
, .precision()
ชุดจำนวนของตัวเลขที่จะพิมพ์หลังจุดทศนิยมดังนั้น1 + .precision()
ตัวเลขจะพิมพ์ รหัสความต้องการmax_digits10
หลักทั้งหมดดังนั้นจะเรียกว่ามี.precision()
max_digits10 - 1
typedef std::numeric_limits< double > dbl;
std::cout.precision(dbl::max_digits10 - 1);
std::cout << std::scientific << exp (-100) << '\n';
std::cout << std::scientific << exp (+100) << '\n';
// Typical output
3.7200759760208361e-44
2.6881171418161356e+43
//1234567890123456 17 total digits
precision()
กำหนดจำนวนตำแหน่งทศนิยมสำหรับโหมดทางวิทยาศาสตร์ โดยไม่ได้ระบุscientific
มันตั้งค่าจำนวนหลักทั้งหมดไม่รวมเลขชี้กำลัง คุณอาจยังคงจบด้วยผลลัพธ์ทางวิทยาศาสตร์ขึ้นอยู่กับค่าหมายเลขของคุณ แต่คุณอาจได้รับตัวเลขน้อยกว่าที่คุณระบุ ตัวอย่าง: cout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"
ผลลัพธ์สำหรับprintf
อาจแตกต่างกัน สิ่งที่สับสนควรระวัง
char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);
อักขระพิเศษใช้สำหรับ: เครื่องหมายทศนิยมจุดทศนิยมต่อท้ายศูนย์ e [+ | -] 3 หลักสำหรับเลขชี้กำลัง ( DBL_MAX_10_EXP = 308) ดังนั้นจำนวนอักขระที่ต้องการทั้งหมดคือ 25
printf("%.12f", M_PI);
% .12f หมายถึงจุดลอยตัวที่มีความแม่นยำ 12 หลัก
ส่วนใหญ่พกพา ...
#include <limits>
using std::numeric_limits;
...
cout.precision(numeric_limits<double>::digits10 + 1);
cout << d;
ด้วย ostream :: ความแม่นยำ (int)
cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;
จะให้ผลผลิต
3.141592653589793, 2.718281828459045
ทำไมคุณต้องพูดว่า "+1" ฉันไม่มีเงื่อนงำ แต่ตัวเลขพิเศษที่คุณได้รับนั้นถูกต้อง
สิ่งนี้จะแสดงค่าสูงสุดทศนิยมสองตำแหน่งหลังจุด
#include <iostream>
#include <iomanip>
double d = 2.0;
int n = 2;
cout << fixed << setprecison(n) << d;
ดูที่นี่: สัญกรณ์จุดคงที่
ใช้สัญกรณ์จุดลอยตัวแบบคงที่ตั้งค่าสถานะรูปแบบ floatfield สำหรับ str สตรีมเป็นคงที่
เมื่อมีการตั้งค่า floatfield เป็นค่าคงที่ค่าจุดลอยตัวจะถูกเขียนโดยใช้เครื่องหมายจุดคงที่: ค่าจะถูกแสดงด้วยตัวเลขหลายหลักในส่วนทศนิยมตามที่ระบุโดยเขตความแม่นยำ (ความแม่นยำ) และไม่มีส่วนเลขชี้กำลัง
ตั้งค่าความแม่นยำทศนิยมตั้งค่าความแม่นยำทศนิยมที่จะใช้ในการจัดรูปแบบค่าทศนิยมในการดำเนินงานการส่งออก
หากคุณคุ้นเคยกับมาตรฐาน IEEE สำหรับการแสดงคะแนนแบบลอยตัวคุณจะรู้ว่าเป็นไปไม่ได้ที่จะแสดงคะแนนแบบลอยที่มีความแม่นยำเต็มรูปแบบนอกขอบเขตของมาตรฐานนั่นคือการบอกว่ามันจะส่งผลเสมอ การปัดเศษของมูลค่าที่แท้จริง
คุณต้องตรวจสอบก่อนว่าค่านั้นอยู่ในขอบเขตหรือไม่ถ้าใช่ให้ใช้:
cout << defaultfloat << d ;
ใช้สัญกรณ์จุดลอยตัวเริ่มต้นตั้งค่าสถานะการจัดรูปแบบ floatfield สำหรับ str สตรีมเป็น defaultfloat
เมื่อ floatfield ถูกตั้งค่าเป็น defaultfloat ค่าจุดลอยตัวจะถูกเขียนโดยใช้สัญกรณ์เริ่มต้น: การแทนค่าใช้ตัวเลขที่มีความหมายมากเท่าที่ต้องการจนถึงความแม่นยำทศนิยมของสตรีม (ความแม่นยำ) นับทั้งตัวเลขก่อนและหลังจุดทศนิยม )
นั่นเป็นพฤติกรรมเริ่มต้นของcout
ซึ่งหมายความว่าคุณไม่ได้ใช้อย่างชัดเจน
fixed
? ด้วยdouble h = 6.62606957e-34;
,fixed
ให้ฉัน0.000000000000000
และเอาท์พุทscientific
6.626069570000000e-34