std :: string para flutuar ou dobrar

98

Estou tentando converter std::stringpara float/double. Eu tentei:

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

Mas sempre retorna zero. Quaisquer outras maneiras?

Max Frai
fonte
3
Resista à tentação de superengenharia de algo que já foi descoberto há uma década.
haavee
1
tem certeza de que emitiu corretamente? Não deve render zero
Johannes Schaub - litb de
1
além disso, você não precisa lançar um atof, ele já retorna um double.
AlbertoPL 18/06/09
Tenho certeza. O depurador me mostra 0. E o resultado é 0. Plataforma: Linux.
Max Frai de
13
Tem certeza de que instalou o local correto? tente "0,6" ou setlocale (LC_NUMERIC, "C");
Johannes Schaub - litb

Respostas:

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

Para mim, é uma sintaxe C ++ válida para converter uma string em um double.

Você pode fazer isso com stringstream ou boost :: lexical_cast, mas eles vêm com uma penalidade de desempenho.


Ahaha você tem um projeto Qt ...

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

Observação extra:
se os dados de entrada forem a const char*, QByteArray::toDoubleserá mais rápido.

TimW
fonte
7
boost :: lexical_cast está transmitindo.
TimW de
1
Você geralmente não pode dizer que eles vêm com uma penalidade de desempenho, eu acho. Pense no que acontece quando um pouco antes disso você tem um cin >> num ;. O usuário teria que digitar muito rapidamente (como rly jon skeet) para notar os milissegundos que lexical_cast é mais lento :) Dito isso, acredito que há tarefas em que lexical_cast é muito ruim para o desempenho :)
Johannes Schaub - litb
3
Para esta solução, o que o :: na frente de atof () faz? O que é necessário para estar lá?
sivabudh
4
@ShaChris Porque quero ter certeza de usar a função atof do namespace global.
TimW
1
depende do local atual
nmr
104

A Biblioteca Padrão (C ++ 11) oferece a funcionalidade desejada com std::stod:

std::string  s  = "0.6"
std::wstring ws = "0.7"
double d  = std::stod(s);
double dw = std::stod(ws);

Geralmente, para a maioria dos outros tipos básicos, consulte <string>. Existem alguns novos recursos para strings C também. Vejo<stdlib.h>

ManuelSchneid3r
fonte
4
Gosto desta solução, mas parece que é apenas do C ++ 11. Portanto, não disponível no meu SDK.
pamplemousse_mk2
É ótimo saber que o comitê de padrões C ++ adicionou isso. ostringstreamem si era simplesmente muito longo para digitar, quanto mais usar ..
bobobobo
4
Para floats (conforme perguntado na pergunta que encontrei com o google digitando "c ++ string to float"), deve-se usar std :: stof.
Étienne
1
Apenas uma observação de que isso pode gerar exceções: std :: invalid_argument (se a conversão falhou) std :: out_of_range (se fora do intervalo)
Jason Doucette
3
O comprador, tome cuidado, depende do local atual.
nmr de
29

O elenco lexical é muito bom.

#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;
}
Bill Lynch
fonte
Obrigado, funciona .. Mas é uma questão para mim: por que meu código não está funcionando.
Max Frai de
2
@Johannes Schaub: Com base no ADL, ele pode muito bem ter feito isso, o uso de definições mais o que ele está realmente usando provavelmente trará para o escopo um grande número de elementos std. Além disso, lexical_cast é incrivelmente lento, então nenhum +1 de mim.
Um bom recurso de boost :: lexical_cast é o tratamento de erros. Se uma conversão falhar, uma exceção é lançada:try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
Semjon Mössinger
Para ser mais preciso, use catch ( boost::bad_lexical_cast const& err )para capturar a exceção.
Semjon Mössinger
14

Você pode usar 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;
   }

Uso:

double number= StringToNumber<double>("0.6");
Edison Gustavo Muenz
fonte
Uhm, então você acha que boost :: lexical_cast tem uma interface terrível, não é? Veja a resposta de StefanB! Boost faz o mesmo.
kirsche40 de
@ kirsche40 Parece uma boa alternativa para pessoas que ainda não têm dependências com Boost (vincular com Boost apenas para converter uma string std :: em números é um pouco exagero!)
Jean-Philippe Jodoin
@ JEan-Phillippe Jodiun Eu respondi a um comentário agora excluído, onde alguém recomendou Boost. Estou ciente de que Boost é na maioria das vezes um exagero. A propósito, há algum tempo o uso do Boost é restrito a compiladores "mais novos". Projetos mais antigos não podem usar Boost. Por exemplo, o ASIO depende muito dos recursos do C ++ 11 como std :: addressof, o que o torna completamente inútil para os compiladores C ++ 98 / C ++ 03. IMHO, quando o projeto começou, a intenção da Boost era fornecer novos recursos "padronizados" para versões mais antigas do compilador ... :-(
kirsche40
10

Sim, com um molde léxico. Use um stringstream e o operador <<, ou use Boost, eles já o implementaram.

Sua própria versão pode ser semelhante a:

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

  os << x;
  os >> ret;

  return ret;  
}
DaClown
fonte
7

Você pode usar o reforço de elenco léxico:

#include <boost/lexical_cast.hpp>

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

Nota: boost :: lexical_cast lança exceção, então você deve estar preparado para lidar com isso quando passar um valor inválido, tente passar string ("xxx")

StefanB
fonte
5

Se você não quiser arrastar todo o impulso, vá com strtod(3)de <cstdlib>- ele já retorna um duplo.

#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;
}

Saídas:

$ g++ -o s s.cc
$ ./s
0.6 0.6
$

Por que atof () não funciona ... em qual plataforma / compilador você está?

Haavee
fonte
Usar um stringstream não exigiria aumento
jalf
Seu método retorna zero também. Linux.
Max Frai de
3

Eu tive o mesmo problema no Linux

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

funciona.

Kenn
fonte
2
   double myAtof ( string &num){
      double tmp;
      sscanf ( num.c_str(), "%lf" , &tmp);
      return tmp;
   }
dpetek
fonte
1
Resposta inválida, como você sabe que o valor armazenado em num é realmente um número de ponto flutuante válido? você não verifica o tipo de retorno de sscanf, parece um estilo de codificação MS.
1

Esta resposta está apoiada em pouco nos seus comentários. Tenho profundas suspeitas de que você simplesmente não está exibindo o resultado corretamente.

A mesma coisa aconteceu comigo uma vez. Passei um dia inteiro tentando descobrir por que estava obtendo um valor ruim em um int de 64 bits, apenas para descobrir que printf estava ignorando o segundo byte. Você não pode simplesmente passar um valor de 64 bits para printf como se fosse um int.

TED
fonte
Não estou usando printf para ver os resultados ... E eu uso esse valor para definir a opacidade da janela, e minha janela está totalmente transparente, então o valor é 0.
Max Frai
1

A maneira C ++ 11 é usar std :: stod e std :: to_string. Ambos funcionam no Visual Studio 11.

BSalita
fonte
1

Quanto a por que atof()não está funcionando na pergunta original: o fato de que é lançado para dobrar me deixa desconfiado. O código não deve ser compilado sem #include <stdlib.h>, mas se o elenco foi adicionado para resolver um aviso de compilação, então atof()não foi declarado corretamente. Se o compilador assume atof()retorna um int, lançando ele vai resolver o aviso de conversão, mas vai não causa o valor de retorno para ser reconhecido como um duplo.

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

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

deve funcionar sem avisos.

Iain
fonte
0

Em vez de arrastar Boost para a equação, você pode manter sua corda (temporariamente) como um char[]e usar sprintf().

Mas é claro que se você estiver usando Boost de qualquer maneira, não é um grande problema.

Chris Tonkinson
fonte
0

Você não quer Boost lexical_cast para string <-> ponto flutuante de qualquer maneira. Esse subconjunto de casos de uso é o único em que o boost consistentemente é pior do que as funções mais antigas - e eles basicamente concentraram todas as suas falhas ali, porque seus próprios resultados de desempenho mostram um desempenho 20-25X MAIS LENTO do que usar sscanf e printf para tais conversões.

Pesquise no Google. boost :: lexical_cast pode lidar com algo como 50 conversões e se você excluir aquelas envolvendo ponto flutuante # é tão bom ou melhor quanto as alternativas óbvias (com a vantagem adicional de ter uma única API para todas essas operações). Mas traga carros alegóricos e é como o Titanic batendo em um iceberg em termos de desempenho.

As antigas funções str-> double dedicadas podem fazer 10.000 análises em cerca de 30 ms (ou melhor). lexical_cast leva algo como 650 ms para fazer o mesmo trabalho.

Zack Yezek
fonte
Sem fonte? Eu mesmo pesquisei no Google
Blake
0

Meu problema:

  1. String independente de local para duplicar (separador decimal sempre '.')
  2. Detecção de erro se a conversão de string falhar

Minha solução (usa a função do 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 ... demorei muito para chegar a essa solução. E ainda tenho a sensação de que não sei o suficiente sobre localização de cordas e outras coisas ...

Anhoppe
fonte