Подтвердить что ты не робот

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

Мне нужно преобразовать число с плавающей запятой в эквивалентную строку в десятичной (или другой базе). Сначала преобразование должно выполняться в формате xE+0, где x - номер с плавающей запятой.

Идея состоит в том, чтобы сначала усечь число с плавающей запятой во временное целое число и затем преобразовать это целое число в строку, а затем рассмотреть дробную часть, умножить ее на 10, а дробная часть не станет 0, После того, как дробная часть передается в левую часть десятичной точки, снова примените целочисленное значение к строковой функции и преобразуйте часть дроби в строку. Есть ли лучший способ, который будет быстрее этого? Будет ли этот метод вызывать какие-либо побочные эффекты?

Чтобы преобразовать число с плавающей запятой в экспоненциальное представление, я должен сделать то же самое, что и выше, а затем отрегулировать мощность? Или непосредственно битмаскируйте представление IEEE 754 и преобразуйте каждую часть в строку.

Примечание. Никакие другие функции не могут использоваться, потому что у меня есть доступ к абсолютно никаким библиотечным функциям. Этот код переходит в игрушечное ядро.

4b9b3361

Ответ 1

Единственное точное решение - выполнить десятичную арифметику с произвольной точностью для базового преобразования, поскольку точное значение может быть очень длинным - для 80-битного long double, до примерно 10000 знаков после запятой, К счастью, это "всего" примерно до 700 мест для IEEE double.

Вместо того, чтобы работать с отдельными десятичными цифрами, полезно вместо этого работать с базой 1 млрд. (максимальная мощность 10, которая соответствует 32-битовому целому числу), а затем конвертировать эти цифры "базовый 1 млрд." в 9 десятичные цифры в конце вычислений.

У меня очень плотная (довольно трудная для чтения), но эффективная реализация здесь, в LGPL Лицензия MIT:

http://git.musl-libc.org/cgit/musl/blob/src/stdio/vfprintf.c?h=v1.1.6

Если вы вычеркнете всю поддержку шестнадцатеричного поплавка, поддержку бесконечности/ната, поддержку вариации %g/%f/%e, округление (которое никогда не понадобится, если вы хотите только точные ответы) и другие вещи вам может и не понадобиться, оставшийся код довольно прост.

Ответ 2

Используйте snprintf() из stdlib.h. Работал для меня.

double num = 123412341234.123456789; 
char output[50];

snprintf(output, 50, "%f", num);

printf("%s", output);

Ответ 3

Перейдите и посмотрите реализацию printf() с помощью "%f" в некоторой библиотеке C.

Ответ 4

Я знаю, может быть, это не нужно, но я создал функцию, которая преобразует float в строку:

CODE:

#include <stdio.h>

/** Number on countu **/

int n_tu(int number, int count)
{
    int result = 1;
    while(count-- > 0)
        result *= number;

    return result;
}

/*** Convert float to string ***/
void float_to_string(float f, char r[])
{
    long long int length, length2, i, number, position, sign;
    float number2;

    sign = -1;   // -1 == positive number
    if (f < 0)
    {
        sign = '-';
        f *= -1;
    }

    number2 = f;
    number = f;
    length = 0;  // Size of decimal part
    length2 = 0; // Size of tenth

    /* Calculate length2 tenth part */
    while( (number2 - (float)number) != 0.0 && !((number2 - (float)number) < 0.0) )
    {
         number2 = f * (n_tu(10.0, length2 + 1));
         number = number2;

         length2++;
    }

    /* Calculate length decimal part */
    for (length = (f > 1) ? 0 : 1; f > 1; length++)
        f /= 10;

    position = length;
    length = length + 1 + length2;
    number = number2;
    if (sign == '-')
    {
        length++;
        position++;
    }

    for (i = length; i >= 0 ; i--)
    {
        if (i == (length))
            r[i] = '\0';
        else if(i == (position))
            r[i] = '.';
        else if(sign == '-' && i == 0)
            r[i] = '-';
        else
        {
            r[i] = (number % 10) + '0';
            number /=10;
        }
    }
}

Ответ 5

Используйте это:

void double_to_char(double f,char * buffer){
    gcvt(f,10,buffer);
}

Ответ 6

Посмотрите, есть ли в стандартной библиотеке BSD C fcvt(). Вы можете начать с источника для этого, а не писать свой код с нуля. Стандарт fcvt() UNIX 98, по-видимому, не выводит научную нотацию, поэтому вам придется выполнять ее самостоятельно, но я не думаю, что это будет сложно.

Ответ 7

sprintf может это сделать:

#include <stdio.h>
int main() {
  float w = 234.567;
  char x[__SIZEOF_FLOAT__];
  sprintf(x, "%g", w);
  puts(x);
}