Jak przekonwertować liczbę zmiennoprzecinkową na ciąg znaków w C ++, określając dokładność i liczbę cyfr dziesiętnych?
Na przykład: 3.14159265359 -> "3.14"
c++
string
floating-point
Shannon Matthews
źródło
źródło
Odpowiedzi:
Typowym sposobem byłoby użycie
stringstream
:#include <iomanip> #include <sstream> double pi = 3.14159265359; std::stringstream stream; stream << std::fixed << std::setprecision(2) << pi; std::string s = stream.str();
Zobacz naprawione
i setprecision .
Do konwersji celów technicznych , takich jak przechowywanie danych w pliku XML lub JSON, C ++ 17 definiuje rodzinę funkcji to_chars .
Zakładając zgodny kompilator (którego nam brakuje w momencie pisania), można rozważyć coś takiego:
#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 }
źródło
Zwyczajową metodą robienia tego typu rzeczy jest drukowanie na łańcuchu. W C ++ oznacza to użycie
std::stringstream
czegoś takiego jak:std::stringstream ss; ss << std::fixed << std::setprecision(2) << number; std::string mystring = ss.str();
źródło
Inną opcją jest
snprintf
:double pi = 3.1415926; std::string s(16, '\0'); auto written = std::snprintf(&s[0], s.size(), "%.2f", pi); s.resize(written);
Demo . Należy dodać obsługę błędów, tj. Sprawdzanie
written < 0
.źródło
snprintf
być lepiej w tym przypadku? Proszę wyjaśnić ... To na pewno nie będzie szybsze, wyprodukuje mniej kodu [Napisałem implementację printf, jest dość kompaktowa i zawiera prawie 2000 linii kodu, ale z rozszerzeniami makr dochodzi do około 2500 linii]__printf_fp
funkcjonalności - jest raczej dziwne, że zajmuje to dużo więcej czasustringstream
, ponieważ naprawdę nie powinno.Możesz użyć
fmt::format
funkcji z biblioteki {fmt} :#include <fmt/core.h> int main() std::string s = fmt::format("{:.2f}", 3.14159265359); // s == "3.14" }
gdzie
2
jest precyzja.Ta funkcja formatowania została zaproponowana do standaryzacji w C ++: P0645 . Zarówno P0645, jak i {fmt} używają składni łańcucha formatu podobnej do Pythona, która jest podobna do
printf
's, ale{}
zamiast tego używa jako separatorów%
.źródło
Tutaj rozwiązanie wykorzystujące tylko standard. Należy jednak pamiętać, że to tylko zaokrągla w dół.
float number = 3.14159; std::string num_text = std::to_string(number); std::string rounded = num_text.substr(0, num_text.find(".")+3);
Za
rounded
to daje:3.14
Kod konwertuje cały float na łańcuch, ale wycina wszystkie znaki 2 znaki po „.”
źródło
number + 0.005
w moim przypadku.Tutaj przedstawiam negatywny przykład, w którym chcesz uniknąć konwersji liczby zmiennoprzecinkowej na ciągi.
float num=99.463; float tmp1=round(num*1000); float tmp2=tmp1/1000; cout << tmp1 << " " << tmp2 << " " << to_string(tmp2) << endl;
Dostajesz
99463 99.463 99.462997
Uwaga: zmienna num może mieć dowolną wartość bliską 99.463, otrzymasz taki sam wydruk. Chodzi o to, aby uniknąć wygodnej funkcji „to_string” w języku c ++ 11. Chwilę zajęło mi wydostanie się z tej pułapki. Najlepszym sposobem są metody stringstream i sprintf (język C). C ++ 11 lub nowszy powinien zawierać drugi parametr jako liczbę cyfr po zmiennoprzecinkowym do pokazania. W tej chwili wartością domyślną jest 6. Stawiam na to, aby inni nie tracili czasu na ten temat.
Napisałem swoją pierwszą wersję, daj mi znać, jeśli znajdziesz jakiś błąd, który należy naprawić. Możesz kontrolować dokładne zachowanie za pomocą iomanipulatora. Moja funkcja służy do wyświetlania liczby cyfr po przecinku.
string ftos(float f, int nd) { ostringstream ostr; int tens = stoi("1" + string(nd, '0')); ostr << round(f*tens)/tens; return ostr.str(); }
źródło