Skip to content

Commit

Permalink
Add engineering mode
Browse files Browse the repository at this point in the history
  • Loading branch information
MaJerle committed Sep 1, 2020
1 parent 488fd58 commit 9ef71fc
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 22 deletions.
29 changes: 28 additions & 1 deletion dev/VisualStudio/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,37 @@ main(void) {
lwprintf_init(lwprintf_output);

/* Float tests */
printf_run(NULL, "%e", 123.456);
printf_run(NULL, "%e", -123.456);
printf_run(NULL, "%e", 0.123456);
printf_run(NULL, "%e", -0.123456);
printf_run(NULL, "%.4e", 123.456);
printf_run(NULL, "%.4e", -123.456);
printf_run(NULL, "%.4e", 0.123456);
printf_run(NULL, "%.4e", -0.123456);
printf_run(NULL, "%.0e", 123.456);
printf_run(NULL, "%.0e", -123.456);
printf_run(NULL, "%.0e", 0.123456);
printf_run(NULL, "%.0e", -0.123456);
printf_run(NULL, "%22.4e", 123.456);
printf_run(NULL, "%22.4e", -123.456);
printf_run(NULL, "%22.4e", 0.123456);
printf_run(NULL, "%22.4e", -0.123456);
printf_run(NULL, "%022.4e", 123.456);
printf_run(NULL, "%022.4e", -123.456);
printf_run(NULL, "%022.4e", 0.123456);
printf_run(NULL, "%022.4e", -0.123456);

/* Add zeros if unused... tbd */
printf_run(NULL, "%22.33e", 123.456);
printf_run(NULL, "%22.33e", -123.456);
printf_run(NULL, "%22.33e", 0.123456);
printf_run(NULL, "%22.33e", -0.123456);
/*
for (float a = 0.0f; a < 2.0f; a += 0.01f) {
printf_run(NULL, "%10f; %10.1f; %10.0f; %+10f", 1.99f + a, 1.99f + a, 1.99f + a, 1.99 + a);
printf_run(NULL, "%10f; %10.1f; %10.0f; %+10f", -1.99f + a, -1.99f + a, -1.99f + a, -1.99 + a);
}
}*/
return 0;

additional_format_specifiers();
Expand Down
73 changes: 52 additions & 21 deletions lwprintf/src/lwprintf/lwprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ typedef struct lwprintf_int {
int precision; /*!< Selected precision */
int width; /*!< Text width indicator */
uint8_t base; /*!< Base for number format output */
char type; /*!< Format type */
} m; /*!< Block that is reset on every start of format */
} lwprintf_int_t;

Expand Down Expand Up @@ -479,14 +480,30 @@ prv_double_to_str(lwprintf_int_t* p, double num) {
#endif
double decimal_part_dbl, diff;
size_t i;
int digits_cnt;
int digits_cnt, exp_cnt;

#if LWPRINTF_CFG_SUPPORT_LONG_LONG
/* Powers of 10 from beginning up to precision level */
static const long long int powers_of_10[] = { 1E00, 1E01, 1E02, 1E03, 1E04, 1E05, 1E06, 1E07, 1E08, 1E09,
1E10, 1E11, 1E12, 1E13, 1E14, 1E15, 1E16, 1E17, 1E18};
#endif

/* Engineering mode */
if (p->m.type == 'e') {
/* Check negative status */
if (num < 0) {
p->m.flags.is_negative = 1;
num = -num;
}

/* Normalize number to be between 0 and 1 and count decimals for exponent */
if (num < 1) {
for (exp_cnt = 0; num < 1; num *= 10, --exp_cnt) {}
} else {
for (exp_cnt = 0; num >= 10; num /= 10, ++exp_cnt) {}
}
}

/* Check for corner cases */
if (num != num) {
return prv_out_str(p, p->m.flags.uc ? "NAN" : "nan", 3);
Expand All @@ -505,7 +522,8 @@ prv_double_to_str(lwprintf_int_t* p, double num) {
if (0) {
/* Go with format of xx.yyEzz instead*/
}
if (num < 0) {
/* For engineering mode, this check has been done already */
if (p->m.type != 'e' && num < 0) {
p->m.flags.is_negative = 1;
num = -num;
}
Expand Down Expand Up @@ -553,14 +571,20 @@ prv_double_to_str(lwprintf_int_t* p, double num) {
digits_cnt += p->m.precision + 1;
}

/* Engineering mode */
if (p->m.type == 'e') {
/* Format is +Exxx, so add 4 or 5 characters (max is 307, min is 00 for exponent) */
digits_cnt += 4 + (exp_cnt >= 100 || exp_cnt <= -100);
}

/* Output strings */
prv_out_str_before(p, digits_cnt);
if (integer_part == 0) {
str[0] = '0';
i = 1;
} else {
for (i = 0; integer_part > 0; integer_part /= 10, ++i) {
str[i] = (integer_part % 10) + '0';
str[i] = '0' + (char)(integer_part % 10);
}
}
/* Output integer part */
Expand All @@ -571,7 +595,7 @@ prv_double_to_str(lwprintf_int_t* p, double num) {
if (p->m.precision > 0) {
p->out_fn(p, '.');
for (i = 0; decimal_part > 0; decimal_part /= 10, ++i) {
str[i] = (decimal_part % 10) + '0';
str[i] = '0' + (decimal_part % 10);
}
for (size_t x = i; x < p->m.precision; ++x) {
p->out_fn(p, '0');
Expand All @@ -580,6 +604,21 @@ prv_double_to_str(lwprintf_int_t* p, double num) {
p->out_fn(p, str[i - 1]);
}
}

/* Engineering mode */
if (p->m.type == 'e') {
p->out_fn(p, p->m.flags.uc ? 'E' : 'e');
p->out_fn(p, exp_cnt >= 0 ? '+' : '-');
if (exp_cnt < 0) {
exp_cnt = -exp_cnt;
}
if (exp_cnt >= 100) {
p->out_fn(p, '0' + (char)(exp_cnt / 100));
exp_cnt /= 100;
}
p->out_fn(p, '0' + (char)(exp_cnt / 10));
p->out_fn(p, '0' + (char)(exp_cnt % 10));
}
prv_out_str_after(p, digits_cnt);

return 1;
Expand Down Expand Up @@ -717,9 +756,12 @@ prv_format(lwprintf_int_t* p, va_list arg) {
}

/* Check type */
switch (*fmt) {
p->m.type = *fmt;
if (*fmt >= 'A' && *fmt <= 'Z') {
p->m.flags.uc = 1;
}
switch (*fmt + ((*fmt >= 'A' && *fmt <= 'Z') ? 0x20 : 0)) {
case 'a':
case 'A':
/* Double in hexadecimal notation */
(void)va_arg(arg, double); /* Read argument to ignore it and move to next one */
prv_out_str_raw(p, "NaN", 3); /* Print string */
Expand All @@ -743,11 +785,9 @@ prv_format(lwprintf_int_t* p, va_list arg) {
break;
}
case 'b':
case 'B':
case 'o':
case 'u':
case 'x':
case 'X':
if (*fmt == 'b' || *fmt == 'B') {
p->m.base = 2;
} else if (*fmt == 'o') {
Expand All @@ -757,7 +797,6 @@ prv_format(lwprintf_int_t* p, va_list arg) {
} else if (*fmt == 'x' || *fmt == 'X') {
p->m.base = 16;
}
p->m.flags.uc = *fmt == 'X' || *fmt == 'B'; /* Select if uppercase text shall be printed */
p->m.flags.space = 0; /* Space flag has no meaning here */

/* Check for different length parameters */
Expand Down Expand Up @@ -826,19 +865,13 @@ prv_format(lwprintf_int_t* p, va_list arg) {
#endif /* LWPRINTF_CFG_SUPPORT_TYPE_POINTER */
#if LWPRINTF_CFG_SUPPORT_TYPE_FLOAT
case 'f':
case 'F':
/* Double number */
p->m.flags.uc = *fmt == 'F';
prv_double_to_str(p, (double)va_arg(arg, double));
break;
case 'e':
case 'E':
case 'g':
case 'G':
/* Double number */
p->m.flags.uc = *fmt == 'E' || *fmt == 'G';
(void)va_arg(arg, double); /* Read argument to ignore it and move to next one */
prv_out_str_raw(p, "NaN", 3); /* Print string */
case 'g': /* Not yet supported properly */
/* Double number in engineering format */
prv_double_to_str(p, (double)va_arg(arg, double));
break;
case 'n': {
int* ptr = (void*)va_arg(arg, int*);
Expand All @@ -857,8 +890,7 @@ prv_format(lwprintf_int_t* p, va_list arg) {
* char arr[] = {0, 1, 2, 3, 255};
* "%5K" would produce 00010203FF
*/
case 'k':
case 'K': {
case 'k': {
unsigned char* ptr = (void *)va_arg(arg, unsigned char *); /* Get input parameter as unsigned char pointer */
int len = p->m.width;
uint8_t is_space = p->m.flags.space == 1;
Expand All @@ -867,7 +899,6 @@ prv_format(lwprintf_int_t* p, va_list arg) {
break;
}

p->m.flags.uc = *fmt == 'K'; /* Set if uppercase */
p->m.flags.zero = 1; /* Prepend with zeros if necessary */
p->m.width = 2; /* Each number is 2 chars min/max */
p->m.base = 16; /* Hex format */
Expand Down

0 comments on commit 9ef71fc

Please sign in to comment.