From 8bfec2b53822e2b62c4577b32e0beae398a16297 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 10 Mar 2014 13:27:02 +0000 Subject: Rename formatfloat file; remove MICROPY_ENABLE_FLOAT from mpconfigport.h. MICROPY_ENABLE_FLOAT is automatically set in mpconfig.h if MICROPY_FLOAT_IMPL is set to a non-zero value. --- py/format-float.c | 311 ----------------------------------------------------- py/format-float.h | 3 - py/formatfloat.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++ py/formatfloat.h | 1 + py/objfloat.c | 5 +- py/py.mk | 2 +- stm/mpconfigport.h | 1 - stm/printf.c | 3 +- 8 files changed, 318 insertions(+), 319 deletions(-) delete mode 100644 py/format-float.c delete mode 100644 py/format-float.h create mode 100644 py/formatfloat.c create mode 100644 py/formatfloat.h diff --git a/py/format-float.c b/py/format-float.c deleted file mode 100644 index 5411ae24f..000000000 --- a/py/format-float.c +++ /dev/null @@ -1,311 +0,0 @@ -/*********************************************************************** - - format-float.c - Ruutine for converting a single-precision floating - point number into a string. - - The code in this funcion was inspired from Fred Bayer's pdouble.c. - Since pdouble.c was released as Public Domain, I'm releasing this - code as public domain as well. - - The original code can be found in https://github.com/dhylands/format-float - - Dave Hylands - -***********************************************************************/ - -#include -#include - -#include "mpconfig.h" - -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT -#include "format-float.h" - -// 1 sign bit, 8 exponent bits, and 23 mantissa bits. -// exponent values 0 and 255 are reserved, exponent can be 1 to 254. -// exponent is stored with a bias of 127. -// The min and max floats are on the order of 1x10^37 and 1x10^-37 - -#define FLT_SIGN_MASK 0x80000000 -#define FLT_EXP_MASK 0x7F800000 -#define FLT_MAN_MASK 0x007FFFFF - -static const float g_pos_pow[] = { - 1e32, 1e16, 1e8, 1e4, 1e2, 1e1 -}; -static const float g_neg_pow[] = { - 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1 -}; - -int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char sign) { - - char *s = buf; - int buf_remaining = buf_size - 1; - - union { - float f; - uint32_t u; - } num = {f}; - - if (buf_size < 7) { - // Smallest exp notion is -9e+99 which is 6 chars plus terminating - // nulll. - - if (buf_size >= 2) { - *s++ = '?'; - } - if (buf_size >= 1) { - *s++ = '\0'; - } - return buf_size >= 2; - } - if (num.u & FLT_SIGN_MASK) { - *s++ = '-'; - num.u &= ~FLT_SIGN_MASK; - } else { - if (sign) { - *s++ = sign; - } - } - buf_remaining -= (s - buf); // Adjust for sign - - if ((num.u & FLT_EXP_MASK) == FLT_EXP_MASK) { - char uc = fmt & 0x20; - if ((num.u & FLT_MAN_MASK) == 0) { - *s++ = 'I' ^ uc; - *s++ = 'N' ^ uc; - *s++ = 'F' ^ uc; - } else { - *s++ = 'N' ^ uc; - *s++ = 'A' ^ uc; - *s++ = 'N' ^ uc; - } - *s = '\0'; - return s - buf; - } - - if (prec < 0) { - prec = 6; - } - char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt - fmt |= 0x20; // Force fmt to be lowercase - char org_fmt = fmt; - if (fmt == 'g' && prec == 0) { - prec = 1; - } - int e, e1; - int dec = 0; - char e_sign = '\0'; - int num_digits = 0; - const float *pos_pow = g_pos_pow; - const float *neg_pow = g_neg_pow; - - if (num.u == 0) { - e = 0; - if (fmt == 'e') { - e_sign = '+'; - } else if (fmt == 'f') { - num_digits = prec + 1; - } - } else if (num.u < 0x3f800000) { // f < 1.0 - // Build negative exponent - for (e = 0, e1 = 32; e1; e1 >>= 1, pos_pow++, neg_pow++) { - if (*neg_pow > num.f) { - e += e1; - num.f *= *pos_pow; - } - } - if (num.f < 1.0F && num.f >= 0.9999995F) { - num.f = 1.0F; - } else { - e++; - num.f *= 10.0F; - } - - // If the user specified 'g' format, and e is <= 4, then we'll switch - // to the fixed format ('f') - - if (fmt == 'f' || (fmt == 'g' && e <= 4)) { - fmt = 'f'; - dec = -1; - *s++ = '0'; - - if (prec + e + 1 > buf_remaining) { - prec = buf_remaining - e - 1; - } - - if (org_fmt == 'g') { - prec += (e - 1); - } - num_digits = prec; - if (num_digits) { - *s++ = '.'; - while (--e && num_digits) { - *s++ = '0'; - num_digits--; - } - } - } else { - // For e & g formats, we'll be printing the exponent, so set the - // sign. - e_sign = '-'; - dec = 0; - - if (prec > (buf_remaining - 6)) { - prec = buf_remaining - 6; - if (fmt == 'g') { - prec++; - } - } - } - } else { - // Build positive exponent - for (e = 0, e1 = 32; e1; e1 >>= 1, pos_pow++, neg_pow++) { - if (*pos_pow <= num.f) { - e += e1; - num.f *= *neg_pow; - } - } - - // If the user specified fixed format (fmt == 'f') and e makes the - // number too big to fit into the available buffer, then we'll - // switch to the 'e' format. - - if (fmt == 'f') { - if (e >= buf_remaining) { - fmt = 'e'; - } else if ((e + prec + 2) > buf_remaining) { - prec = buf_remaining - e - 2; - if (prec < 0) { - // This means no decimal point, so we can add one back - // for the decimal. - prec++; - } - } - } - if (fmt == 'e' && prec > (buf_remaining - 6)) { - prec = buf_remaining - 6; - } - // If the user specified 'g' format, and e is < prec, then we'll switch - // to the fixed format. - - if (fmt == 'g' && e < prec) { - fmt = 'f'; - prec -= (e + 1); - } - if (fmt == 'f') { - dec = e; - num_digits = prec + e + 1; - } else { - e_sign = '+'; - } - } - if (prec < 0) { - // This can happen when the prec is trimmed to prevent buffer overflow - prec = 0; - } - - // We now have num.f as a floating point number between >= 1 and < 10 - // (or equal to zero), and e contains the absolute value of the power of - // 10 exponent. and (dec + 1) == the number of dgits before the decimal. - - // For e, prec is # digits after the decimal - // For f, prec is # digits after the decimal - // For g, prec is the max number of significant digits - // - // For e & g there will be a single digit before the decimal - // for f there will be e digits before the decimal - - if (fmt == 'e') { - num_digits = prec + 1; - } else if (fmt == 'g') { - if (prec == 0) { - prec = 1; - } - num_digits = prec; - } - - // Print the digits of the mantissa - for (int i = 0; i < num_digits; ++i, --dec) { - int32_t d = num.f; - *s++ = '0' + d; - if (dec == 0 && prec > 0) { - *s++ = '.'; - } - num.f -= (float)d; - num.f *= 10.0F; - } - - // Round - if (num.f >= 5.0F) { - char *rs = s; - rs--; - while (1) { - if (*rs == '.') { - rs--; - continue; - } - if (*rs < '0' || *rs > '9') { - // + or - - rs++; // So we sit on the digit to the right of the sign - break; - } - if (*rs < '9') { - (*rs)++; - break; - } - *rs = '0'; - if (rs == buf) { - break; - } - rs--; - } - if (*rs == '0') { - // We need to insert a 1 - if (rs[1] == '.' && fmt != 'f') { - // We're going to round 9.99 to 10.00 - // Move the decimal point - rs[0] = '.'; - rs[1] = '0'; - if (e_sign == '-') { - e--; - } else { - e++; - } - } - s++; - char *ss = s; - while (ss > rs) { - *ss = ss[-1]; - ss--; - } - *rs = '1'; - } - if (num.u < 0x3f800000 && fmt == 'f') { - // We rounded up to 1.0 - prec--; - } - } - - if (org_fmt == 'g' && prec > 0) { - // Remove trailing zeros and a trailing decimal point - while (s[-1] == '0') { - s--; - } - if (s[-1] == '.') { - s--; - } - } - // Append the exponent - if (e_sign) { - *s++ = e_char; - *s++ = e_sign; - *s++ = '0' + (e / 10); - *s++ = '0' + (e % 10); - } - *s = '\0'; - - return s - buf; -} - -#endif diff --git a/py/format-float.h b/py/format-float.h deleted file mode 100644 index 590fb0e91..000000000 --- a/py/format-float.h +++ /dev/null @@ -1,3 +0,0 @@ -int format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign); - - diff --git a/py/formatfloat.c b/py/formatfloat.c new file mode 100644 index 000000000..e42266a71 --- /dev/null +++ b/py/formatfloat.c @@ -0,0 +1,311 @@ +/*********************************************************************** + + formatfloat.c - Ruutine for converting a single-precision floating + point number into a string. + + The code in this funcion was inspired from Fred Bayer's pdouble.c. + Since pdouble.c was released as Public Domain, I'm releasing this + code as public domain as well. + + The original code can be found in https://github.com/dhylands/format-float + + Dave Hylands + +***********************************************************************/ + +#include +#include + +#include "mpconfig.h" + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#include "formatfloat.h" + +// 1 sign bit, 8 exponent bits, and 23 mantissa bits. +// exponent values 0 and 255 are reserved, exponent can be 1 to 254. +// exponent is stored with a bias of 127. +// The min and max floats are on the order of 1x10^37 and 1x10^-37 + +#define FLT_SIGN_MASK 0x80000000 +#define FLT_EXP_MASK 0x7F800000 +#define FLT_MAN_MASK 0x007FFFFF + +static const float g_pos_pow[] = { + 1e32, 1e16, 1e8, 1e4, 1e2, 1e1 +}; +static const float g_neg_pow[] = { + 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1 +}; + +int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char sign) { + + char *s = buf; + int buf_remaining = buf_size - 1; + + union { + float f; + uint32_t u; + } num = {f}; + + if (buf_size < 7) { + // Smallest exp notion is -9e+99 which is 6 chars plus terminating + // nulll. + + if (buf_size >= 2) { + *s++ = '?'; + } + if (buf_size >= 1) { + *s++ = '\0'; + } + return buf_size >= 2; + } + if (num.u & FLT_SIGN_MASK) { + *s++ = '-'; + num.u &= ~FLT_SIGN_MASK; + } else { + if (sign) { + *s++ = sign; + } + } + buf_remaining -= (s - buf); // Adjust for sign + + if ((num.u & FLT_EXP_MASK) == FLT_EXP_MASK) { + char uc = fmt & 0x20; + if ((num.u & FLT_MAN_MASK) == 0) { + *s++ = 'I' ^ uc; + *s++ = 'N' ^ uc; + *s++ = 'F' ^ uc; + } else { + *s++ = 'N' ^ uc; + *s++ = 'A' ^ uc; + *s++ = 'N' ^ uc; + } + *s = '\0'; + return s - buf; + } + + if (prec < 0) { + prec = 6; + } + char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt + fmt |= 0x20; // Force fmt to be lowercase + char org_fmt = fmt; + if (fmt == 'g' && prec == 0) { + prec = 1; + } + int e, e1; + int dec = 0; + char e_sign = '\0'; + int num_digits = 0; + const float *pos_pow = g_pos_pow; + const float *neg_pow = g_neg_pow; + + if (num.u == 0) { + e = 0; + if (fmt == 'e') { + e_sign = '+'; + } else if (fmt == 'f') { + num_digits = prec + 1; + } + } else if (num.u < 0x3f800000) { // f < 1.0 + // Build negative exponent + for (e = 0, e1 = 32; e1; e1 >>= 1, pos_pow++, neg_pow++) { + if (*neg_pow > num.f) { + e += e1; + num.f *= *pos_pow; + } + } + if (num.f < 1.0F && num.f >= 0.9999995F) { + num.f = 1.0F; + } else { + e++; + num.f *= 10.0F; + } + + // If the user specified 'g' format, and e is <= 4, then we'll switch + // to the fixed format ('f') + + if (fmt == 'f' || (fmt == 'g' && e <= 4)) { + fmt = 'f'; + dec = -1; + *s++ = '0'; + + if (prec + e + 1 > buf_remaining) { + prec = buf_remaining - e - 1; + } + + if (org_fmt == 'g') { + prec += (e - 1); + } + num_digits = prec; + if (num_digits) { + *s++ = '.'; + while (--e && num_digits) { + *s++ = '0'; + num_digits--; + } + } + } else { + // For e & g formats, we'll be printing the exponent, so set the + // sign. + e_sign = '-'; + dec = 0; + + if (prec > (buf_remaining - 6)) { + prec = buf_remaining - 6; + if (fmt == 'g') { + prec++; + } + } + } + } else { + // Build positive exponent + for (e = 0, e1 = 32; e1; e1 >>= 1, pos_pow++, neg_pow++) { + if (*pos_pow <= num.f) { + e += e1; + num.f *= *neg_pow; + } + } + + // If the user specified fixed format (fmt == 'f') and e makes the + // number too big to fit into the available buffer, then we'll + // switch to the 'e' format. + + if (fmt == 'f') { + if (e >= buf_remaining) { + fmt = 'e'; + } else if ((e + prec + 2) > buf_remaining) { + prec = buf_remaining - e - 2; + if (prec < 0) { + // This means no decimal point, so we can add one back + // for the decimal. + prec++; + } + } + } + if (fmt == 'e' && prec > (buf_remaining - 6)) { + prec = buf_remaining - 6; + } + // If the user specified 'g' format, and e is < prec, then we'll switch + // to the fixed format. + + if (fmt == 'g' && e < prec) { + fmt = 'f'; + prec -= (e + 1); + } + if (fmt == 'f') { + dec = e; + num_digits = prec + e + 1; + } else { + e_sign = '+'; + } + } + if (prec < 0) { + // This can happen when the prec is trimmed to prevent buffer overflow + prec = 0; + } + + // We now have num.f as a floating point number between >= 1 and < 10 + // (or equal to zero), and e contains the absolute value of the power of + // 10 exponent. and (dec + 1) == the number of dgits before the decimal. + + // For e, prec is # digits after the decimal + // For f, prec is # digits after the decimal + // For g, prec is the max number of significant digits + // + // For e & g there will be a single digit before the decimal + // for f there will be e digits before the decimal + + if (fmt == 'e') { + num_digits = prec + 1; + } else if (fmt == 'g') { + if (prec == 0) { + prec = 1; + } + num_digits = prec; + } + + // Print the digits of the mantissa + for (int i = 0; i < num_digits; ++i, --dec) { + int32_t d = num.f; + *s++ = '0' + d; + if (dec == 0 && prec > 0) { + *s++ = '.'; + } + num.f -= (float)d; + num.f *= 10.0F; + } + + // Round + if (num.f >= 5.0F) { + char *rs = s; + rs--; + while (1) { + if (*rs == '.') { + rs--; + continue; + } + if (*rs < '0' || *rs > '9') { + // + or - + rs++; // So we sit on the digit to the right of the sign + break; + } + if (*rs < '9') { + (*rs)++; + break; + } + *rs = '0'; + if (rs == buf) { + break; + } + rs--; + } + if (*rs == '0') { + // We need to insert a 1 + if (rs[1] == '.' && fmt != 'f') { + // We're going to round 9.99 to 10.00 + // Move the decimal point + rs[0] = '.'; + rs[1] = '0'; + if (e_sign == '-') { + e--; + } else { + e++; + } + } + s++; + char *ss = s; + while (ss > rs) { + *ss = ss[-1]; + ss--; + } + *rs = '1'; + } + if (num.u < 0x3f800000 && fmt == 'f') { + // We rounded up to 1.0 + prec--; + } + } + + if (org_fmt == 'g' && prec > 0) { + // Remove trailing zeros and a trailing decimal point + while (s[-1] == '0') { + s--; + } + if (s[-1] == '.') { + s--; + } + } + // Append the exponent + if (e_sign) { + *s++ = e_char; + *s++ = e_sign; + *s++ = '0' + (e / 10); + *s++ = '0' + (e % 10); + } + *s = '\0'; + + return s - buf; +} + +#endif diff --git a/py/formatfloat.h b/py/formatfloat.h new file mode 100644 index 000000000..4c2c30e53 --- /dev/null +++ b/py/formatfloat.h @@ -0,0 +1 @@ +int format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign); diff --git a/py/objfloat.c b/py/objfloat.c index 5b953f05e..91d669ad5 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -12,8 +12,9 @@ #include "runtime0.h" #if MICROPY_ENABLE_FLOAT + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT -#include "format-float.h" +#include "formatfloat.h" #endif mp_obj_t mp_obj_new_float(mp_float_t value); @@ -120,4 +121,4 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) { return mp_obj_new_float(lhs_val); } -#endif +#endif // MICROPY_ENABLE_FLOAT diff --git a/py/py.mk b/py/py.mk index 4fd295f8e..081417681 100644 --- a/py/py.mk +++ b/py/py.mk @@ -32,7 +32,7 @@ PY_O_BASENAME = \ asmthumb.o \ emitnthumb.o \ emitinlinethumb.o \ - format-float.o \ + formatfloat.o \ parsenumbase.o \ parsenum.o \ runtime.o \ diff --git a/stm/mpconfigport.h b/stm/mpconfigport.h index 57c92181b..3f48c43f0 100644 --- a/stm/mpconfigport.h +++ b/stm/mpconfigport.h @@ -7,7 +7,6 @@ #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_REPL_HELPERS (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) -#define MICROPY_ENABLE_FLOAT (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_PATH_MAX (128) /* Enable FatFS LFNs diff --git a/stm/printf.c b/stm/printf.c index 56a5d864c..446b3182f 100644 --- a/stm/printf.c +++ b/stm/printf.c @@ -11,8 +11,9 @@ #include "lcd.h" #include "usart.h" #include "usb.h" + #if MICROPY_ENABLE_FLOAT -#include "format-float.h" +#include "formatfloat.h" #endif #define PF_FLAG_LEFT_ADJUST (0x01) -- cgit v1.2.3