std :: string để float hoặc double


98

Tôi đang cố gắng chuyển đổi std::stringsang float/double. Tôi đã thử:

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

Nhưng nó luôn trả về số không. Bất kỳ cách nào khác?


3
Chống lại ham muốn vận động quá mức một thứ gì đó đã được tìm ra cách đây một thập kỷ.
haavee

1
bạn có chắc là bạn xuất nó chính xác không? Nó sẽ không mang lại kết quả bằng không
Johannes Schaub - litb

1
Ngoài ra, bạn không cần ép buộc, nó đã trả về một nhân đôi.
AlbertoPL

Tôi chắc chắn. Trình gỡ lỗi hiển thị cho tôi 0. Và kết quả là 0. Nền tảng: Linux.
Max Frai

13
Bạn có chắc mình đã cài đặt đúng ngôn ngữ không? thử "0,6" hoặc setlocale (LC_NUMERIC, "C");
Johannes Schaub - litb

Câu trả lời:


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

Đối với tôi, nó là một cú pháp C ++ hợp lệ để chuyển đổi một chuỗi thành một chuỗi kép.

Bạn có thể làm điều đó với stringstream hoặc boost :: lexical_cast nhưng chúng đi kèm với hình phạt về hiệu suất.


Ahaha bạn có một dự án Qt ...

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

Lưu ý thêm:
Nếu dữ liệu đầu vào là a const char*, QByteArray::toDoublesẽ nhanh hơn.


7
boost :: lexical_cast đang phát trực tuyến.
TimW

1
Tôi nghĩ rằng bạn không thể nói họ đi kèm với một hình phạt hiệu suất. Hãy nghĩ về điều gì sẽ xảy ra khi bạn có một cin >> num ;. Người dùng sẽ phải nhập rất nhanh (rly jon tiltet như vậy) để ghi nhận mili giây lexical_cast chậm hơn :) Điều đó nói rằng, tôi tin rằng có những tác vụ mà lexical_cast chỉ hút quá nhiều hiệu suất :)
Johannes Schaub - litb

3
Đối với giải pháp này, :: ở phía trước của atof () làm gì? Nó cần gì ở đó?
sivabudh 17/02/10

4
@ShaChris Vì tôi muốn đảm bảo rằng mình sử dụng hàm atof từ không gian tên chung.
TimW

1
phụ thuộc vào ngôn ngữ hiện tại
2017

104

Thư viện Chuẩn (C ++ 11) cung cấp chức năng mong muốn với std::stod:

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

Nói chung cho hầu hết các loại cơ bản khác, hãy xem <string>. Cũng có một số tính năng mới cho chuỗi C. Xem<stdlib.h>


4
Tôi thích giải pháp này, nhưng có vẻ như nó chỉ từ C ++ 11. Vì vậy, không có sẵn trên SDK của tôi.
pamplemousse_mk2 Ngày

Thật tuyệt khi biết rằng ủy ban tiêu chuẩn C ++ đã thêm điều này. ostringstreambản thân nó chỉ đơn giản là quá lâu để gõ ra, hãy để một mình sử dụng ..
bobobobo

4
Đối với float (như đã hỏi trong câu hỏi mà tôi đã tìm thấy với google bằng cách nhập "c ++ string to float"), người ta nên sử dụng std :: stof.
Étienne

1
Chỉ cần một lưu ý rằng điều này có thể ném ngoại lệ: std :: invalid_argument (nếu chuyển đổi thất bại) std :: out_of_range (nếu ra khỏi phạm vi)
Jason Doucette

3
Người mua hãy cẩn thận, phụ thuộc vào ngôn ngữ hiện tại.
nmr

29

Dàn diễn viên Lexical rất đẹp.

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

Cảm ơn, nó hoạt động .. Nhưng đó là một câu hỏi cho tôi: tại sao mã của tôi không hoạt động.
Max Frai

2
@Johannes Schaub: Dựa trên ADL, anh ấy cũng có thể có, việc sử dụng định hướng cộng với những gì anh ấy thực sự đang sử dụng có thể sẽ đưa vào phạm vi một số lượng lớn các yếu tố std. Hơn nữa, lexical_cast rất chậm, vì vậy không có +1 nào từ tôi.

Một tính năng hay của boost :: lexical_cast là xử lý lỗi. Nếu chuyển đổi không thành công, một ngoại lệ sẽ được đưa ra:try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
Semjon Mössinger,

Nói chính xác hơn, sử dụng catch ( boost::bad_lexical_cast const& err )để bắt ngoại lệ.
Semjon Mössinger

14

Bạn có thể sử dụng 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;
   }

Sử dụng:

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

Uhm, vậy bạn nghĩ boost :: lexical_cast có một giao diện khủng khiếp, phải không? Nhìn vào câu trả lời của stefanB! Boost cũng làm như vậy.
kirsche 40

@ kirsche40 Có vẻ như một lựa chọn tốt cho những người chưa có phụ thuộc với Boost (liên kết với Boost chỉ để chuyển đổi một std :: string đến các số là một overkill chút!)
Jean-Philippe Jodoin

@ JEan-Phillippe Jodiun Tôi đã trả lời một nhận xét hiện đã bị xóa, nơi ai đó đã đề xuất Boost. Tôi biết rằng phần lớn thời gian Boost là quá mức cần thiết. Nhân tiện, hiện tại việc sử dụng Boost bị hạn chế đối với các trình biên dịch "mới hơn". Các dự án cũ hơn không thể sử dụng Boost. Ví dụ: ASIO phụ thuộc nhiều vào C ++ 11-tính năng như std :: addressof, điều này làm cho nó hoàn toàn vô giá trị đối với trình biên dịch C ++ 98 / C ++ 03. IMHO, khi dự án bắt đầu đó là ý định của Boost để cung cấp mới "chuẩn" tính năng cho phiên bản cũ biên dịch ... :-(
kirsche40

10

Có, với một dàn diễn viên từ vựng. Sử dụng một chuỗi chuỗi và toán tử << hoặc sử dụng Boost, họ đã triển khai nó.

Phiên bản của riêng bạn có thể trông giống như sau:

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

  os << x;
  os >> ret;

  return ret;  
}

7

Bạn có thể sử dụng tăng cường diễn viên từ vựng:

#include <boost/lexical_cast.hpp>

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

Lưu ý: boost :: lexical_cast ném ra ngoại lệ, vì vậy bạn nên chuẩn bị đối phó với nó khi bạn chuyển giá trị không hợp lệ, hãy thử chuyển chuỗi ("xxx")


5

Nếu bạn không muốn tăng tất cả, hãy chọn strtod(3)từ <cstdlib>- nó đã trả về một nhân đôi.

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

Kết quả đầu ra:

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

Tại sao atof () không hoạt động ... bạn đang sử dụng nền tảng / trình biên dịch nào?


Sử dụng một chuỗi chuỗi sẽ không yêu cầu tăng cường
jalf

Phương thức của bạn cũng trả về số không. Linux.
Max Frai

3

Tôi đã gặp vấn đề tương tự trong Linux

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

nó hoạt động.


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

1
Câu trả lời không hợp lệ, làm thế nào để bạn biết giá trị được lưu trữ trong num thực sự là một số dấu phẩy động hợp lệ? bạn không kiểm tra kiểu trả về của sscanf, có vẻ như kiểu mã hóa MS.

1

Câu trả lời này đang ủng hộ rất nhiều ý kiến ​​của bạn. Tôi rất nghi ngờ rằng bạn không hiển thị kết quả đúng cách.

Tôi đã có một lần chính xác điều đó xảy ra với tôi. Tôi đã dành cả ngày để cố gắng tìm ra lý do tại sao tôi nhận được một giá trị xấu vào một int 64-bit, chỉ để phát hiện ra rằng printf đang bỏ qua byte thứ hai. Bạn không thể chỉ chuyển một giá trị 64-bit vào printf giống như một giá trị int.


Tôi không sử dụng printf để xem kết quả ... Và tôi sử dụng giá trị đó để đặt độ mờ cửa sổ và cửa sổ của tôi là toàn bộ trasparent, vì vậy giá trị là 0.
Max Frai

1

Cách C ++ 11 là sử dụng std :: stod và std :: to_string. Cả hai đều hoạt động trong Visual Studio 11.


1

Về lý do tại sao atof()không hoạt động trong câu hỏi ban đầu: thực tế là nó được chọn tăng gấp đôi khiến tôi nghi ngờ. Mã không nên biên dịch mà không có #include <stdlib.h>, nhưng nếu ép kiểu được thêm vào để giải quyết cảnh báo biên dịch, thì mã đó atof()không được khai báo chính xác. Nếu trình biên dịch giả sử atof()trả về một int, việc ép kiểu sẽ giải quyết cảnh báo chuyển đổi, nhưng nó sẽ không khiến giá trị trả về được nhận dạng là một giá trị kép.

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

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

nên hoạt động mà không có cảnh báo.


0

Thay vì kéo Boost vào phương trình, bạn có thể giữ chuỗi của mình (tạm thời) như một char[]và sử dụng sprintf().

Nhưng tất nhiên nếu bạn đang sử dụng Boost, nó thực sự không quá nhiều vấn đề.


0

Dù sao thì bạn cũng không muốn Boost lexical_cast cho chuỗi <-> dấu phẩy động. Tập hợp con các trường hợp sử dụng đó là tập hợp duy nhất mà mức tăng liên tục kém hơn các chức năng cũ hơn- và về cơ bản chúng tập trung tất cả lỗi của chúng vào đó, bởi vì kết quả hiệu suất của riêng chúng cho thấy hiệu suất CHẬM hơn 20-25 lần so với sử dụng sscanf và printf cho các chuyển đổi như vậy.

Google nó cho mình. boost :: lexical_cast có thể xử lý một số thứ như 50 chuyển đổi và nếu bạn loại trừ những chuyển đổi liên quan đến dấu phẩy động #s thì càng tốt hoặc tốt hơn như các lựa chọn thay thế rõ ràng (với lợi thế bổ sung là có một API duy nhất cho tất cả các hoạt động đó). Nhưng mang lại những chiếc phao nổi và nó giống như con tàu Titanic va vào một tảng băng trôi về mặt hiệu suất.

Các hàm kép str-> cũ, chuyên dụng đều có thể thực hiện 10000 phân tích cú pháp trong 30 ms (hoặc tốt hơn). lexical_cast mất khoảng 650 mili giây để thực hiện công việc tương tự.


Không có nguồn? Tôi đã tự mình truy cập vào địa chỉ: boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/…
Blake

0

Vấn đề của tôi:

  1. Chuỗi độc lập ngôn ngữ thành đôi (dấu phân tách thập phân luôn là '.')
  2. Phát hiện lỗi nếu chuyển đổi chuỗi không thành công

Giải pháp của tôi (sử dụng hàm 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 ... tôi mất khá nhiều thời gian để đi đến giải pháp này. Và tôi vẫn có cảm giác rằng tôi không biết đủ về bản địa hóa chuỗi và những thứ ...

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.