2010-09-29 4 views
2

Я задаюсь вопросом, какой алгоритм может быть использован, чтобы взять что-то вроде «4.72» в тип данных с плавающей точкой, равныйстрока для преобразования плавающего?

float x = 4.72; 
+7

Вы действительно хотите * алгоритм * или просто функцию, которая уже написана? – fennec

ответ

10

scanf, operator>> для istreams и strtof - это очевидный выбор.

Там это также atof, но, как atoi, ему не хватает способ сказать вам произошла ошибка на входе, так что, как правило, лучше избегать обоих.

+0

+1 для 'strtof'. –

0

В atof() функция может быть полезной. http://www.cplusplus.com/reference/clibrary/cstdlib/atof/

+0

Я настоятельно рекомендую 'strtod()' over 'atof()', поскольку у вас есть больше шансов узнать, что что-то пошло не так, когда вы получаете неожиданный ввод с помощью 'strtod()'. – RBerteig

+0

Совершенно верно. Согласен. –

3

Для Cstrtod() и C99 друзей strtof() и strtold() (описание на той же ссылке) уже есть, что алгоритм реализован.

Если у вас возникли проблемы с написанием собственного сообщения, напишите свой код и задайте ему конкретные вопросы.

+0

'strtof' вместо' strtod', так как вопрошающий хочет 'float' вместо' double'. –

+0

Правый Стивен, спасибо (но strtof и strtold являются «новыми»). Сообщение отредактировано. – pmg

+0

Использование 'strtod' и преобразование результата в' float' (неявно или с литой) является столь же хорошим и более переносимым, чем 'strtof'. –

10

Для C++ вы можете использовать boost::lexical_cast:

std::string str("4.72"); 
    float x = boost::lexical_cast<float>(str); 

Для C вы можете использовать sscanf:

char str[]= "4.72"; 
    float x; 
    sscanf(str, "%f", &x); 
3

Для C++ This это алгоритм, который я использую:

bool FromString(const string& str, double& number) { 

    std::istringstream i(str); 

    if (!(i >> number)) { 
     // Number conversion failed 
     return false; 
    } 

    return true; 
} 

Я использовал atof() в прошлом для преобразования, но я нашел это проблематичным, потому что если действительное преобразование не может быть выполнено, оно вернется (0.0). Таким образом, вы не знали бы, не сработали ли они и вернули нуль, или если в строке действительно было «0».

0

От cplusplus.com: «stringstream предоставляет интерфейс для управления строками, как если бы они были потоками ввода/вывода».

Вы можете инициализировать stringstream с вашей строки, то читать поплавок из stringstream используя operator>> так же, как вы бы с cin.

Вот пример:

#include<iostream> 
#include<string> 
#include<sstream> 
using namespace std; 

int main() { 
    string s = "4.72"; 
    stringstream sstrm(s); 
    float x; 
    sstrm >> x; 
    cout << x << endl; 
} 
1

Я предполагаю, что вы хотите, фактический алгоритм, а не функция библиотеки, которая уже делает это. У меня нет времени, чтобы написать и проверить фактический код, но вот то, что я хотел бы сделать:

  1. Инициализировать поплавок, который будет использоваться в качестве аккумулятора 0.
  2. Выяснить, где десятичное место в строке это даст вам знать, что такое «столбец» каждой из цифр (т.е. 100, 10, 1, 1, 10 и т.д.).
  3. Начало в начале строки.
  4. Снять эту цифру, преобразовать в int (тривиально сделано путем вычитания 0x30 из значения ASCII)
  5. Умножьте значение на столбец места (для первой цифры в вашем примере это будет 4 * 1 == 4 , для следующей цифры 7 * 0,1 == 0,7).
  6. Добавить результат в аккумулятор
  7. Повторите шаг 4 для каждой оставшейся цифры.
  8. Аккумулятор теперь содержит ваш результат.

Из-за округления преобразования между базой 10 и базой 2 на каждой итерации этого цикла результат, полученный из этого алгоритма, может быть не самым близким бинарным представлением к исходному значению. Я действительно не знаю, как улучшить его, хотя ... возможно, кто-то еще может это сделать.

+2

Не забудьте обработать цифры типа '-1.2e-3'. Это преобразование чревато тонкостями и краевыми случаями. Это отнюдь не просто, чтобы получить право. Если вы должны реализовать его самостоятельно, проверьте дерьмо из него на каждом краевом кейсе, о котором вы можете мечтать. А потом волнуйся. И не забывайте также о случаях NaN и INF. – RBerteig

+1

@RBerteig: если это моя функция преобразования строк, я могу просто объявить отрицательные числа и научную нотацию недействительными;) Но на самом деле, да, это должно быть более сложным, чем то, что я написал. Я подумал, что ОП просто пытается обернуть вокруг, как такое преобразование возможно. – rmeador

+0

Конечно, вы можете принять решение о разумных пределах для того, что должно быть обработано для упрощения проблемы. Я просто подумал, что добавлю напоминание о том, что преобразование текста в плавающую точку, возможно, придется обрабатывать случаи, более сложные, чем «4.72». Одна реализация C89-совместимого 'strtod()' я видел, например, около 80 строк плотного и едва прокомментированного кода. – RBerteig

3

Как вы просили алгоритм, а не метод, вот мое объяснение для простого алгоритма (и реализация в C):

  1. Initialize 4 целочисленных переменных, одна для значения до точки , один для последующей части, один для власти мантиссы, один для знака. Скажем, f, m, d, sign = 1.
  2. Сначала найдите знак + или - в начале. Если нет знаковых знаков или знак +, продолжайте. Если первый символ -, то знак = -1.
  3. Затем прочитайте целочисленное значение в f до a. или NULL.
  4. Если вы закончите с символом точки, начните чтение части мантиссы, как на предыдущем шаге, в m. Но на этот раз также умножьте d на 10 с каждой цифрой.
  5. В конце, знак возврата * (f + (float) m/d). Кастинг гарантирует, что деление выполняется в плавающих точках, а тип выражения - float.

Думаю, чтение кода может быть проще. Итак, вот код:

float atof(char *s) 
{ 
    int f, m, sign, d=1; 
    f = m = 0; 

    sign = (s[0] == '-') ? -1 : 1; 
    if (s[0] == '-' || s[0] == '+') s++; 

    for (; *s != '.' && *s; s++) { 
      f = (*s-'0') + f*10; 
    } 
    if (*s == '.') 
      for (++s; *s; s++) { 
        m = (*s-'0') + m*10; 
        d *= 10; 
      } 
    return sign*(f + (float)m/d); 
} 
+0

Приятное и понятное объяснение с источником для простой части. Не забудьте обработать '-1e-6',' .3e + 5', '+ 2.e-4' и т. Д. Или указать явно, что вы не разрешаете эту форму. Подумайте о том, как лучше обрабатывать неверные числа (попробуйте «ABC» в качестве входных данных). Также рассмотрите обработку NaN и INF. C99 требует, чтобы 'scanf()' был способен точно восстановить значение, напечатанное 'printf()', даже NaN и INF. C89 не делает, но его 'strtod()' выполняет дескриптор 'E'. – RBerteig

Смежные вопросы