Целью было написать независимую от локали функцию, которая печатает числа с плавающей запятой (т. Е. Такую, которая всегда использует . как десятичную точку независимо от языкового стандарта), который будет использоваться в библиотека это было предназначено для создания JSON. Я стремился к следующему:
- Простота реализации
- Возможность использования с разными типами потоков (запись в файл, строку и т. Д.)
- Разумная правильность
Вот основной код:
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
typedef int (*printfn_t)(void *, const char *, ...);
#define print(...) if (printfn(stream, __VA_ARGS__) < 0) {
return false;
}
static const int PRECISION = 15;
static int count_digits(double n) {
return floor(log10(n) + 1);
}
bool print_number(
printfn_t printfn,
void *stream,
double number
) {
if (number == 0) {
print("0");
return true;
}
if (number < 0) {
print("-");
number = -number;
}
uint64_t integral = 0, decimal = 0;
int exponent = 0;
if (number > 9007199254740991) {
exponent = count_digits(number) - 1;
number = number / pow(10, exponent);
} else if (number < 1 / pow(10, PRECISION)) {
exponent = count_digits(number) - 1;
number = number * pow(10, -exponent);
}
integral = number;
decimal = round(fmod(number, 1) * pow(10, PRECISION));
print("%" PRId64, integral);
if (decimal != 0) {
print(".");
int decimal_length = count_digits(decimal);
for (int i = 0; i < PRECISION - decimal_length; i++) {
print("0");
}
print("%" PRId64, decimal);
}
if (exponent != 0) {
print("e%i", exponent);
}
return true;
}
И вот как вы это используете:
int main() {
double input = 0;
scanf("%lf", &input);
print_number(
(printfn_t) fprintf,
stdout,
input
);
}
