निर्दिष्ट दशमलव अंकों की सटीक और संख्या के साथ फ्लोट को स्ट्रिंग में बदलें?


88

दशमलव अंकों की शुद्धता और संख्या को निर्दिष्ट करते हुए आप C ++ में एक फ्लोट को स्ट्रिंग में कैसे परिवर्तित करते हैं?

उदाहरण के लिए: 3.14159265359 -> "3.14"


क्यों नहीं आप चाहते हैं और फिर इसे स्ट्रिंग में परिवर्तित निर्दिष्ट परिशुद्धता के साथ एक अस्थायी नाव का निर्माण?
गिलाद

@ गिलाद 'अस्थायी फ़्लोट' में 'निर्दिष्ट परिशुद्धता' नहीं होती है और ऐसे मामले होते हैं जब ऐसा दृष्टिकोण टूट जाएगा। यह प्रश्न मूल रूप से यह पूछने की तरह है कि "% .2f 'प्रारूप के समकक्ष क्या है?"
user2864740

1
अगर यह सिर्फ IO की जरूरत है तो stackoverflow.com/questions/14432043/c-float-formatting देखें ।
user2864740

जवाबों:


131

उपयोग करने के लिए एक विशिष्ट तरीका होगा stringstream:

#include <iomanip>
#include <sstream>

double pi = 3.14159265359;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << pi;
std::string s = stream.str();

तय देखें

निश्चित फ़्लोटिंग-पॉइंट नोटेशन का उपयोग करें

स्ट्रेट स्ट्रीम के floatfieldलिए प्रारूप ध्वज सेट करता हैfixed

जब floatfieldसेट किया जाता है fixed, फ़्लोटिंग-पॉइंट वैल्यूज़ को निश्चित-पॉइंट नोटेशन का उपयोग करके लिखा जाता है: मान को दशमलव क्षेत्र में सटीक रूप से कई अंकों के साथ दर्शाया जाता है, जैसा कि सटीक फ़ील्ड ( precision) के साथ और बिना किसी एक्सपोनेंट भाग के निर्दिष्ट किया गया है ।

और असफलता


तकनीकी उद्देश्य के रूपांतरण के लिए , XML या JSON फ़ाइल में डेटा संग्रहीत करने के लिए, C ++ 17 to_chars को परिभाषित करता है कार्यों का परिवार।

एक आज्ञाकारी संकलक (जो हमारे पास लेखन के समय कमी है) को मानते हुए, कुछ इस तरह से माना जा सकता है:

#include <array>
#include <charconv>

double pi = 3.14159265359;
std::array<char, 128> buffer;
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), pi,
                               std::chars_format::fixed, 2);
if (ec == std::errc{}) {
    std::string s(buffer.data(), ptr);
    // ....
}
else {
    // error handling
}

28

इस तरह की करने के लिए प्रथागत पद्धति "प्रिंट टू स्ट्रिंग" है। C ++ में इसका मतलब है कि std::stringstreamकुछ का उपयोग करना:

std::stringstream ss;
ss << std::fixed << std::setprecision(2) << number;
std::string mystring = ss.str();

12

एक अन्य विकल्प है snprintf:

double pi = 3.1415926;

std::string s(16, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.2f", pi);
s.resize(written);

डेमो । त्रुटि हैंडलिंग को जोड़ा जाना चाहिए, अर्थात के लिए जाँच करनाwritten < 0


snprintfइस मामले में बेहतर क्यों होगा ? कृपया समझाएं ... यह निश्चित रूप से तेज नहीं होगा, कम कोड का उत्पादन करेगा [मैंने एक प्रिंटफ कार्यान्वयन लिखा है, यह कोड के 2000 लाइनों के तहत बिल्कुल कॉम्पैक्ट है, लेकिन मैक्रो विस्तार के साथ लगभग 2500 लाइनें मिलती हैं]
मैट पीटरसन

1
@MatsPetersson मेरा मानना ​​है कि यह तेज़ होगा। यही कारण है कि मैंने पहली बार में इसका जवाब दिया।
कोलंबो

@MatsPetersson मैंने माप (GCC 4.8.1, -O2) का प्रदर्शन किया है जो दर्शाता है कि वास्तव में स्निपरफ को कारक 17/22 से कम समय लग रहा है। मैं शीघ्र ही कोड अपलोड कर दूंगा।
कोलम्बो

@MatsPetersson मेरा बेंचमार्क शायद त्रुटिपूर्ण है, लेकिन स्ट्रिंगस्ट्रीम संस्करण 1000000 पुनरावृत्तियों (Clang 3.7.0, libstdc ++, -O2) में स्निपर संस्करण के रूप में दो बार लेता है।

मैंने कुछ माप भी किए - और यह कम से कम (लिनक्स पर) प्रतीत होता है कि दोनों स्ट्रिंगस्ट्रीम और स्निप्रफ एक ही अंतर्निहित __printf_fpकार्यक्षमता का उपयोग करते हैं - यह अजीब है कि इसमें इतना लंबा समय लगता है stringstream, जैसा कि वास्तव में नहीं होना चाहिए।
मैट पीटरसन

9

आप {fmt} लाइब्रेरीfmt::format से फ़ंक्शन का उपयोग कर सकते हैं :

#include <fmt/core.h>

int main()
  std::string s = fmt::format("{:.2f}", 3.14159265359); // s == "3.14"
}

कहाँ पे 2 सटीक है।

यह स्वरूपण सुविधा C ++: P0645 में मानकीकरण के लिए प्रस्तावित की गई है । P0645 और {fmt} दोनों एक पायथन-जैसे प्रारूप स्ट्रिंग सिंटैक्स का उपयोग करते हैं जो कि printf's के समान है , लेकिन {}इसके बजाय सीमांकक के रूप में उपयोग करता है %


7

यहाँ केवल एसटीडी का उपयोग कर एक समाधान। हालाँकि, ध्यान दें कि यह केवल गोल है।

    float number = 3.14159;
    std::string num_text = std::to_string(number);
    std::string rounded = num_text.substr(0, num_text.find(".")+3);

इसके लिए roundedपैदावार:

3.14

कोड पूरे फ़्लोट को स्ट्रिंग में कनवर्ट करता है, लेकिन "के बाद सभी वर्ण 2 वर्ण काटता है।"


केवल बात यह है कि इस तरह से आप वास्तव में संख्या को गोल नहीं कर रहे हैं।
ChrCury78

1
@ ChrCury78 जैसा कि मेरे जवाब में कहा गया है कि यह केवल गोल है। यदि आप एक सामान्य गोलाई चाहते हैं तो अपने मान के अनुसार केवल 5 डिगेट में जोड़ें। number + 0.005मेरे मामले में उदाहरण के लिए ।
सेबस्टियन आर।

2

यहां मैं एक नकारात्मक उदाहरण प्रदान कर रहा हूं जहां आपकी संख्या फ्लोटिंग संख्या को स्ट्रिंग्स में परिवर्तित करने से बचना चाहती है।

float num=99.463;
float tmp1=round(num*1000);
float tmp2=tmp1/1000;
cout << tmp1 << " " << tmp2 << " " << to_string(tmp2) << endl;

आपको मिला

99463 99.463 99.462997

नोट: संख्या चर 99.463 के करीब कोई भी मूल्य हो सकता है, आपको एक ही प्रिंट आउट मिलेगा। बिंदु सुविधाजनक c ++ 11 "to_string" फ़ंक्शन से बचने के लिए है। इस जाल से निकलने में मुझे थोड़ा समय लगा। सबसे अच्छा तरीका स्ट्रिंगस्ट्रीम और स्प्रिंटफ तरीके (सी भाषा) है। C ++ 11 या नए को फ्लोटिंग पॉइंट दिखाने के बाद अंकों की संख्या के रूप में एक दूसरा पैरामीटर प्रदान करना चाहिए। अभी डिफ़ॉल्ट 6 है। मैं इसे प्रस्तुत कर रहा हूं ताकि अन्य लोग इस विषय पर समय बर्बाद न करें।

मैंने अपना पहला संस्करण लिखा, कृपया मुझे बताएं कि क्या आपको कोई बग मिला है जिसे ठीक करने की आवश्यकता है। आप iomanipulator के साथ सटीक व्यवहार को नियंत्रित कर सकते हैं। मेरा कार्य दशमलव बिंदु के बाद अंकों की संख्या दिखाने के लिए है।

string ftos(float f, int nd) {
   ostringstream ostr;
   int tens = stoi("1" + string(nd, '0'));
   ostr << round(f*tens)/tens;
   return ostr.str();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.