std :: string float veya double


99

Ben dönüştürmek çalışıyorum std::stringiçin float/double. Denedim:

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

Ama her zaman sıfır döndürür. Başka yol var mı?


3
On yıl önce çözülen bir şeyi aşırı mühendislik dürtüsüne direnin.
haavee

1
doğru çıktı aldığınızdan emin misiniz? Sıfır vermemeli
Johannes Schaub - litb

1
ek olarak, atof atmanıza gerek yoktur, zaten bir double döndürür.
AlbertoPL

Eminim. Hata ayıklayıcı bana 0 gösteriyor. Ve sonuç 0. Platform: Linux.
Max Frai

13
Doğru yerel ayarın kurulu olduğundan emin misiniz? "0,6" veya setlocale (LC_NUMERIC, "C") deneyin;
Johannes Schaub - litb

Yanıtlar:


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

Benim için öyle mi, bir dizeyi ikiliye dönüştürmek geçerli bir C ++ sözdizimi.

Bunu stringstream veya boost :: lexical_cast ile yapabilirsiniz, ancak bunlar bir performans cezası ile gelir.


Ahaha bir Qt projeniz var ...

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

Ek not:
Giriş verileri a ise const char*, QByteArray::toDoubledaha hızlı olacaktır.


7
boost :: lexical_cast yayınlanıyor.
TimW

1
Genelde performans cezası aldıklarını söyleyemezsiniz, bence. Tam önünde bir cin >> num; olduğunda ne olacağını bir düşünün. Kullanıcının milisaniyenin daha yavaş olduğunu not etmek için çok hızlı yazması gerekirdi (rly jon skeet like) lexical_cast daha yavaş :) Bununla birlikte, lexical_cast'in çok fazla performans emdiği görevler olduğuna inanıyorum :)
Johannes Schaub - litb

3
Bu çözüm için atof () önündeki :: ne yapar? Orada olması gereken ne?
sivabudh

4
@ShaChris Çünkü global isim alanından atof fonksiyonunu kullandığımdan emin olmak istiyorum.
TimW

1
mevcut yerel ayara bağlıdır
nmr

104

Standart Kitaplık (C ++ 11) aşağıdakilerle istenen işlevselliği sunar std::stod:

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

Genellikle diğer temel türlerin çoğu için bkz <string>. C dizgileri için de bazı yeni özellikler var. Görmek<stdlib.h>


4
Bu çözümü beğendim, ancak görünüşe göre sadece C ++ 11'den geliyor. Yani SDK'mda mevcut değil.
pamplemousse_mk2

Bu var harika C ++ standartları komitesi bu katma olduğunu bilmek. ostringstreamkendi başına yazmak için çok uzundu, bırakın kullanmayı bırakın ..
bobobobo

4
Float'lar için (google ile "float için c ++ string" yazarak bulduğum soruda sorulduğu gibi) std :: stof kullanılmalıdır.
Étienne

1
Bunun istisnaları atabileceğini unutmayın: std :: geçersiz_argüm (dönüştürme başarısız olursa) std :: out_of_range (aralık dışındaysa)
Jason Doucette

3
Alıcı dikkat edin, mevcut yerel ayara bağlıdır.
nmr

29

Sözcüksel döküm çok güzel.

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

Teşekkürler, işe yarıyor .. Ama bu benim için bir soru: kodum neden çalışmıyor.
Max Frai

2
@Johannes Schaub: ADL'ye dayanarak, kullanma tanımları ve gerçekte kullandığı şey muhtemelen çok sayıda standart unsuru kapsamına alabilir. Ayrıca lexical_cast delicesine yavaştır, bu yüzden benden +1 yok.

Boost :: lexical_cast'in güzel bir özelliği de hata işlemedir. Bir dönüştürme başarısız olursa, bir istisna atılır:try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
Semjon Mössinger

Daha kesin olmak gerekirse, catch ( boost::bad_lexical_cast const& err )istisnayı yakalamak için kullanın .
Semjon Mössinger

14

Std :: stringstream'i kullanabilirsiniz:

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

Kullanım:

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

Uhm, boost :: lexical_cast'in korkunç bir arayüze sahip olduğunu düşünüyorsun, değil mi? StefanB'nin cevabına bakın! Boost da aynı şeyi yapar.
kirsche40

@ kirsche40 Boost ile zaten bağımlılığı olmayan insanlar için iyi bir alternatif gibi görünüyor (sadece bir std :: string'i sayılara dönüştürmek için Boost ile bağlantı kurmak biraz fazla
abartı

@ JEan-Phillippe Jodiun Birisinin Boost'u önerdiği, silinmiş bir yoruma yanıt verdim. Boost'un çoğu zaman abartılı olduğunun farkındayım. Bu arada, bir süredir Boost'un kullanımı "daha yeni" derleyicilerle sınırlı. Daha eski projeler Boost'u kullanamaz. Örneğin ASIO, std :: addressof gibi C ++ 11 özelliklerine bağlıdır, bu da onu C ++ 98 / C ++ 03 derleyicileri için tamamen değersiz kılar. IMHO, proje başladığında
Boost'un amacı

10

Evet, sözcüksel bir döküm ile. Bir dizgi akışı ve << işlecini kullanın veya Boost'u kullanın, zaten uyguladılar.

Kendi sürümünüz şöyle görünebilir:

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

  os << x;
  os >> ret;

  return ret;  
}

7

Arttırılmış sözcüksel döküm kullanabilirsiniz:

#include <boost/lexical_cast.hpp>

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

Not: boost :: lexical_cast istisna atar, bu nedenle geçersiz bir değer ilettiğinizde bununla başa çıkmaya hazır olmalısınız, dizeyi ("xxx") geçirmeyi deneyin


5

Eğer boost tümünde drag istemiyorsanız, gitmek strtod(3)dan <cstdlib>zaten bir çift döner -.

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

Çıktılar:

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

Atof () neden çalışmıyor ... hangi platformda / derleyicide bulunuyorsunuz?


Dizgi akışı kullanmak destek gerektirmez
jalf

Yönteminiz de sıfır döndürüyor. Linux.
Max Frai

3

Linux'ta da aynı sorunu yaşadım

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

işe yarıyor.


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

1
Geçersiz cevap, num içinde saklanan değerin gerçekte geçerli bir kayan nokta sayısı olduğunu nasıl anlarsınız? sscanf'ın dönüş türünü kontrol etmezsiniz, bir MS kodlama stili gibi görünür.

1

Bu cevap, yorumlarınızda litb'yi yedeklemektedir. Sonucu düzgün bir şekilde göstermediğiniz konusunda derin şüphelerim var.

Bir keresinde bana da aynı şey olmuştu. Tüm günümü 64 bitlik bir int'e neden kötü bir değer aldığımı anlamaya çalışarak geçirdim, sadece printf'in ikinci baytı görmezden geldiğini keşfetmek için. 64 bitlik bir değeri printf'e bir int gibi geçiremezsiniz.


Sonuçları görmek için printf kullanmıyorum ... Ve bu değeri pencere opaklığını ayarlamak için kullanıyorum ve pencerem tam şeffaf, yani değer 0.
Max Frai

1

C ++ 11 yolu std :: stod ve std :: to_string kullanmaktır. Her ikisi de Visual Studio 11'de çalışır.


1

atof()Asıl soruda neden işe yaramadığına gelince : ikiye katlanmış olması beni şüphelendiriyor. Kod olmadan derlenmemelidir #include <stdlib.h>, ancak dönüştürme bir derleme uyarısını çözmek için eklendiyse, atof()doğru şekilde bildirilmez. Derleyici talip olursa atof()döndürür bir int, bu dönüşüm uyarısı çözecek döküm, ancak olacak değil dönüş değeri bir çift olarak tanınmak neden olur.

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

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

uyarı olmadan çalışmalıdır.


0

Aksine denkleme Boost sürükleyerek yerine, bir gibi dize (geçici olarak) tutmak char[]ve kullanım sprintf().

Ancak elbette Boost kullanıyorsanız, bu gerçekten çok fazla bir sorun değil.


0

Yine de string <-> kayan nokta için lexical_cast istemezsiniz. Bu kullanım durumları alt kümesi, sürekli olarak artırmanın eski işlevlerden daha kötü olduğu tek kümedir - ve temelde tüm başarısızlıklarını orada yoğunlaştırdılar, çünkü kendi performans sonuçları, bu tür dönüştürmeler için sscanf ve printf kullanmaktan 20-25X DAHA YAVAŞ bir performans gösteriyor.

Kendin Google. boost :: lexical_cast, 50 dönüşüm gibi bir şeyi işleyebilir ve kayan nokta #s içerenleri hariç tutarsanız, bariz alternatifler kadar iyi veya daha iyidir (tüm bu işlemler için tek bir API'ye sahip olmanın ek avantajı ile). Ancak, performans açısından bir buzdağına çarpan şamandıralar ve benzerlerini getirin.

Eski, adanmış str-> double işlevlerinin tümü, 30 ms (veya daha iyi) gibi bir şeyde 10000 ayrıştırma yapabilir. lexical_cast aynı işi yapmak için 650 ms gibi bir şey alır.


Kaynak yok? Google'da
Blake

0

Benim sorunum:

  1. Yerel bağımsız dizeyi ikiye katlamak (ondalık ayırıcı her zaman '.')
  2. Dizi dönüştürme başarısız olursa hata algılama

Çözümüm (Windows işlevi _wcstod_l kullanır):

// 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 ... bu çözüme ulaşmam oldukça uzun sürdü. Ve hala dizi yerelleştirmesi ve benzeri şeyler hakkında yeterince bilgim olmadığını hissediyorum ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.