std :: string in float o double


98

Sto cercando di convertire std::stringin float/double. Provai:

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

Ma restituisce sempre zero. Altri modi?


3
Resisti all'impulso di ingegnerizzare qualcosa di già scoperto dieci anni fa.
haavee il

1
sei sicuro di averlo stampato correttamente? Non dovrebbe produrre zero
Johannes Schaub - litb

1
inoltre, non è necessario lanciare atof, restituisce già un doppio.
AlbertoPL

Sono sicuro. Il debugger mi mostra 0. E il risultato è 0. Piattaforma: Linux.
Max Frai

13
Sei sicuro di aver installato la lingua corretta? prova "0,6" o setlocale (LC_NUMERIC, "C");
Johannes Schaub - litb

Risposte:


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

Lo fa per me, è una sintassi C ++ valida per convertire una stringa in un double.

Puoi farlo con lo stringstream o boost :: lexical_cast ma quelli hanno una penalizzazione delle prestazioni.


Ahaha hai un progetto Qt ...

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

Nota aggiuntiva:
se i dati di input sono a const char*, QByteArray::toDoublesarà più veloce.


7
boost :: lexical_cast è in streaming.
TimW

1
In genere non si può dire che hanno una penalità sulle prestazioni, credo. Pensa a cosa succede quando appena prima hai un cin >> num ;. L'utente dovrebbe digitare molto velocemente (tipo rly jon skeet) per notare mai che i millisecondi lexical_cast è più lento :) Detto questo, credo che ci siano attività in cui lexical_cast fa schifo solo troppe prestazioni :)
Johannes Schaub - litb

3
Per questa soluzione, cosa fa :: davanti a atof ()? Di cosa ha bisogno per essere lì?
sivabudh

4
@ ShaChris Perché voglio assicurarmi di utilizzare la funzione atof dallo spazio dei nomi globale.
TimW

1
dipende dalla lingua corrente
nmr

104

La libreria standard (C ++ 11) offre le funzionalità desiderate con std::stod:

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

Generalmente per la maggior parte degli altri tipi di base, vedere <string>. Ci sono anche alcune nuove funzionalità per le stringhe in C. Vedere<stdlib.h>


4
Mi piace questa soluzione, ma sembra che provenga solo da C ++ 11. Quindi non disponibile sul mio SDK.
pamplemousse_mk2

È bello sapere che il comitato per gli standard C ++ lo ha aggiunto. ostringstreamdi per sé era semplicemente troppo lungo per scrivere, figuriamoci usare ..
bobobobo

4
Per i float (come chiesto nella domanda che ho trovato con google digitando "c ++ string to float"), si dovrebbe usare std :: stof.
Étienne

1
Solo una nota che questo può generare eccezioni: std :: invalid_argument (se la conversione non è riuscita) std :: out_of_range (se fuori intervallo)
Jason Doucette

3
Attenzione dell'acquirente, dipende dalle impostazioni internazionali correnti.
nmr

29

Il cast lessicale è molto carino.

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

Grazie, funziona .. Ma è una domanda per me: perché il mio codice non funziona.
Max Frai

2
@Johannes Schaub: Basato su ADL, potrebbe anche averlo, le definizioni di utilizzo più ciò che sta effettivamente utilizzando probabilmente porteranno nell'ambito di un vasto numero di elementi standard. Inoltre lexical_cast è follemente lento, quindi nessun +1 da parte mia.

Una bella caratteristica di boost :: lexical_cast è la gestione degli errori. Se una conversione fallisce, viene lanciata un'eccezione:try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
Semjon Mössinger

Per essere più precisi, usa catch ( boost::bad_lexical_cast const& err )per catturare l'eccezione.
Semjon Mössinger

14

Puoi usare 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;
   }

Utilizzo:

double number= StringToNumber<double>("0.6");

Uhm, quindi pensi che boost :: lexical_cast abbia un'interfaccia terribile, vero? Guarda la risposta di stefanB! Boost fa lo stesso.
kirsche40

@ kirsche40 Sembra una buona alternativa per le persone che non hanno già dipendenze con Boost (il collegamento con Boost solo per convertire una stringa std :: in numeri è un po 'eccessivo!)
Jean-Philippe Jodoin

@ JEan-Phillippe Jodiun Ho risposto a un commento ora cancellato, in cui qualcuno ha consigliato Boost. Sono consapevole che Boost è il più delle volte eccessivo. A proposito, da tempo l'utilizzo di Boost è limitato ai compilatori "più recenti". I progetti più vecchi non possono utilizzare Boost. Ad esempio ASIO dipende molto dalle funzionalità di C ++ 11 come std :: addressof, il che lo rende completamente inutile per i compilatori C ++ 98 / C ++ 03. IMHO, quando il progetto è iniziato, era intenzione di Boost fornire nuove funzionalità "standardizzate" per le versioni precedenti del compilatore ... :-(
kirsche40

10

Sì, con un cast lessicale. Usa un flusso di stringhe e l'operatore << o usa Boost, lo hanno già implementato.

La tua versione potrebbe essere simile a:

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

  os << x;
  os >> ret;

  return ret;  
}

7

Puoi usare il cast lessicale boost:

#include <boost/lexical_cast.hpp>

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

Nota: boost :: lexical_cast genera un'eccezione, quindi dovresti essere pronto a gestirla quando passi un valore non valido, prova a passare la stringa ("xxx")


5

Se non vuoi trascinare tutto il boost, vai con strtod(3)from <cstdlib>- restituisce già un doppio.

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

Uscite:

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

Perché atof () non funziona ... su quale piattaforma / compilatore sei?


L'utilizzo di uno stringstream non richiederebbe un boost
jalf

Anche il tuo metodo restituisce zero. Linux.
Max Frai

3

Ho avuto lo stesso problema con Linux

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

Funziona.


2
   double myAtof ( string &num){
      double tmp;
      sscanf ( num.c_str(), "%lf" , &tmp);
      return tmp;
   }

1
Risposta non valida, come fai a sapere che il valore memorizzato in num è effettivamente un numero in virgola mobile valido? non controlli il tipo di ritorno di sscanf, sembra uno stile di codifica MS.

1

Questa risposta sta tornando alla lettera nei tuoi commenti. Ho il profondo sospetto che tu non stia visualizzando correttamente il risultato.

Una volta mi è successa la stessa identica cosa. Ho passato un'intera giornata a cercare di capire perché stavo ottenendo un valore negativo in un int a 64 bit, solo per scoprire che printf ignorava il secondo byte. Non puoi semplicemente passare un valore a 64 bit a printf come se fosse un int.


Non sto usando printf per vedere i risultati ... E uso quel valore per impostare l'opacità della finestra, e la mia finestra è completamente trasparente, quindi il valore è 0.
Max Frai

1

Il modo in C ++ 11 consiste nell'usare std :: stod e std :: to_string. Entrambi funzionano in Visual Studio 11.


1

Per quanto riguarda il motivo per cui atof()non funziona nella domanda originale: il fatto che sia stato scelto per il doppio mi rende sospettoso. Il codice non dovrebbe essere compilato senza #include <stdlib.h>, ma se il cast è stato aggiunto per risolvere un avviso di compilazione, atof()non viene dichiarato correttamente. Se il compilatore assume atof()restituisce un int, fusione che possa risolvere l'avviso di conversione, ma sarà non causa il valore di ritorno di essere riconosciuto come un doppio.

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

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

dovrebbe funzionare senza avvisi.


0

Invece di trascinare Boost nell'equazione, potresti mantenere la tua stringa (temporaneamente) come un file char[]e usaresprintf() .

Ma ovviamente se stai usando Boost comunque, non è davvero un grosso problema.


0

Non vuoi comunque Boost lexical_cast per string <-> floating point. Quel sottoinsieme di casi d'uso è l'unico insieme per il quale il potenziamento è costantemente peggiore delle funzioni precedenti e fondamentalmente hanno concentrato tutti i loro errori lì, perché i risultati delle loro prestazioni mostrano prestazioni 20-25 volte più lente rispetto all'utilizzo di sscanf e printf per tali conversioni.

Google da te. boost :: lexical_cast può gestire qualcosa come 50 conversioni e se escludi quelle che coinvolgono il floating point # è buono o migliore come le ovvie alternative (con l'ulteriore vantaggio di avere un'unica API per tutte quelle operazioni). Ma porta i galleggianti ed è come se il Titanic colpisse un iceberg in termini di prestazioni.

Le vecchie funzioni str-> double dedicate possono tutte eseguire 10000 analisi in qualcosa come 30 ms (o meglio). lexical_cast impiega qualcosa come 650 ms per fare lo stesso lavoro.


Nessuna fonte? L'ho cercato su Google
Blake

0

Il mio problema:

  1. Locale stringa indipendente da raddoppiare (separatore decimale sempre ".")
  2. Rilevamento degli errori se la conversione della stringa non riesce

La mia soluzione (utilizza la funzione di 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 ... mi ci è voluto parecchio tempo per arrivare a questa soluzione. E ho ancora la sensazione di non saperne abbastanza sulla localizzazione delle stringhe e cose del genere ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.