std :: string to float หรือ double


99

ฉันกำลังพยายามแปลงstd::stringเป็นfloat/doubleไฟล์. ฉันเหนื่อย:

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

แต่จะส่งกลับศูนย์เสมอ วิธีอื่น ๆ ?


3
ต่อต้านความต้องการที่จะใช้เครื่องมือมากเกินไปในบางสิ่งที่คิดไว้เมื่อสิบปีก่อน
haavee

1
แน่ใจหรือว่าส่งออกมาถูกต้อง มันไม่ควรให้ศูนย์
Johannes Schaub - litb

1
นอกจากนี้คุณไม่จำเป็นต้องโยน atof มันส่งคืนสองเท่าแล้ว
AlbertoPL

ฉันแน่ใจ. ดีบักเกอร์แสดงให้ฉันเห็น 0 และผลลัพธ์คือ 0 แพลตฟอร์ม: Linux
Max Frai

13
คุณแน่ใจหรือไม่ว่าคุณได้ติดตั้งภาษาที่ถูกต้องแล้ว? ลอง "0,6" หรือ setlocale (LC_NUMERIC, "C");
Johannes Schaub - litb

คำตอบ:


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

สำหรับฉันมันเป็นไวยากรณ์ C ++ ที่ถูกต้องในการแปลงสตริงเป็นคู่

คุณสามารถทำได้ด้วย stringstream หรือ boost :: lexical_cast แต่สิ่งเหล่านี้มาพร้อมกับการลงโทษด้านประสิทธิภาพ


อ่าฮะคุณมีโครงการ Qt ...

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

หมายเหตุพิเศษ:
หากข้อมูลของท่านเป็นconst char*, QByteArray::toDoubleจะเร็วขึ้น


7
boost :: lexical_cast กำลังสตรีม
TimW

1
โดยทั่วไปคุณไม่สามารถพูดได้ว่าพวกเขามาพร้อมกับบทลงโทษด้านประสิทธิภาพฉันคิดว่า ลองนึกถึงสิ่งที่เกิดขึ้นเมื่อก่อนหน้านี้คุณมี cin >> num; ผู้ใช้จะต้องพิมพ์เร็วมาก (rly jon skeet like) เพื่อที่จะสังเกตว่า lexical_cast ในระดับมิลลิวินาทีนั้นช้าลง :) ที่กล่าวว่าฉันเชื่อว่ามีงานที่ lexical_cast ดูดประสิทธิภาพมากเกินไป :)
Johannes Schaub - litb

3
สำหรับวิธีแก้ปัญหานี้ :: in front of atof () ทำอะไร? มันต้องมีอะไร?
sivabudh

4
@ShaChris เพราะฉันต้องการให้แน่ใจว่าฉันใช้ฟังก์ชัน atof จากเนมสเปซส่วนกลาง
TimW

1
ขึ้นอยู่กับสถานที่ปัจจุบัน
นาโนเมตร

104

Standard Library (C ++ 11) มีฟังก์ชันที่ต้องการด้วยstd::stod:

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

<string>โดยทั่วไปส่วนใหญ่ประเภทพื้นฐานอื่นดู มีคุณสมบัติใหม่บางอย่างสำหรับสตริง C ด้วย ดู<stdlib.h>


4
ฉันชอบวิธีนี้ แต่ดูเหมือนว่ามันมาจาก C ++ 11 เท่านั้น ดังนั้นจึงไม่มีใน SDK ของฉัน
pamplemousse_mk2

เป็นเรื่องดีที่ทราบว่าคณะกรรมการมาตรฐาน C ++ ได้เพิ่มสิ่งนี้ ostringstreamในตัวมันเองก็ยาวเกินไปที่จะพิมพ์ออกมานับประสาอะไรกับ ..
bobobobo

4
สำหรับการลอย (ตามที่ถามในคำถามที่พบกับ google โดยพิมพ์ "c ++ string to float") ควรใช้ std :: stof
Étienne

1
โปรดทราบว่าสิ่งนี้สามารถทำให้เกิดข้อยกเว้น: std :: invalid_argument (หากการแปลงล้มเหลว) std :: out_of_range (ถ้าอยู่นอกช่วง)
Jason Doucette

3
ผู้ซื้อระวังขึ้นอยู่กับสถานที่ปัจจุบัน
นาโนเมตร

29

คำศัพท์น่ารักมาก

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

ขอบคุณมันใช้งานได้ .. แต่เป็นคำถามสำหรับฉัน: ทำไมรหัสของฉันไม่ทำงาน
Max Frai

2
@Johannes Schaub: จาก ADL เขาอาจมีเช่นกันการกำหนดโดยใช้บวกกับสิ่งที่เขาใช้จริงอาจทำให้องค์ประกอบมาตรฐานจำนวนมากเข้าสู่ขอบเขต นอกจากนี้ lexical_cast ยังช้าอย่างบ้าคลั่งจึงไม่มี +1 จากฉัน

คุณสมบัติที่ดีของ boost :: lexical_cast คือการจัดการข้อผิดพลาด หากการแปลงล้มเหลวข้อยกเว้นจะถูกโยนทิ้ง:try { ... boost::lexical_cast ... } catch (std::exception const& err) { //handle excpetion }
Semjon Mössinger

เพื่อให้แม่นยำยิ่งขึ้นให้ใช้catch ( boost::bad_lexical_cast const& err )เพื่อตรวจจับข้อยกเว้น
Semjon Mössinger

14

คุณสามารถใช้ 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;
   }

การใช้งาน:

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

อืมคุณคิดว่า boost :: lexical_cast มีอินเทอร์เฟซที่แย่มากใช่ไหม ดูคำตอบของ stefanB! Boost ก็เช่นเดียวกัน
kirsche40

@ kirsche40 ดูเหมือนจะเป็นทางเลือกที่ดีสำหรับผู้ที่ยังไม่มีการอ้างอิงกับ Boost (การเชื่อมโยงกับ Boost เพียงเพื่อแปลง std :: string เป็นตัวเลขนั้นเกินความสามารถไปหน่อย!)
Jean-Philippe Jodoin

@ JEan-Phillippe Jodiun ฉันตอบความคิดเห็นที่ลบไปแล้วซึ่งมีคนแนะนำ Boost ฉันทราบดีว่า Boost เป็นช่วงเวลาที่มากเกินไป อย่างไรก็ตามในบางครั้งการใช้ Boost ถูก จำกัด ไว้ที่คอมไพเลอร์ "รุ่นใหม่" โครงการที่เก่ากว่าไม่สามารถใช้ Boost ได้ ตัวอย่างเช่น ASIO ขึ้นอยู่กับคุณลักษณะ C ++ 11 เช่น std :: addressof ซึ่งทำให้ไม่มีค่าสำหรับคอมไพเลอร์ C ++ 98 / C ++ 03 IMHO เมื่อโครงการเริ่มต้นเป็นความตั้งใจของ Boost ที่จะให้คุณลักษณะ "มาตรฐาน" ใหม่สำหรับคอมไพเลอร์เวอร์ชันเก่า ... :-(
kirsche40

10

ใช่ด้วยการร่ายคำศัพท์ ใช้ stringstream และ << โอเปอเรเตอร์หรือใช้ Boost พวกเขาได้ติดตั้งไปแล้ว

เวอร์ชันของคุณเองอาจมีลักษณะดังนี้:

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

  os << x;
  os >> ret;

  return ret;  
}

7

คุณสามารถใช้การร่ายเสริมคำศัพท์:

#include <boost/lexical_cast.hpp>

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

หมายเหตุ: boost :: lexical_cast จะแสดงข้อยกเว้นดังนั้นคุณควรเตรียมพร้อมที่จะจัดการเมื่อคุณส่งค่าที่ไม่ถูกต้องให้ลองส่งสตริง ("xxx")


5

หากคุณไม่ต้องการลากบูสต์ทั้งหมดให้ไปstrtod(3)จาก<cstdlib>- มันจะส่งคืนค่าสองเท่า

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

ผลลัพธ์:

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

ทำไม atof () ไม่ทำงาน ... คุณอยู่บนแพลตฟอร์ม / คอมไพเลอร์อะไร


การใช้สตรีมสตริงไม่จำเป็นต้องเพิ่ม
jalf

วิธีของคุณคืนค่าศูนย์ด้วย ลินุกซ์
Max Frai

3

ฉันมีปัญหาเดียวกันใน Linux

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

มันได้ผล.


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

1
คำตอบไม่ถูกต้องคุณจะรู้ได้อย่างไรว่าค่าที่จัดเก็บใน num เป็นตัวเลขทศนิยมที่ถูกต้อง? คุณไม่ได้ตรวจสอบประเภทการส่งคืนของ sscanf ดูเหมือนว่าจะเป็นสไตล์การเข้ารหัส MS

1

คำตอบนี้กำลังสำรองข้อมูล litb ในความคิดเห็นของคุณ ฉันมีความสงสัยอย่างยิ่งว่าคุณไม่ได้แสดงผลอย่างถูกต้อง

ฉันเคยมีสิ่งเดียวกันเกิดขึ้นกับฉันครั้งหนึ่ง ฉันใช้เวลาทั้งวันในการพยายามหาสาเหตุว่าทำไมฉันถึงได้รับค่าที่ไม่ถูกต้องเป็น int 64 บิตเพียงเพื่อจะพบว่า printf ไม่สนใจไบต์ที่สอง คุณไม่สามารถส่งค่า 64 บิตไปยัง printf ได้เหมือนกับ int


ฉันไม่ได้ใช้ printf เพื่อดูผลลัพธ์ ... และฉันใช้ค่านั้นเพื่อตั้งค่าความทึบของหน้าต่างและหน้าต่างของฉันเป็น trasparent แบบเต็มดังนั้นค่าจึงเป็น 0
Max Frai


1

เหตุใดจึงatof()ไม่ทำงานในคำถามเดิม: ความจริงที่ว่ามันเป็นสองเท่าทำให้ฉันสงสัย โค้ดไม่ควรคอมไพล์โดยไม่มี#include <stdlib.h>แต่ถ้ามีการเพิ่ม cast เพื่อแก้คำเตือนการคอมไพล์แสดงว่าatof()ไม่ถูกต้อง หากคอมไพลเลอร์ถือว่าatof()ส่งกลับ int การแคสต์จะแก้คำเตือนการแปลง แต่จะไม่ทำให้ค่าที่ส่งคืนถูกรับรู้ว่าเป็นสองเท่า

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

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

ควรทำงานโดยไม่มีคำเตือน


0

แทนที่จะลาก Boost เป็นสมการที่คุณสามารถเก็บสายของคุณ (ชั่วคราว) เป็นและการใช้งานchar[]sprintf()

แต่แน่นอนว่าถ้าคุณใช้ Boost อยู่แล้วมันก็ไม่ใช่ปัญหามากเกินไป


0

คุณไม่ต้องการ Boost lexical_cast สำหรับ string <-> floating point กรณีการใช้งานชุดย่อยดังกล่าวเป็นชุดเดียวที่การเพิ่มประสิทธิภาพอย่างต่อเนื่องนั้นแย่กว่าฟังก์ชันรุ่นเก่า - และโดยพื้นฐานแล้วพวกเขาจะเน้นความล้มเหลวทั้งหมดที่นั่นเนื่องจากผลการปฏิบัติงานของตัวเองแสดงประสิทธิภาพ SLOWER 20-25X เมื่อเทียบกับการใช้ sscanf และ printf สำหรับการแปลง

Google ด้วยตัวคุณเอง boost :: lexical_cast สามารถจัดการบางอย่างเช่นการแปลง 50 รายการและหากคุณยกเว้นรายการที่เกี่ยวข้องกับจุดลอยตัว #s ดีหรือดีกว่าเป็นทางเลือกที่ชัดเจน (ด้วยข้อดีเพิ่มเติมของการมี API เดียวสำหรับการดำเนินการทั้งหมด) แต่นำมาซึ่งการลอยตัวและเหมือนเรือไททานิกชนภูเขาน้ำแข็งในแง่ของประสิทธิภาพ

ฟังก์ชัน str-> double แบบเก่าโดยเฉพาะสามารถทำ 10,000 parses ในบางอย่างเช่น 30 ms (หรือดีกว่า) lexical_cast ใช้เวลาประมาณ 650 ms ในการทำงานเดียวกัน


ไม่มีที่มา? ฉัน googled มันด้วยตัวเอง: boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/…
Blake

0

ปัญหาของฉัน:

  1. สตริงอิสระตำแหน่งเป็นสองเท่า (ตัวคั่นทศนิยมเสมอ '.')
  2. การตรวจจับข้อผิดพลาดหากการแปลงสตริงล้มเหลว

โซลูชันของฉัน (ใช้ฟังก์ชัน 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 ... ใช้เวลานานพอสมควรในการแก้ปัญหานี้ และฉันยังมีความรู้สึกว่าฉันไม่รู้จักการแปลสตริงและสิ่งต่างๆมากพอ ...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.