std :: string для float или double

98

Я пытаюсь преобразовать std::stringв float/double. Я попытался:

std::string num = "0.6";
double temp = (double)atof(num.c_str());

Но всегда возвращает ноль. Любые другие способы?

Макс Фрай
источник
3
Не поддавайтесь искушению чрезмерно изобретать то, что было выяснено уже десять лет назад.
Haavee
1
вы уверены, что выводите его правильно? Он не должен давать ноль
Йоханнес Шауб - лит,
1
кроме того, вам не нужно приводить atof, он уже возвращает double.
AlbertoPL
Я уверен. Отладчик показывает мне 0. И результат 0. Платформа: Linux.
Max Frai
13
Вы уверены, что у вас установлен правильный языковой стандарт? попробуйте «0,6» или setlocale (LC_NUMERIC, «C»);
Йоханнес Шауб - лит

Ответы:

125
std::string num = "0.6";
double temp = ::atof(num.c_str());

Для меня это правильный синтаксис C ++ для преобразования строки в double.

Вы можете сделать это с помощью stringstream или boost :: lexical_cast, но это снижает производительность.


Ахаха, у вас есть проект Qt ...

QString winOpacity("0.6");
double temp = winOpacity.toDouble();

Дополнительное примечание:
если входные данные - это const char*, QByteArray::toDoubleбудет быстрее.

TimW
источник
7
boost :: lexical_cast транслируется.
TimW
1
Я думаю, вы не можете вообще сказать, что они идут со снижением производительности. Подумайте, что происходит, когда прямо перед этим у вас есть cin >> num ;. Пользователю придется набирать текст очень быстро (например, rly jon skeet), чтобы когда-либо заметить, что в миллисекундах lexical_cast медленнее :) Тем не менее, я считаю, что есть задачи, в которых lexical_cast просто отстойно сказывается на производительности :)
Йоханнес Шауб - litb
3
Что в этом решении делает :: перед atof ()? Что там должно быть?
sivabudh
4
@ShaChris Потому что я хочу убедиться, что использую функцию atof из глобального пространства имен.
TimW
1
зависит от текущей локали
nmr
104

Стандартная библиотека (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>

ManuelSchneid3r
источник
4
Мне нравится это решение, но похоже, что оно только из C ++ 11. Так что недоступно в моем SDK.
pamplemousse_mk2
Это здорово знать , что комитет по стандартизации C ++ добавил это. ostringstreamсам по себе был слишком длинным, чтобы печатать, не говоря уже об использовании ..
bobobobo
4
Для чисел с плавающей запятой (как задано в вопросе, который я нашел с помощью Google, набрав «c ++ string to float»), следует использовать std :: stof.
Étienne
1
Замечу, что это может вызвать исключения: std :: invalid_argument (если преобразование не удалось) std :: out_of_range (если вне диапазона)
Джейсон Дусетт,
3
Покупатель, будьте осторожны, это зависит от текущего региона.
мр
29

Лексический состав очень приятный.

#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;
}
Билл Линч
источник
Спасибо, работает .. Но это вопрос ко мне: почему мой код не работает.
Макс Фрай,
2
@Johannes Schaub: Основываясь на ADL, он мог бы с таким же успехом иметь, определения using плюс то, что он фактически использует, вероятно, внесет в область применения огромное количество элементов std. Кроме того, lexical_cast безумно медленный, так что +1 от меня нет.
Приятной особенностью boost :: lexical_cast является обработка ошибок. Если преобразование не удается, try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
выдается
Чтобы быть более точным, используйте catch ( boost::bad_lexical_cast const& err )для перехвата исключения.
Semjon Mössinger
14

Вы можете использовать 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 :: lexical_cast ужасный интерфейс, не так ли? Посмотрите ответ stefanB! Boost делает то же самое.
kirsche40
@ kirsche40 Кажется хорошей альтернативой для людей, у которых еще нет зависимостей от Boost (связывание с Boost только для преобразования std :: string в числа - это немного излишне!)
Жан-Филипп Жоден
@ JEan-Phillippe Jodiun Я ответил на теперь удаленный комментарий, где кто-то рекомендовал Boost. Я знаю, что Boost в большинстве случаев является излишним. Кстати, с некоторых пор использование Boost ограничено «более новыми» компиляторами. В более старых проектах нельзя использовать Boost. Например, ASIO сильно зависит от функций C ++ 11, таких как std :: addressof, что делает его совершенно бесполезным для компиляторов C ++ 98 / C ++ 03. ИМХО, когда проект стартовал, намерением Boost было предоставить новые "стандартизованные" функции для старых версий компилятора ... :-(
kirsche40
10

Да, с лексическим составом. Используйте строковый поток и оператор << или используйте Boost, они уже реализовали его.

Ваша собственная версия может выглядеть так:

template<typename to, typename from>to lexical_cast(from const &x) {
  std::stringstream os;
  to ret;

  os << x;
  os >> ret;

  return ret;  
}
DaClown
источник
7

Вы можете использовать усиление лексического приведения:

#include <boost/lexical_cast.hpp>

string v("0.6");
double dd = boost::lexical_cast<double>(v);
cout << dd << endl;

Примечание: boost :: lexical_cast вызывает исключение, поэтому вы должны быть готовы с ним справиться, когда вы передаете недопустимое значение, попробуйте передать строку ("xxx")

СтефанБ
источник
5

Если вы не хотите перетаскивать все ускорение, используйте 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 () не работает ... на какой платформе / компиляторе вы работаете?

хаави
источник
Использование струнного потока не потребует ускорения
jalf
Ваш метод тоже возвращает ноль. Linux.
Макс Фрай,
3

У меня была такая же проблема в Linux

double s2f(string str)
{
 istringstream buffer(str);
 double temp;
 buffer >> temp;
 return temp;
}

оно работает.

Kenn
источник
2
   double myAtof ( string &num){
      double tmp;
      sscanf ( num.c_str(), "%lf" , &tmp);
      return tmp;
   }
dpetek
источник
1
Неверный ответ, откуда вы знаете, что значение, хранящееся в num, на самом деле является действительным числом с плавающей запятой? вы не проверяете возвращаемый тип sscanf, похоже на стиль кодирования MS.
1

Этот ответ подкреплен вашими комментариями. У меня есть глубокие подозрения, что вы просто неправильно показываете результат.

Однажды со мной случилось то же самое. Я потратил целый день, пытаясь понять, почему я получил плохое значение в 64-битном int, только чтобы обнаружить, что printf игнорирует второй байт. Вы не можете просто передать 64-битное значение в printf, как int.

ТЕД
источник
Я не использую printf для просмотра результатов ... И я использую это значение для установки непрозрачности окна, и мое окно полностью прозрачное, поэтому значение равно 0.
Макс Фрай
1

Способ C ++ 11 - использовать std :: stod и std :: to_string. Оба работают в Visual Studio 11.

BSalita
источник
1

Что касается того, почему atof()не работает в исходном вопросе: тот факт, что он приведен к удвоению, вызывает у меня подозрения. Код не должен компилироваться без него #include <stdlib.h>, но если приведение было добавлено для устранения предупреждения компиляции, atof()оно объявлено неправильно. Если компилятор предполагает, что atof()возвращает int, его приведение устранит предупреждение о преобразовании, но не приведет к тому, что возвращаемое значение будет распознано как двойное.

#include <stdlib.h>
#include <string>

... 
  std::string num = "0.6";
  double temp = atof(num.c_str());

должен работать без предупреждений.

Иэн
источник
0

Вместо того, чтобы перетаскивать Boost в уравнение, вы можете оставить свою строку (временно) как a char[]и использовать sprintf().

Но, конечно, если вы все равно используете Boost, это не такая уж большая проблема.

Крис Тонкинсон
источник
0

В любом случае вам не нужно Boost lexical_cast для строки <-> с плавающей запятой. Это подмножество вариантов использования - единственный набор, для которого ускорение постоянно хуже, чем у старых функций, и они в основном сосредоточили все свои отказы именно там, потому что их собственные результаты производительности показывают производительность в 20-25 раз МЕДЛЕННУЮ, чем при использовании sscanf и printf для таких преобразований.

Погуглите сами. boost :: lexical_cast может обрабатывать примерно 50 преобразований, и если вы исключите те, которые включают #s с плавающей запятой, это будет так же хорошо или лучше, как и очевидные альтернативы (с дополнительным преимуществом наличия единого API для всех этих операций). Но добавьте поплавки, и это похоже на то, что Титаник врезался в айсберг с точки зрения производительности.

Все старые специализированные функции str-> double могут выполнять 10000 разборов примерно за 30 мс (или лучше). lexical_cast занимает примерно 650 мс, чтобы выполнить ту же работу.

Зак Йезек
источник
Нет источника? Я сам погуглил
Блейк
0

Моя проблема:

  1. Строка, не зависящая от локали, в двойную (десятичный разделитель всегда '.
  2. Обнаружение ошибки при сбое преобразования строки

Мое решение (использует функцию 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 ... мне потребовалось довольно много времени, чтобы добраться до этого решения. И у меня до сих пор такое чувство, что я недостаточно разбираюсь в локализации строк и тому подобном ...

Anhoppe
источник