Я искал проблему, из-за которой я конвертирую float в удобочитаемый формат и обратно. А именно строка. Я столкнулся с проблемами при использовании stringstream и обнаружил, что atof дает «лучшие» результаты.
Обратите внимание, я не распечатываю данные в этом случае, я использовал отладчик для получения значений:
const char *val = "73.31";
std::stringstream ss;
ss << val << '\0';
float floatVal = 0.0f;
ss >> floatVal; //VALUE IS 73.3100052
floatVal = atof(val); //VALUE IS 73.3099976
Вероятно, этому есть разумное объяснение. Если бы кто-нибудь мог просветить меня, я был бы очень рад :).
Ответ основан на предположении, что OP использует MSVC
atof
действительно лучше в чтении значений с плавающей запятой, чем istream
,
Смотрите этот пример:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdlib>
int main()
{
const char *val = "73.31";
std::stringstream ss;
ss << val;
float floatVal = 0.0f;
ss >> floatVal;
std::cout << "istream>>(float&) :" << std::setw(18) << std::setprecision(15) << floatVal << std::endl;
double doubleVal = atof(val);
std::cout << "double atof(const char*) :" << std::setw(18) << std::setprecision(15) << doubleVal << std::endl;
floatVal = doubleVal;
std::cout << "(float)double atof(const char*) :" << std::setw(18) << std::setprecision(15) << floatVal << std::endl;
doubleVal = floatVal;
std::cout << "(double)(float)double atof(const char*) :" << std::setw(18) << std::setprecision(15) << floatVal << std::endl;
}
Выход:
istream>>(float&) : 73.3100051879883
double atof(const char*) : 73.31
(float)double atof(const char*) : 73.3099975585938
(double)(float)double atof(const char*) : 73.3099975585938
Компилятор даже предупреждает о преобразовании из double
в float
этот:
warning C4244: '=': conversion from 'double' to 'float', possible loss of data
Я также нашел эту страницу: Преобразования из типов с плавающей точкой
Обновить:
Значение 73.3099975585938
кажется правильным float
интерпретация double
значение 73.31
,
Обновить:
istream>>(double&)
также работает правильно:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdlib>
int main()
{
const char *val = "73.31";
std::stringstream ss;
ss << val;
double doubleVal = 0.0f;
ss >> doubleVal;
std::cout << "istream>>(double&) :" << std::setw(18) << std::setprecision(15) << doubleVal << std::endl;
}
Выход:
istream>>(double&) : 73.31
Для арифметических типов istream::operator>>
использования num_get::get
,
num_get::get
должен использовать что-то вроде scanf("%g")
за float
источник
НО:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <iomanip>
#include <cstdlib>int main()
{
std::string s = "73.31";
float f = 0.f;
sscanf(s.c_str(), "%g", &f);
std::cout << std::setw(18) << std::setprecision(15) << f << std::endl;
}
Выход:
73.3099975585938
Для меня это выглядит как ошибка в Microsoft num_get