Próbuję przekonwertować std::stringna float/double. Próbowałem:
std::string num = "0.6";
double temp = (double)atof(num.c_str());
Ale zawsze zwraca zero. Jakieś inne sposoby?
Próbuję przekonwertować std::stringna float/double. Próbowałem:
std::string num = "0.6";
double temp = (double)atof(num.c_str());
Ale zawsze zwraca zero. Jakieś inne sposoby?
Odpowiedzi:
std::string num = "0.6";
double temp = ::atof(num.c_str());
Czy to dla mnie, poprawną składnią C ++ jest konwertowanie ciągu znaków na podwójny.
Możesz to zrobić za pomocą stringstream lub boost :: lexical_cast, ale wiąże się to z obniżeniem wydajności.
Ahaha, masz projekt Qt ...
QString winOpacity("0.6");
double temp = winOpacity.toDouble();
Dodatkowa uwaga:
jeśli dane wejściowe to a const char*, QByteArray::toDoublebędzie szybsze.
Biblioteka standardowa (C ++ 11) oferuje pożądaną funkcjonalność dzięki std::stod:
std::string s = "0.6"
std::wstring ws = "0.7"
double d = std::stod(s);
double dw = std::stod(ws);
Ogólnie dla większości innych podstawowych typów, zobacz <string>. Jest też kilka nowych funkcji dla łańcuchów C. Widzieć<stdlib.h>
ostringstreamsam w sobie był po prostu zbyt długi, aby pisać, nie mówiąc już o użyciu ...
Obsada leksykalna jest bardzo fajna.
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
using std::endl;
using std::cout;
using std::string;
using boost::lexical_cast;
int main() {
string str = "0.6";
double dub = lexical_cast<double>(str);
cout << dub << endl;
}
try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
catch ( boost::bad_lexical_cast const& err )do wychwycenia wyjątku.
Możesz użyć std :: stringstream:
#include <sstream>
#include <string>
template<typename T>
T StringToNumber(const std::string& numberAsString)
{
T valor;
std::stringstream stream(numberAsString);
stream >> valor;
if (stream.fail()) {
std::runtime_error e(numberAsString);
throw e;
}
return valor;
}
Stosowanie:
double number= StringToNumber<double>("0.6");
Tak, z obsadą leksykalną. Użyj stringstream i operatora << lub użyj Boost, oni już to zaimplementowali.
Twoja własna wersja mogłaby wyglądać następująco:
template<typename to, typename from>to lexical_cast(from const &x) {
std::stringstream os;
to ret;
os << x;
os >> ret;
return ret;
}
Możesz użyć wzmocnienia leksykalnego rzutowania:
#include <boost/lexical_cast.hpp>
string v("0.6");
double dd = boost::lexical_cast<double>(v);
cout << dd << endl;
Uwaga: boost :: lexical_cast zgłasza wyjątek, więc powinieneś być przygotowany na poradzenie sobie z tym, gdy przekazujesz nieprawidłową wartość, spróbuj przekazać string ("xxx")
Jeśli nie chcesz, aby przeciągnąć na cały impuls, iść z strtod(3)od <cstdlib>- to już wraca podwójnie.
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
using namespace std;
int main() {
std::string num = "0.6";
double temp = ::strtod(num.c_str(), 0);
cout << num << " " << temp << endl;
return 0;
}
Wyjścia:
$ g++ -o s s.cc
$ ./s
0.6 0.6
$
Dlaczego atof () nie działa ... na jakiej platformie / kompilatorze jesteś?
double myAtof ( string &num){
double tmp;
sscanf ( num.c_str(), "%lf" , &tmp);
return tmp;
}
Ta odpowiedź jest kopią zapasową w twoich komentarzach. Mam głębokie podejrzenie, że po prostu nie wyświetlasz poprawnie wyniku.
Kiedyś spotkało mnie dokładnie to samo. Spędziłem cały dzień próbując dowiedzieć się, dlaczego otrzymałem złą wartość w 64-bitowym int, tylko po to, by odkryć, że printf ignoruje drugi bajt. Nie możesz po prostu przekazać 64-bitowej wartości do printf, tak jak jest to int.
Co do tego, dlaczego atof()nie działa w pierwotnym pytaniu: fakt, że jest obsadzony podwójnie, budzi we mnie podejrzenia. Kod nie powinien się kompilować bez #include <stdlib.h>, ale jeśli rzutowanie zostało dodane w celu rozwiązania ostrzeżenia o kompilacji, atof()nie jest poprawnie zadeklarowane. Jeśli kompilator zakłada, że atof()zwraca wartość typu int, rzutowanie go rozwiąże ostrzeżenie o konwersji, ale nie spowoduje, że wartość zwracana zostanie rozpoznana jako podwójna.
#include <stdlib.h>
#include <string>
...
std::string num = "0.6";
double temp = atof(num.c_str());
powinien działać bez ostrzeżeń.
Zamiast przeciągać Boost do równania, możesz zachować strunę (tymczasowo) jako a char[]i użyć sprintf().
Ale oczywiście, jeśli i tak używasz Boost, to naprawdę nie jest to zbyt duży problem.
I tak nie chcesz Boost lexical_cast dla ciągu <-> zmiennoprzecinkowego. Ten podzbiór przypadków użycia jest jedynym zestawem, dla którego wzmocnienie konsekwentnie jest gorsze niż starsze funkcje - i zasadniczo skoncentrowały tam wszystkie swoje awarie, ponieważ ich własne wyniki wydajności pokazują 20-25X MNIEJSZĄ wydajność niż użycie sscanf i printf do takich konwersji.
Google to sam. boost :: lexical_cast może obsłużyć około 50 konwersji, a jeśli wykluczysz te, które zawierają zmiennoprzecinkowe #, będzie to równie dobre lub lepsze, jak oczywiste alternatywy (z dodatkową zaletą posiadania jednego interfejsu API dla wszystkich tych operacji). Ale przynieś pływaki i pod względem wydajności to jak Titanic uderzający w górę lodową.
Wszystkie stare, dedykowane funkcje str-> double mogą wykonać 10000 parsów w czasie około 30 ms (lub lepszym). lexical_cast wykonuje to samo przez około 650 ms.
Mój problem:
Moje rozwiązanie (używa funkcji Windows _wcstod_l):
// string to convert. Note: decimal seperator is ',' here
std::wstring str = L"1,101";
// Use this for error detection
wchar_t* stopString;
// Create a locale for "C". Thus a '.' is expected as decimal separator
double dbl = _wcstod_l(str.c_str(), &stopString, _create_locale(LC_ALL, "C"));
if (wcslen(stopString) != 0)
{
// ... error handling ... we'll run into this because of the separator
}
HTH ... zajęło mi dość długo dotarcie do tego rozwiązania. I nadal mam wrażenie, że nie wiem wystarczająco dużo o lokalizacji ciągów znaków i tak dalej ...