diff --git a/sys/fmt/fmt.c b/sys/fmt/fmt.c index 791597b230ae2a769d13529c8133428b8108fa8f..e2cc6c3a4df46ff939b994f890d42567148075de 100644 --- a/sys/fmt/fmt.c +++ b/sys/fmt/fmt.c @@ -243,6 +243,56 @@ size_t fmt_s16_dfp(char *out, int16_t val, unsigned fp_digits) return pos; } +static const uint32_t _tenmap[] = { + 0, + 10LU, + 100LU, + 1000LU, + 10000LU, + 100000LU, + 1000000LU, + 10000000LU, +}; + +/* this is very probably not the most efficient implementation, as it at least + * pulls in floating point math. But it works, and it's always nice to have + * low hanging fruits when optimizing. (Kaspar) + */ +size_t fmt_float(char *out, float f, unsigned precision) +{ + assert (precision <= 7); + + unsigned negative = (f < 0); + uint32_t integer; + + if (negative) { + f *= -1; + } + + integer = (uint32_t) f; + f -= integer; + + uint32_t fraction = f * _tenmap[precision]; + + size_t res = negative; + if (negative && out) { + *out++ = '-'; + } + + res += fmt_u32_dec(out, integer); + if (precision && fraction) { + if (out) { + out += res; + *out++ = '.'; + size_t tmp = fmt_u32_dec(out, fraction); + fmt_lpad(out, tmp, precision, '0'); + } + res += (1 + precision); + } + + return res; +} + size_t fmt_lpad(char *out, size_t in_len, size_t pad_len, char pad_char) { if (in_len >= pad_len) { @@ -347,6 +397,13 @@ void print_u64_dec(uint64_t val) print(buf, len); } +void print_float(float f, unsigned precision) +{ + char buf[19]; + size_t len = fmt_float(buf, f, precision); + print(buf, len); +} + void print_str(const char* str) { print(str, fmt_strlen(str)); diff --git a/sys/include/fmt.h b/sys/include/fmt.h index abef5deded2fef4c17faa71282355f0a72684c5a..01f0b6678b1f077443efae8bde1f7c0d5d871433 100644 --- a/sys/include/fmt.h +++ b/sys/include/fmt.h @@ -203,6 +203,24 @@ size_t fmt_s16_dec(char *out, int16_t val); */ size_t fmt_s16_dfp(char *out, int16_t val, unsigned fp_digits); +/** + * @brief Format float to string + * + * Converts float value @p f to string + * + * @pre -2^32 < f < 2^32 + * + * @note This function is using floating point math. It pulls in about 2.4k + * bytes of code on ARM Cortex-M platforms. + * + * @param[out] out string to write to (or NULL) + * @param[in] f float value to convert + * @param[in] precision number of digits after decimal point (<=7) + * + * @returns nr of bytes the function did or would write to out + */ +size_t fmt_float(char *out, float f, unsigned precision); + /** * @brief Count characters until '\0' (exclusive) in @p str * @@ -291,9 +309,21 @@ void print_u64_hex(uint64_t val); */ void print_u64_dec(uint64_t val); +/** + * @brief Print float value + * + * @pre -2^32 < f < 2^32 + * + * @param[in] f float value to print + * @param[in] precision number of digits after decimal point (<=7) + */ +void print_float(float f, unsigned precision); + /** * @brief Print null-terminated string to stdout * + * @note See fmt_float for code size warning! + * * @param[in] str Pointer to string to print */ void print_str(const char* str);