- %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) {
@ -264,7 +300,7 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
FmtWord int_fmt = {.flags = fmt->flags, .type = UNSIGNED_INTEGER, .width = fmt->width};
// separate into integer and fractional part
uint64_t int_part = (uint64_t) d; // integer part
uint64_t int_part = (uint64_t)d; // integer part
int copy_len = print_number(int_part, negative, &int_fmt, outbuf, free_space);
free_space -= copy_len;
outbuf += copy_len;
@ -285,7 +321,7 @@ static int pfn_double(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space
FmtWord frac_fmt = {.flags = FLAG_NO, .width = -1, .type = UNSIGNED_INTEGER};
// get "leading zeros" in fractional part
double d_frac = d - (double) int_part;
double d_frac = d - (double)int_part;
// print leading zeros
int leading_zeros_printed = 0;
@ -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
uint64_t frac_part = (uint64_t) d_frac;
frac_part = round_to_base(frac_part, 10) / 10; // remove last zero digit (result of rounding)
d_frac *= (double)power(10, fmt->precision - leading_zeros_printed);
uint64_t frac_part = (uint64_t)d_frac;
// print fractional part
copy_len = print_number(frac_part, false, &frac_fmt, outbuf, free_space);
@ -348,17 +383,19 @@ static int pfn_char(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space)
// print string
static int pfn_string(va_list *va, FmtWord *fmt, char *outbuf, size_t free_space) {
char *str = va_arg((*va), char*);
char *str = va_arg((*va), char *);
return string_copy(outbuf, str, 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},
@ -575,7 +612,7 @@ unsigned long int vembfmt(char *str, unsigned long int len, const char *format,
sum_copy_len += copy_len;
// print data
FmtWord word = { 0 };
FmtWord word = {0};
int rewind;
process_format_word(word_str, &word, &rewind);
if (word.type != UNKNOWN) {