diff --git a/py/formatfloat.c b/py/formatfloat.c index 64f0131471143872082c6ad71018af2b38eb630c..cc06361008574af888c8dc673d7d2bd85ace0bef 100644 --- a/py/formatfloat.c +++ b/py/formatfloat.c @@ -24,10 +24,15 @@ * THE SOFTWARE. */ +#include <stdlib.h> +#include <stdint.h> +#include "py/formatfloat.h" + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT /*********************************************************************** - formatfloat.c - Ruutine for converting a single-precision floating - point number into a string. + Routine 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 @@ -39,15 +44,6 @@ ***********************************************************************/ -#include <stdlib.h> -#include <stdint.h> - -#include "py/mpconfig.h" - -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT - -#include "py/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. @@ -341,4 +337,76 @@ int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, cha return s - buf; } +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + +#include <errno.h> +#include <stdio.h> + +#ifdef _MSC_VER +// For msvc we need to address some quirks in the snprintf implementation: +// - there is no standard snprintf, it is named _snprintf instead +// - 'F' format isn't handled so use 'f' +// - nan and inf are printed as 1.#QNAN and 1.#INF +#include <math.h> +#include <string.h> + +STATIC int copy_with_sign(char *dest, size_t bufSize, const char *value, char sign) { + if (bufSize == 0) { + return 0; + } + size_t numSignChars = 0; + if (sign) { + *dest = sign; + ++numSignChars; + } + // check total length including terminator + size_t length = strlen(value) + 1 + numSignChars; + if (length > bufSize) { + length = bufSize; + } + // length without terminator + --length; + if (length > numSignChars) { + memcpy(dest + numSignChars, value, length - numSignChars); + } + dest[length] = 0; + return length; +} + +#define snprintf _snprintf +#endif + +int mp_format_float(double value, char *buf, size_t bufSize, char fmt, int prec, char sign) { + if (!buf) { + errno = EINVAL; + return -1; + } +#ifdef _MSC_VER + if (isnan(value)) { + return copy_with_sign(buf, bufSize, "nan", sign); + } else if (isinf(value)) { + return copy_with_sign(buf, bufSize, "inf", value > 0.0 ? sign : '-'); + } else { + if (fmt == 'F') { + fmt = 'f'; + } +#endif + char fmt_buf[6]; + char *fmt_s = fmt_buf; + + *fmt_s++ = '%'; + if (sign) { + *fmt_s++ = sign; + } + *fmt_s++ = '.'; + *fmt_s++ = '*'; + *fmt_s++ = fmt; + *fmt_s = '\0'; + + return snprintf(buf, bufSize, fmt_buf, prec, value); +#ifdef _MSC_VER + } +#endif +} + #endif diff --git a/py/formatfloat.h b/py/formatfloat.h index 1eb2c1e46f2751af08b401bf1f41ffb24520533e..019603447171e7302b55a6932c38c6caa49fdeed 100644 --- a/py/formatfloat.h +++ b/py/formatfloat.h @@ -26,6 +26,10 @@ #ifndef __MICROPY_INCLUDED_PY_FORMATFLOAT_H__ #define __MICROPY_INCLUDED_PY_FORMATFLOAT_H__ -int mp_format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign); +#include "py/mpconfig.h" + +#if MICROPY_PY_BUILTINS_FLOAT +int mp_format_float(mp_float_t f, char *buf, size_t bufSize, char fmt, int prec, char sign); +#endif #endif // __MICROPY_INCLUDED_PY_FORMATFLOAT_H__ diff --git a/py/mpprint.c b/py/mpprint.c index 99d0357af849f4f550451dd47966969f2917b3e7..78a0b7aa557c234cbba5e638ee7940b3728bf7e0 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -35,10 +35,6 @@ #include "py/objint.h" #include "py/runtime.h" -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE -#include <stdio.h> -#endif - #if MICROPY_PY_BUILTINS_FLOAT #include "py/formatfloat.h" #endif @@ -340,29 +336,12 @@ int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, c if (flags & PF_FLAG_SPACE_SIGN) { sign = ' '; } - int len; -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT - len = mp_format_float(f, buf, sizeof(buf), fmt, prec, sign); -#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE - char fmt_buf[6]; - char *fmt_s = fmt_buf; - *fmt_s++ = '%'; - if (sign) { - *fmt_s++ = sign; - } - *fmt_s++ = '.'; - *fmt_s++ = '*'; - *fmt_s++ = fmt; - *fmt_s = '\0'; - - len = snprintf(buf, sizeof(buf), fmt_buf, prec, f); + int len = mp_format_float(f, buf, sizeof(buf), fmt, prec, sign); if (len < 0) { len = 0; } -#else -#error Unknown MICROPY FLOAT IMPL -#endif + char *s = buf; if ((flags & PF_FLAG_ADD_PERCENT) && (size_t)(len + 1) < sizeof(buf)) { diff --git a/py/objcomplex.c b/py/objcomplex.c index 8a424f7f269bacadfa23a9d30ce3181a7448450c..b790b05638bf23a05bcbdf1533d4dfef88abc64b 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -37,10 +37,7 @@ #if MICROPY_PY_BUILTINS_COMPLEX #include <math.h> - -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #include "py/formatfloat.h" -#endif typedef struct _mp_obj_complex_t { mp_obj_base_t base; @@ -53,33 +50,23 @@ STATIC void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_ mp_obj_complex_t *o = o_in; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT char buf[16]; - if (o->real == 0) { - mp_format_float(o->imag, buf, sizeof(buf), 'g', 7, '\0'); - mp_printf(print, "%sj", buf); - } else { - mp_format_float(o->real, buf, sizeof(buf), 'g', 7, '\0'); - mp_printf(print, "(%s", buf); - if (o->imag >= 0 || isnan(o->imag)) { - mp_print_str(print, "+"); - } - mp_format_float(o->imag, buf, sizeof(buf), 'g', 7, '\0'); - mp_printf(print, "%sj)", buf); - } + const int precision = 7; #else char buf[32]; + const int precision = 16; +#endif if (o->real == 0) { - sprintf(buf, "%.16g", (double)o->imag); + mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); mp_printf(print, "%sj", buf); } else { - sprintf(buf, "%.16g", (double)o->real); + mp_format_float(o->real, buf, sizeof(buf), 'g', precision, '\0'); mp_printf(print, "(%s", buf); if (o->imag >= 0 || isnan(o->imag)) { mp_print_str(print, "+"); } - sprintf(buf, "%.16g", (double)o->imag); + mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); mp_printf(print, "%sj)", buf); } -#endif } STATIC mp_obj_t complex_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { diff --git a/py/objfloat.c b/py/objfloat.c index f74e12f9d40dfdcd7698689dbd1167ab661a1de4..ffb3c7196486d3083f735b2cf85b1c964ffb2171 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -37,31 +37,24 @@ #if MICROPY_PY_BUILTINS_FLOAT #include <math.h> - -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #include "py/formatfloat.h" -#endif STATIC void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_float_t *o = o_in; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT char buf[16]; - mp_format_float(o->value, buf, sizeof(buf), 'g', 7, '\0'); - mp_print_str(print, buf); - if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) { - // Python floats always have decimal point (unless inf or nan) - mp_print_str(print, ".0"); - } + const int precision = 7; #else char buf[32]; - sprintf(buf, "%.16g", (double) o->value); + const int precision = 16; +#endif + mp_format_float(o->value, buf, sizeof(buf), 'g', precision, '\0'); mp_print_str(print, buf); if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) { // Python floats always have decimal point (unless inf or nan) mp_print_str(print, ".0"); } -#endif } STATIC mp_obj_t float_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { diff --git a/tests/float/float1.py b/tests/float/float1.py index f670a63486f06b1f05f95060b0e98ff9831fd8ba..935375c4760c2e76ae71360520ddff5056e61254 100644 --- a/tests/float/float1.py +++ b/tests/float/float1.py @@ -13,6 +13,7 @@ print(float("1e1")) print(float("1e+1")) print(float("1e-1")) print(float("inf")) +print(float("-inf")) print(float("INF")) print(float("infinity")) print(float("INFINITY")) diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index 8b1eaacf76d7038eac9f888a0ed4116256353178..70c06d3e5fcca244553b19b2bc5f852f57c5b60e 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -198,7 +198,4 @@ void msec_sleep(double msec); #include <stddef.h> //for NULL #include <assert.h> //for assert -// Functions implemented in platform code - -int snprintf(char *dest, size_t count, const char *format, ...); #endif diff --git a/windows/msvc/snprintf.c b/windows/msvc/snprintf.c deleted file mode 100644 index d200a4cbc81a557408ba283be67e9f1acf2d3146..0000000000000000000000000000000000000000 --- a/windows/msvc/snprintf.c +++ /dev/null @@ -1,44 +0,0 @@ -/* -* This file is part of the Micro Python project, http://micropython.org/ -* -* The MIT License (MIT) -* -* Copyright (c) 2013, 2014 Damien P. George -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ - -#include <stdarg.h> -#include <stdio.h> -#include <malloc.h> - -// _snprintf/vsnprintf are fine, except the 'F' specifier is not handled -int snprintf(char *dest, size_t count, const char *format, ...) { - const size_t fmtLen = strlen(format) + 1; - char *fixedFmt = alloca(fmtLen); - for (size_t i = 0; i < fmtLen; ++i) - fixedFmt[i] = format[i] == 'F' ? 'f' : format[i]; - - va_list args; - va_start(args, format); - const int ret = vsnprintf(dest, count, fixedFmt, args); - va_end(args); - - return ret; -}