std :: string menjadi float atau double

98

Saya mencoba untuk beralih std::stringke float/double. Saya mencoba:

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

Tapi selalu mengembalikan nol. Ada cara lain?

Max Frai
sumber
3
Tahan keinginan untuk merekayasa sesuatu yang sudah diketahui satu dekade lalu.
haavee
1
apakah Anda yakin Anda mengeluarkannya dengan benar? Seharusnya tidak menghasilkan nol
Johannes Schaub - litb
1
Selain itu, Anda tidak perlu melakukan cast, itu sudah mengembalikan double.
AlbertoPL
Saya yakin. Debugger menunjukkan kepada saya 0. Dan hasilnya 0. Platform: Linux.
Max Frai
13
Apakah Anda yakin telah menginstal lokal yang tepat? coba "0,6" atau setlocale (LC_NUMERIC, "C");
Johannes Schaub - litb

Jawaban:

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

Apakah itu untuk saya, itu adalah sintaks C ++ yang valid untuk mengubah string menjadi ganda.

Anda dapat melakukannya dengan stringstream atau boost :: lexical_cast tetapi hal itu disertai dengan penalti kinerja.


Ahaha Anda memiliki proyek Qt ...

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

Catatan tambahan:
Jika data masukan adalah const char*, QByteArray::toDoubleakan lebih cepat.

TimW
sumber
7
boost :: lexical_cast sedang streaming.
TimW
1
Anda tidak bisa secara umum mengatakan mereka datang dengan penalti kinerja, saya kira. Pikirkan tentang apa yang terjadi jika sebelum itu Anda memiliki cin >> num ;. Pengguna harus mengetik dengan sangat cepat (rly jon skeet like) untuk mencatat milidetik lexical_cast lebih lambat :) Yang mengatakan, saya percaya ada tugas di mana lexical_cast hanya menyebalkan terlalu banyak kinerja :)
Johannes Schaub - litb
3
Untuk solusi ini, apa yang dilakukan :: di depan atof ()? Apa yang dibutuhkan untuk berada di sana?
sivabudh
4
@ShaChris Karena saya ingin memastikan saya menggunakan fungsi atof dari namespace global.
TimW
1
tergantung pada lokasi saat ini
nmr
104

Pustaka Standar (C ++ 11) menawarkan fungsionalitas yang diinginkan dengan std::stod:

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

Umumnya untuk kebanyakan tipe dasar lainnya, lihat <string>. Ada beberapa fitur baru untuk string C juga. Lihat<stdlib.h>

ManuelSchneid3r
sumber
4
Saya suka solusi ini, tetapi tampaknya hanya dari C ++ 11. Jadi tidak tersedia di SDK saya.
pamplemousse_mk2
Ini bagus untuk mengetahui bahwa panitia C ++ standar menambahkan ini. ostringstreamitu sendiri terlalu panjang untuk diketik, apalagi digunakan ..
bobobobo
4
Untuk float (seperti yang ditanyakan dalam pertanyaan yang saya temukan dengan google dengan mengetik "c ++ string to float"), seseorang harus menggunakan std :: stof.
Étienne
1
Hanya catatan bahwa ini dapat memunculkan pengecualian: std :: invalid_argument (jika konversi gagal) std :: out_of_range (jika di luar kisaran)
Jason Doucette
3
Pembeli berhati-hatilah, tergantung pada lokal saat ini.
nmr
29

Pemeran leksikal sangat bagus.

#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
sumber
Terima kasih, berhasil .. Tapi ini pertanyaan bagi saya: mengapa kode saya tidak berfungsi.
Max Frai
2
@Johannes Schaub: Berdasarkan ADL, dia mungkin juga memiliki, definisi yang menggunakan ditambah apa yang sebenarnya dia gunakan mungkin akan membawa ke ruang lingkup sejumlah besar elemen std. Selain itu lexical_cast sangat lambat, jadi tidak ada +1 dari saya.
Fitur yang bagus dari boost :: lexical_cast adalah penanganan kesalahan. Jika konversi gagal, pengecualian dilemparkan:try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
Semjon Mössinger
Untuk lebih tepatnya, gunakan catch ( boost::bad_lexical_cast const& err )untuk menangkap pengecualian.
Semjon Mössinger
14

Anda dapat menggunakan 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;
   }

Pemakaian:

double number= StringToNumber<double>("0.6");
Edison Gustavo Muenz
sumber
Uhm, jadi menurutmu boost :: lexical_cast memiliki antarmuka yang buruk, bukan? Lihat jawaban StefanB! Boost melakukan hal yang sama.
kirsche40
@ kirsche40 Sepertinya alternatif yang baik untuk orang-orang yang belum memiliki ketergantungan dengan Boost (menghubungkan dengan Boost hanya untuk mengonversi std :: string ke angka agak berlebihan!)
Jean-Philippe Jodoin
@ JEan-Phillippe Jodiun Saya menjawab komentar yang sekarang dihapus, di mana seseorang merekomendasikan Boost. Saya sadar bahwa Boost sering kali berlebihan. Ngomong-ngomong, untuk beberapa waktu sekarang penggunaan Boost dibatasi untuk kompiler "lebih baru". Proyek lama tidak dapat menggunakan Boost. Misalnya ASIO sangat bergantung pada fitur-fitur C ++ 11 seperti std :: addressof yang membuatnya benar-benar tidak berguna untuk kompiler C ++ 98 / C ++ 03. IMHO, ketika proyek dimulai, Boost bermaksud untuk menyediakan fitur "standar" baru untuk versi kompilator yang lebih lama ... :-(
kirsche40
10

Ya, dengan pemeran leksikal. Gunakan stringstream dan operator <<, atau gunakan Boost, mereka sudah menerapkannya.

Versi Anda sendiri akan terlihat seperti ini:

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

  os << x;
  os >> ret;

  return ret;  
}
DaClown
sumber
7

Anda dapat menggunakan boost lexical cast:

#include <boost/lexical_cast.hpp>

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

Catatan: boost :: lexical_cast melempar pengecualian jadi Anda harus siap menghadapinya ketika Anda memberikan nilai yang tidak valid, coba berikan string ("xxx")

StefanB
sumber
5

Jika Anda tidak ingin tarik di semua dorongan, pergi dengan strtod(3)dari <cstdlib>- sudah mengembalikan ganda.

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

Keluaran:

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

Mengapa atof () tidak berfungsi ... Anda menggunakan platform / kompiler apa?

haavee
sumber
Menggunakan aliran string tidak membutuhkan dorongan
jalf
Metode Anda juga mengembalikan nol. Linux.
Max Frai
3

Saya memiliki masalah yang sama di Linux

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

berhasil.

kenn
sumber
2
   double myAtof ( string &num){
      double tmp;
      sscanf ( num.c_str(), "%lf" , &tmp);
      return tmp;
   }
dpetek
sumber
1
Jawaban tidak valid, bagaimana Anda tahu bahwa nilai yang disimpan dalam bilangan sebenarnya adalah bilangan floating point yang valid? Anda tidak memeriksa kembali jenis sscanf, sepertinya gaya pengkodean MS.
1

Jawaban ini mendukung komentar Anda. Saya sangat curiga Anda tidak menampilkan hasilnya dengan benar.

Aku pernah mengalami hal yang persis sama padaku. Saya menghabiskan sepanjang hari mencoba mencari tahu mengapa saya mendapatkan nilai buruk menjadi int 64-bit, hanya untuk menemukan bahwa printf mengabaikan byte kedua. Anda tidak bisa begitu saja memberikan nilai 64-bit ke printf seperti int.

TED
sumber
Saya tidak menggunakan printf untuk melihat hasil ... Dan saya menggunakan nilai itu untuk mengatur opasitas jendela, dan jendela saya transparan penuh, jadi nilainya 0.
Max Frai
1

Cara C ++ 11 adalah dengan menggunakan std :: stod dan std :: to_string. Keduanya bekerja di Visual Studio 11.

BSalita
sumber
1

Mengapa atof() tidak berfungsi dalam pertanyaan asli: fakta bahwa itu dilemparkan menjadi dua kali lipat membuat saya curiga. Kode tidak boleh dikompilasi tanpa #include <stdlib.h>, tetapi jika pemeran ditambahkan untuk menyelesaikan peringatan kompilasi, maka atof()tidak dideklarasikan dengan benar. Jika compiler mengasumsikan atof()kembali int, casting itu akan memecahkan peringatan konversi, tetapi akan tidak menyebabkan nilai kembali untuk diakui sebagai ganda.

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

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

harus bekerja tanpa peringatan.

Iain
sumber
0

Daripada menyeret Boost ke dalam persamaan, Anda dapat menyimpan string (sementara) sebagai char[]dan digunakansprintf() .

Tetapi tentu saja jika Anda tetap menggunakan Boost, itu sebenarnya tidak terlalu menjadi masalah.

Chris Tonkinson
sumber
0

Anda tidak ingin Boost lexical_cast untuk string <-> floating point. Subset kasus penggunaan tersebut adalah satu-satunya rangkaian yang peningkatannya secara konsisten lebih buruk daripada fungsi yang lebih lama - dan pada dasarnya semua kegagalannya terkonsentrasi di sana, karena hasil performa mereka sendiri menunjukkan performa 20-25X lebih lambat daripada menggunakan sscanf dan printf untuk konversi semacam itu.

Google sendiri. boost :: lexical_cast dapat menangani sesuatu seperti 50 konversi dan jika Anda mengecualikan yang melibatkan floating point #s itu sama baiknya atau lebih baik dengan alternatif yang jelas (dengan keuntungan tambahan memiliki satu API untuk semua operasi tersebut). Tapi bawa pelampung dan itu seperti Titanic menabrak gunung es dalam hal kinerja.

Fungsi str-> double yang lama dan berdedikasi semuanya dapat melakukan 10.000 parsing dalam waktu seperti 30 ms (atau lebih baik). lexical_cast membutuhkan waktu seperti 650 ms untuk melakukan pekerjaan yang sama.

Zack Yezek
sumber
Tidak ada sumber? Saya mencari di Google sendiri: boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/…
Blake
0

Masalahku:

  1. String independen lokal menjadi ganda (pemisah desimal selalu '.')
  2. Deteksi kesalahan jika konversi string gagal

Solusi saya (menggunakan fungsi 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 ... butuh waktu lama bagi saya untuk mendapatkan solusi ini. Dan saya masih merasa bahwa saya tidak cukup tahu tentang lokalisasi string dan semacamnya ...

anhoppe
sumber