Преобразование float в строку

Как преобразовать целое число с плавающей запятой в строку в C / C ++ без библиотечной функции sprintf ?

Я ищу функцию, например char *ftoa(float num) которая преобразует num в строку и возвращает ее.

ftoa(3.1415) должен возвращать "3.1415" .

Когда вы имеете дело с номерами fp, он может получить очень сложный код, но алгоритм упрощен и подобен ответу edgar holleis; престижность! Его сложность, потому что, когда вы имеете дело с числами с плавающей запятой, вычисления будут немного завышены в зависимости от выбранной вами точности. Вот почему его не очень хорошая практика программирования сравнить float с нолем.

Но есть ответ, и это моя попытка реализовать его. Здесь я использовал значение допуска, чтобы вы не вычисляли слишком много десятичных знаков, что приводило к бесконечному циклу. Я уверен, что там могут быть лучшие решения, но это должно помочь вам хорошо понять, как это сделать.

 char fstr[80]; float num = 2.55f; int m = log10(num); int digit; float tolerance = .0001f; while (num > 0 + precision) { float weight = pow(10.0f, m); digit = floor(num / weight); num -= (digit*weight); *(fstr++)= '0' + digit; if (m == 0) *(fstr++) = '.'; m--; } *(fstr) = '\0'; 

Основываясь на ответе Софи Пэла, это немного более полное решение, учитывающее число ноль, NaN, бесконечные, отрицательные числа и научную нотацию. Хотя sprintf по-прежнему обеспечивает более точное строковое представление.

 /* Double to ASCII Conversion without sprintf. Roughly equivalent to: sprintf(s, "%.14g", n); */ #include  #include  // For printf #include  static double PRECISION = 0.00000000000001; static int MAX_NUMBER_STRING_SIZE = 32; /** * Double to ASCII */ char * dtoa(char *s, double n) { // handle special cases if (isnan(n)) { strcpy(s, "nan"); } else if (isinf(n)) { strcpy(s, "inf"); } else if (n == 0.0) { strcpy(s, "0"); } else { int digit, m, m1; char *c = s; int neg = (n < 0); if (neg) n = -n; // calculate magnitude m = log10(n); int useExp = (m >= 14 || (neg && m >= 9) || m <= -9); if (neg) *(c++) = '-'; // set up for scientific notation if (useExp) { if (m < 0) m -= 1.0; n = n / pow(10.0, m); m1 = m; m = 0; } if (m < 1.0) { m = 0; } // convert the number while (n > PRECISION || m >= 0) { double weight = pow(10.0, m); if (weight > 0 && !isinf(weight)) { digit = floor(n / weight); n -= (digit * weight); *(c++) = '0' + digit; } if (m == 0 && n > 0) *(c++) = '.'; m--; } if (useExp) { // convert the exponent int i, j; *(c++) = 'e'; if (m1 > 0) { *(c++) = '+'; } else { *(c++) = '-'; m1 = -m1; } m = 0; while (m1 > 0) { *(c++) = '0' + m1 % 10; m1 /= 10; m++; } c -= m; for (i = 0, j = m-1; i 

Выходы:

  1. printf: 0, dtoa: 0
  2. printf: 42, dtoa: 42
  3. printf: 1234567.8901234, dtoa: 1234567.89012344996444
  4. printf: 1.8e-14, dtoa: 1.79999999999999e-14
  5. printf: 555555.55555556, dtoa: 555555.55555555550381
  6. printf: -8.8888888888889e + 14, dtoa: -8.88888888888888e + 14
  7. printf: 1.1111111111111e + 23, dtoa: 1.11111111111111e + 23
  1. Используйте log функцию, чтобы узнать величину m вашего номера. Если величина отрицательная, напечатайте "0." и соответствующее количество нhive.
  2. Последовательно делим на 10^m и передаем результат в int, чтобы получить десятичные цифры. m-- для следующей цифры.
  3. Если вы пришли к m==0 , не забудьте напечатать десятичную точку "." ,
  4. Отломитесь после пары цифр. Если m>0 при разрыве, не забудьте напечатать "E" и itoa(m) .

Вместо log функции вы также можете напрямую извлекать экспоненту путем смещения бит и корректировки смещения экспоненты (см. IEEE 754). Java имеет двоичную функцию для получения двоичного представления.

  /* * Program to convert float number to string without using sprintf */ #include "iostream" #include "string" #include "math.h" # define PRECISION 5 using namespace std; char* floatToString(float num) { int whole_part = num; int digit = 0, reminder =0; int log_value = log10(num), index = log_value; long wt =0; // String containg result char* str = new char[20]; //Initilise stirng to zero memset(str, 0 ,20); //Extract the whole part from float num for(int i = 1 ; i < log_value + 2 ; i++) { wt = pow(10.0,i); reminder = whole_part % wt; digit = (reminder - digit) / (wt/10); //Store digit in string str[index--] = digit + 48; // ASCII value of digit = digit + 48 if (index == -1) break; } index = log_value + 1; str[index] = '.'; float fraction_part = num - whole_part; float tmp1 = fraction_part, tmp =0; //Extract the fraction part from num for( int i= 1; i < PRECISION; i++) { wt =10; tmp = tmp1 * wt; digit = tmp; //Store digit in string str[++index] = digit +48; // ASCII value of digit = digit + 48 tmp1 = tmp - digit; } return str; } //Main program void main() { int i; float f = 123456.789; char* str = floatToString(f); cout << endl << str; cin >> i; delete [] str; } 

Просто нашли реальную хорошую реализацию на https://code.google.com/p/stringencoders/

 size_t modp_dtoa(double value, char* str, int prec) { /* Hacky test for NaN * under -fast-math this won't work, but then you also won't * have correct nan values anyways. The alternative is * to link with libmath (bad) or hack IEEE double bits (bad) */ if (! (value == value)) { str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0'; return (size_t)3; } /* if input is larger than thres_max, revert to exponential */ const double thres_max = (double)(0x7FFFFFFF); double diff = 0.0; char* wstr = str; if (prec < 0) { prec = 0; } else if (prec > 9) { /* precision of >= 10 can lead to overflow errors */ prec = 9; } /* we'll work in positive values and deal with the negative sign issue later */ int neg = 0; if (value < 0) { neg = 1; value = -value; } int whole = (int) value; double tmp = (value - whole) * powers_of_10[prec]; uint32_t frac = (uint32_t)(tmp); diff = tmp - frac; if (diff > 0.5) { ++frac; /* handle rollover, eg case 0.99 with prec 1 is 1.0 */ if (frac >= powers_of_10[prec]) { frac = 0; ++whole; } } else if (diff == 0.5 && ((frac == 0) || (frac & 1))) { /* if halfway, round up if odd, OR if last digit is 0. That last part is strange */ ++frac; } /* for very large numbers switch back to native sprintf for exponentials. anyone want to write code to replace this? */ /* normal printf behavior is to print EVERY whole number digit which can be 100s of characters overflowing your buffers == bad */ if (value > thres_max) { sprintf(str, "%e", neg ? -value : value); return strlen(str); } if (prec == 0) { diff = value - whole; if (diff > 0.5) { /* greater than 0.5, round up, eg 1.6 -> 2 */ ++whole; } else if (diff == 0.5 && (whole & 1)) { /* exactly 0.5 and ODD, then round up */ /* 1.5 -> 2, but 2.5 -> 2 */ ++whole; } } else { int count = prec; // now do fractional part, as an unsigned number do { --count; *wstr++ = (char)(48 + (frac % 10)); } while (frac /= 10); // add extra 0s while (count-- > 0) *wstr++ = '0'; // add decimal *wstr++ = '.'; } // do whole part // Take care of sign // Conversion. Number is reversed. do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10); if (neg) { *wstr++ = '-'; } *wstr='\0'; strreverse(str, wstr-1); return (size_t)(wstr - str); } 

У вас две основные проблемы:

  1. Преобразование представления битов в строку символов
  2. Выделение достаточной памяти для хранения символов.

Самый простой способ решить вторую часть – выделить достаточно большой кусок для каждого возможного ответа. Начните с этого. Позже вы захотите быть более умными, но не беспокойтесь, пока не решите числовую часть проблемы.

У вас есть два набора инструментов для работы с числовой частью проблемы: прямая манипуляция бит (маскирование, перемещение и т. Д.) И арифметическая операция (*, +, /, плюс возможно математические функции link log() ).

В принципе вы могли бы напрямую поработать с поразрядным представлением, но это не было бы переносимым в том случае, если форматы представления с плавающей запятой изменяются в будущем. Метод, предложенный edgar.holleis, должен быть переносимым.

Вот что я придумал; это очень эффективно и очень просто. Предполагается, что ваша система имеет itoa .

 #include  #include  /* return decimal part of val */ int dec(float val) { int mult = floor(val); while (floor(val) != ceil(val)) { mult *= 10; val *= 10; } return floor(val) - mult; } /* convert a double to a string */ char *ftoa(float val, char *str) { if (isnan(n)) { strcpy(str, "NaN"); return str; } else if (isinf(n)) { strcpy(str, "inf"); return str; } char leading_integer[31] = {0}; // 63 instead of 31 for 64-bit systems char trailing_decimal[31] = {0}; // 63 instead of 31 for 64-bit systems /* fill string with leading integer */ itoa(floor(val), leading_integer, 10); /* fill string with the decimal part */ itoa(dec(val), trailing_decimal, 10); /* set given string to full decimal */ strcpy(str, leading_integer); strcat(str, "."); strcat(str, trailing_decimal); return str; } 

Попробуйте прямо сейчас!

Этот смысл может помочь: https://gist.github.com/psych0der/6319244 Основная идея состоит в том, чтобы разделить всю часть и десятичную часть, а затем объединить оба из них с десятичной точкой между ними.

  • Приведение float в int (побитовое) в C
  • Является ли добавление и умножение с плавающей запятой ассоциативным?
  • Что случилось с этим делением?
  • Двойной расчет, создающий нечетный результат
  • Какова максимальная длина в символах, необходимых для представления любого двойного значения?
  • Сделать поплавок показывать только два десятичных знака
  • Равновесие и допуски с плавающей точкой
  • Детали реализации оборудования с плавающей запятой
  • Каково первое целое число, которое плавающий IEEE 754 не может точно представлять?
  • Какой диапазон чисел может быть представлен в 16-, 32- и 64-битных системах IEEE-754?
  • Как получить десятичную часть поплавка?
  • Interesting Posts

    Зеркальное изображение двоичного дерева

    Является ли transferCurrentComplicationUserInfo более подходящим для обновления осложнений?

    FIELDDATA Данные слишком велики

    Что такое «символ» в Джулии?

    Предотrotation атаки CSRF, XSS и SQL Injection в JSF

    Как отладить ошибку w3wp clr.dll

    Воспроизведение локального (жесткого диска) видеофайла с помощью тега HTML5?

    Изменение пути поиска DLL для статической связанной DLL

    Где я могу получить репозитории для старых версий Ubuntu?

    Как создать URL веб-API ASP.NET?

    Ionic2 / Angular2 – прочитать пользовательский файл конфигурации

    Как использовать контейнер DI / IoC с привязкой модели в ASP.NET MVC 2+?

    jQuery .load () не работает в IE, но отлично работает в Firefox, Chrome и Safari

    Почему браузеры создают префиксы поставщиков для свойств CSS?

    На ноутбуке Intel Core Duo с 32-разрядной версией Windows 7 будут проблемы с производительностью, если я установлю комплект памяти объемом 4 ГБ?

    Давайте будем гением компьютера.