- %k added

- %f rounding fixed
This commit is contained in:
Wiesner András 2024-11-05 13:22:45 +01:00
parent 7a12fe54cd
commit 6374ef283f

View File

@ -6,6 +6,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/_types.h>
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
@ -14,17 +15,31 @@
// format length ((nothing),l)
typedef enum {
LEN_NORMAL, LEN_LONG
LEN_NORMAL,
LEN_LONG
} FmtLength;
// format flags ((nothing),0)
typedef enum {
FLAG_NO = 0, FLAG_LEADING_ZEROS = 1, FLAG_LEADING_SPACES = 2, FLAG_PREPEND_PLUS_SIGN = 4
FLAG_NO = 0,
FLAG_LEADING_ZEROS = 1,
FLAG_LEADING_SPACES = 2,
FLAG_PREPEND_PLUS_SIGN = 4
} FmtFlags;
// format type
typedef enum {
UNKNOWN = -1, LITERAL_PERCENT, SIGNED_INTEGER, UNSIGNED_INTEGER, DOUBLE, DOUBLE_EXPONENTIAL, UNSIGNED_HEXADECIMAL_INT, UNSIGNED_HEXADECIMAL_INT_UPPERCASE, STRING, CHARACTER
UNKNOWN = -1,
LITERAL_PERCENT,
SIGNED_INTEGER,
UNSIGNED_INTEGER,
DOUBLE,
DOUBLE_EXPONENTIAL,
DOUBLE_TRUNCATE,
UNSIGNED_HEXADECIMAL_INT,
UNSIGNED_HEXADECIMAL_INT_UPPERCASE,
STRING,
CHARACTER
} FmtType;
struct _FmtWord;
@ -84,6 +99,21 @@ static uint64_t power(uint64_t a, unsigned long int n) {
return a;
}
static double powerf(double d, long int n) {
if (n == 0) {
return 1.0;
}
d = (n < 0) ? (1 / d) : d;
n = (n < 0) ? -n : n;
double d_orig = d;
for (unsigned long int i = 0; i < n - 1; i++) {
d *= d_orig;
}
return d;
}
// round to closest base^1 value
static uint64_t round_to_base(uint64_t a, uint64_t base) {
uint64_t mod = a % base;
@ -249,6 +279,12 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
d *= -1;
}
// round to requested precision if trucation is not instructed
if (fmt->type != DOUBLE_TRUNCATE) {
double r = 0.5 * powerf(10, -fmt->precision);
d += r;
}
// normalize if exponential form is required
int exponent = 0;
if (fmt->type == DOUBLE_EXPONENTIAL) {
@ -300,9 +336,8 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
}
// extract fractional part as integer
d_frac *= (double) power(10, fmt->precision - leading_zeros_printed + 1); // get one more digit
d_frac *= (double)power(10, fmt->precision - leading_zeros_printed);
uint64_t frac_part = (uint64_t)d_frac;
frac_part = round_to_base(frac_part, 10) / 10; // remove last zero digit (result of rounding)
// print fractional part
copy_len = print_number(frac_part, false, &frac_fmt, outbuf, free_space);
@ -353,12 +388,14 @@ static int pfn_string(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
}
// format swting assignment table
static FmtTypeDesignatorPair sTypeDesAssignment[] = {{'%', LITERAL_PERCENT, pfn_literal_percent},
static FmtTypeDesignatorPair sTypeDesAssignment[] = {
{'%', LITERAL_PERCENT, pfn_literal_percent},
{'d', SIGNED_INTEGER, pfn_integer},
{'i', SIGNED_INTEGER, pfn_integer},
{'u', UNSIGNED_INTEGER, pfn_integer},
{'f', DOUBLE, pfn_double},
{'e', DOUBLE_EXPONENTIAL, pfn_double},
{'k', DOUBLE_TRUNCATE, pfn_double},
{'x', UNSIGNED_HEXADECIMAL_INT, pfn_integer},
{'X', UNSIGNED_HEXADECIMAL_INT_UPPERCASE, pfn_integer},
{'p', UNSIGNED_HEXADECIMAL_INT, pfn_integer},