Я намагаюся конвертувати std::stringв float/double. Я намагався:
std::string num = "0.6";
double temp = (double)atof(num.c_str());
Але це завжди повертає нуль. Будь-які інші способи?
Я намагаюся конвертувати std::stringв float/double. Я намагався:
std::string num = "0.6";
double temp = (double)atof(num.c_str());
Але це завжди повертає нуль. Будь-які інші способи?
Відповіді:
std::string num = "0.6";
double temp = ::atof(num.c_str());
Це для мене, це дійсний синтаксис C ++ для перетворення рядка у подвійний.
Ви можете зробити це за допомогою stringstream або boost :: lexical_cast, але ті мають штраф за продуктивність.
Ага, у вас проект Qt ...
QString winOpacity("0.6");
double temp = winOpacity.toDouble();
Додаткова примітка:
Якщо вхідні дані a const char*, QByteArray::toDoubleце буде швидше.
Стандартна бібліотека (C ++ 11) пропонує бажану функціональність із std::stod:
std::string s = "0.6"
std::wstring ws = "0.7"
double d = std::stod(s);
double dw = std::stod(ws);
Як правило, для більшості інших основних типів див <string>. Є також деякі нові функції для рядків C. Побачити<stdlib.h>
ostringstreamсаме по собі було просто занадто довгим, щоб набирати текст, не кажучи вже про використання ...
Лексичний склад дуже приємний.
#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 )щоб зловити виняток.
Ви можете використовувати 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;
}
Використання:
double number= StringToNumber<double>("0.6");
Так, з лексичним складом. Використовуйте рядок рядків та оператор <<, або використовуйте Boost, вони це вже реалізували.
Ваша власна версія може виглядати так:
template<typename to, typename from>to lexical_cast(from const &x) {
std::stringstream os;
to ret;
os << x;
os >> ret;
return ret;
}
Ви можете використовувати посилення лексичного складу:
#include <boost/lexical_cast.hpp>
string v("0.6");
double dd = boost::lexical_cast<double>(v);
cout << dd << endl;
Примітка: boost :: lexical_cast видає виняток, тому ви повинні бути готові мати справу з ним, коли передаєте недійсне значення, спробуйте передати рядок ("xxx")
Якщо ви не хочете перетягувати весь підсилення, перейдіть з strtod(3)from <cstdlib>- це вже повертає дубль.
#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;
}
Виходи:
$ g++ -o s s.cc
$ ./s
0.6 0.6
$
Чому atof () не працює ... на якій платформі / компіляторі ви знаходитесь?
double myAtof ( string &num){
double tmp;
sscanf ( num.c_str(), "%lf" , &tmp);
return tmp;
}
Ця відповідь є резервним кодом у ваших коментарях. Я глибоко підозрюю, що ви просто не відображаєте результат належним чином.
У мене колись траплялося саме те саме. Я витратив цілий день, намагаючись зрозуміти, чому я отримую погане значення в 64-розрядному int, лише виявивши, що printf ігнорує другий байт. Ви не можете просто передати 64-бітове значення в printf, як його int.
Що стосується того, чому atof()не спрацьовує оригінальне запитання: той факт, що його роблять подвійним, робить мене підозрілим. Код не повинен компілюватися без #include <stdlib.h>, але якщо приклад був доданий для вирішення попередження про компіляцію, тоді atof()він неправильно оголошений. Якщо компілятор припускає, що atof()повертає int, це призводить до вирішення попередження про перетворення, але це не призведе до того, що значення, що повертається, розпізнається як подвійне.
#include <stdlib.h>
#include <string>
...
std::string num = "0.6";
double temp = atof(num.c_str());
повинен працювати без попереджень.
Замість того, щоб перетягувати Boost у рівняння, ви можете зберегти рядок (тимчасово) як a char[]та використовувати sprintf().
Але, звичайно, якщо ви все одно використовуєте Boost, це насправді не надто велика проблема.
Ви все одно не хочете Boost lexical_cast для рядка <-> з плаваючою комою. Ця підмножина випадків використання є єдиним набором, для якого підвищення постійно гірше, ніж у старих функцій, - і вони в основному зосереджували там усі свої помилки, оскільки їх власні результати продуктивності показують 20-25X ПОВІЛЬНІШУ ефективність, ніж використання sscanf та printf для таких перетворень.
Погугліть це самостійно. boost :: lexical_cast може обробляти щось на зразок 50 перетворень, і якщо виключити ті, що включають числа з плаваючою комою, це так само добре чи краще, як очевидні альтернативи (з додатковою перевагою наявності єдиного API для всіх цих операцій). Але принесіть поплавки та подібні Титаніку, що б’є айсберг з точки зору продуктивності.
Старі, виділені функції str-> double можуть виконувати 10000 аналізів приблизно за 30 мс (або краще). lexical_cast займає приблизно 650 мс, щоб виконати ту саму роботу.
Моя проблема:
Моє рішення (використовує функцію 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 ... мені знадобилося досить багато часу, щоб дійти до цього рішення. І я все ще маю відчуття, що я недостатньо знаю про локалізацію рядків та інше ...