Независимая от локали функция печати с плавающей запятой

Целью было написать независимую от локали функцию, которая печатает числа с плавающей запятой (т. Е. Такую, которая всегда использует . как десятичную точку независимо от языкового стандарта), который будет использоваться в библиотека это было предназначено для создания 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
    );
}

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *