Как преобразовать float в строку без sprintf в C? - PullRequest
2 голосов
/ 27 мая 2020

Мой код принимает строковый формат и объединяет его в буфер (без sprintf, itoa et c).

У меня проблемы с преобразованием числа float в string, так как мне нужна точность не более 7 цифр без нулей в конце. а также преобразовать каждое число в переменной float в char (но в этом вопросе мне не нужна помощь).

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

            if (*format == 'f') {
                float f = *(float*)ptrs[counter];
                char str[30];
                int b, c, m, k = 7, i = 0, l = 0;
                int a = f;
                f -= a;
                while (k >= 0) {
                    l = pow(10, k);
                    m = a / l;
                    if (m > 0) {
                        break;
                    }
                    k--;
                }
                printf("%d", k);
                for (l = k + 1; l > 0; l--) {
                    b = pow(10, l - 1);
                    c = a / b;
                    str[i++] = c + 48;
                    a %= b;
                }
                str[i++] = '.';
                for (l = 0; l < 7; l++) {
                    f *= 10.0;
                    b = f;
                    str[i++] = b + 48;
                    f -= b;
                }
                for (i = 0; i < 7; i++) {
                    *buffer = str[i];
                    buffer++;
                }
                counter++;
                str[i] = '\0';

например:

ввод: float v2 =0.9372;
вывод: .937199
желаемый результат: 0.9372

ввод: float v2 =0.25000;
вывод: 1.25000
желаемый результат: 0.25

1 Ответ

3 голосов
/ 27 мая 2020

он запутан, а также иногда дает неправильный результат

В какой-то момент, учитывая базовый 2-й характер типичной с плавающей запятой, программист должен сделать выбор:

При обычном кодировании с плавающей запятой есть также выдаёт

  • Infinity

  • Not-a-number.

  • Странности вроде -0.0

А насколько переносимым сделать код?


Источники неточности

Использование OP int ограничивает float примерно до [INT_MIN ... INT_MAX]. Код не работает для float за пределами этого диапазона. Можно использовать long long, чтобы получить больший диапазон без значительного изменения кода. Еще лучше исследовать float modff(float value, float *iptr).

float f = ...;
// int a=f;
long long a=f;

Повторное использование f*=10.0 ниже с дробным значением в f вводит возможное округление (неточность) на каждой итерации.

for(l=0;l<7;l++) {
  f*=10.0;

Код не пытается округлить, учитывая, что f не может быть 0,0 после дроби, образующей for(l=0;l<7;l++) { f*=10.0; l oop. Я рассматриваю это как место для повышения точности. Эта область также сложна, поскольку округление может повлиять на многие ведущие цифры, когда они равны 9, что в конечном итоге потребует сдвига строкового буфера. В 0.93721 после этого l oop, f было около 0,74. Поскольку более 0,5, округление дало бы ответ ".9371999" -> ".9372000".

Код стремится к 7 десятичным цифрам после .. Значения в виде десятичного кода, присвоенные float соответствию от 6 до 9 значащим десятичным разрядам, включая цифры слева от .. Ожидания не должны становиться слишком завышенными.


Идея улучшения

Если количество желаемых цифр дробной части мало, выполните 1 масштабирование / округление

// ASSUME f >= 0.0, (sign handling done before here)
long long a=f;
f-=a;
int int_f = round(f*pow(10, 7));
if (int_f < 10000000) {
  later_printf_the_7_digits(int_f);
} else {
  a++;
  later_printf_the_7_digits(0);
}
...