2424 * THE SOFTWARE.
2525 */
2626
27+ #include "py/mpconfig.h"
28+ #if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE
29+
2730#include <stdlib.h>
2831#include <stdint.h>
2932#include "py/formatfloat.h"
3033
31- #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
3234/***********************************************************************
3335
34- Routine for converting a single-precision floating
36+ Routine for converting a arbitrary floating
3537 point number into a string.
3638
3739 The code in this funcion was inspired from Fred Bayer's pdouble.c.
4446
4547***********************************************************************/
4648
49+ #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
4750// 1 sign bit, 8 exponent bits, and 23 mantissa bits.
4851// exponent values 0 and 255 are reserved, exponent can be 1 to 254.
4952// exponent is stored with a bias of 127.
5053// The min and max floats are on the order of 1x10^37 and 1x10^-37
5154
55+ #define FPTYPE float
56+ #define FPCONST (x ) x##F
57+ #define FPROUND_TO_ONE 0.9999995F
58+ #define FPDECEXP 32
59+
5260#define FLT_SIGN_MASK 0x80000000
5361#define FLT_EXP_MASK 0x7F800000
5462#define FLT_MAN_MASK 0x007FFFFF
5563
56- static const float g_pos_pow [] = {
64+ union floatbits {
65+ float f ;
66+ uint32_t u ;
67+ };
68+ static inline int fp_signbit (float x ) { union floatbits fb = {x }; return fb .u & FLT_SIGN_MASK ; }
69+ static inline int fp_isspecial (float x ) { union floatbits fb = {x }; return (fb .u & FLT_EXP_MASK ) == FLT_EXP_MASK ; }
70+ static inline int fp_isinf (float x ) { union floatbits fb = {x }; return (fb .u & FLT_MAN_MASK ) == 0 ; }
71+ static inline int fp_iszero (float x ) { union floatbits fb = {x }; return fb .u == 0 ; }
72+ static inline int fp_isless1 (float x ) { union floatbits fb = {x }; return fb .u < 0x3f800000 ; }
73+ // Assumes both fp_isspecial() and fp_isinf() were applied before
74+ #define fp_isnan (x ) 1
75+
76+ #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
77+
78+ #define FPTYPE double
79+ #define FPCONST (x ) x
80+ #define FPROUND_TO_ONE 0.999999999995
81+ #define FPDECEXP 256
82+ #include <math.h>
83+ #define fp_signbit (x ) signbit(x)
84+ #define fp_isspecial (x ) 1
85+ #define fp_isnan (x ) isnan(x)
86+ #define fp_isinf (x ) isinf(x)
87+ #define fp_iszero (x ) (x == 0)
88+ #define fp_isless1 (x ) (x < 1.0)
89+
90+ #endif
91+
92+ static const FPTYPE g_pos_pow [] = {
93+ #if FPDECEXP > 32
94+ 1e256 , 1e128 , 1e64 ,
95+ #endif
5796 1e32 , 1e16 , 1e8 , 1e4 , 1e2 , 1e1
5897};
59- static const float g_neg_pow [] = {
98+ static const FPTYPE g_neg_pow [] = {
99+ #if FPDECEXP > 32
100+ 1e-256 , 1e-128 , 1e-64 ,
101+ #endif
60102 1e-32 , 1e-16 , 1e-8 , 1e-4 , 1e-2 , 1e-1
61103};
62104
63- int mp_format_float (float f , char * buf , size_t buf_size , char fmt , int prec , char sign ) {
105+ int mp_format_float (FPTYPE f , char * buf , size_t buf_size , char fmt , int prec , char sign ) {
64106
65107 char * s = buf ;
66108 int buf_remaining = buf_size - 1 ;
67109
68- union {
69- float f ;
70- uint32_t u ;
71- } num = {f };
72-
73110 if (buf_size < 7 ) {
74111 // Smallest exp notion is -9e+99 which is 6 chars plus terminating
75112 // null.
@@ -82,29 +119,31 @@ int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, cha
82119 }
83120 return buf_size >= 2 ;
84121 }
85- if (num . u & FLT_SIGN_MASK ) {
122+ if (fp_signbit ( f ) ) {
86123 * s ++ = '-' ;
87- num . u &= ~ FLT_SIGN_MASK ;
124+ f = - f ;
88125 } else {
89126 if (sign ) {
90127 * s ++ = sign ;
91128 }
92129 }
93130 buf_remaining -= (s - buf ); // Adjust for sign
94131
95- if (( num . u & FLT_EXP_MASK ) == FLT_EXP_MASK ) {
132+ if (fp_isspecial ( f ) ) {
96133 char uc = fmt & 0x20 ;
97- if (( num . u & FLT_MAN_MASK ) == 0 ) {
134+ if (fp_isinf ( f ) ) {
98135 * s ++ = 'I' ^ uc ;
99136 * s ++ = 'N' ^ uc ;
100137 * s ++ = 'F' ^ uc ;
101- } else {
138+ goto ret ;
139+ } else if (fp_isnan (f )) {
102140 * s ++ = 'N' ^ uc ;
103141 * s ++ = 'A' ^ uc ;
104142 * s ++ = 'N' ^ uc ;
143+ ret :
144+ * s = '\0' ;
145+ return s - buf ;
105146 }
106- * s = '\0' ;
107- return s - buf ;
108147 }
109148
110149 if (prec < 0 ) {
@@ -120,28 +159,28 @@ int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, cha
120159 int dec = 0 ;
121160 char e_sign = '\0' ;
122161 int num_digits = 0 ;
123- const float * pos_pow = g_pos_pow ;
124- const float * neg_pow = g_neg_pow ;
162+ const FPTYPE * pos_pow = g_pos_pow ;
163+ const FPTYPE * neg_pow = g_neg_pow ;
125164
126- if (num . u == 0 ) {
165+ if (fp_iszero ( f ) ) {
127166 e = 0 ;
128167 if (fmt == 'e' ) {
129168 e_sign = '+' ;
130169 } else if (fmt == 'f' ) {
131170 num_digits = prec + 1 ;
132171 }
133- } else if (num . u < 0x3f800000 ) { // f < 1.0
172+ } else if (fp_isless1 ( f )) {
134173 // Build negative exponent
135- for (e = 0 , e1 = 32 ; e1 ; e1 >>= 1 , pos_pow ++ , neg_pow ++ ) {
136- if (* neg_pow > num . f ) {
174+ for (e = 0 , e1 = FPDECEXP ; e1 ; e1 >>= 1 , pos_pow ++ , neg_pow ++ ) {
175+ if (* neg_pow > f ) {
137176 e += e1 ;
138- num . f *= * pos_pow ;
177+ f *= * pos_pow ;
139178 }
140179 }
141180 char first_dig = '0' ;
142181 char e_sign_char = '-' ;
143- if (num . f < 1.0F && num . f >= 0.9999995F ) {
144- num . f = 1.0F ;
182+ if (fp_isless1 ( f ) && f >= FPROUND_TO_ONE ) {
183+ f = FPCONST ( 1.0 ) ;
145184 if (e > 1 ) {
146185 // numbers less than 1.0 start with 0.xxx
147186 first_dig = '1' ;
@@ -151,7 +190,7 @@ int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, cha
151190 }
152191 } else {
153192 e ++ ;
154- num . f *= 10.0F ;
193+ f *= FPCONST ( 10.0 ) ;
155194 }
156195
157196 // If the user specified 'g' format, and e is <= 4, then we'll switch
@@ -192,10 +231,10 @@ int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, cha
192231 }
193232 } else {
194233 // Build positive exponent
195- for (e = 0 , e1 = 32 ; e1 ; e1 >>= 1 , pos_pow ++ , neg_pow ++ ) {
196- if (* pos_pow <= num . f ) {
234+ for (e = 0 , e1 = FPDECEXP ; e1 ; e1 >>= 1 , pos_pow ++ , neg_pow ++ ) {
235+ if (* pos_pow <= f ) {
197236 e += e1 ;
198- num . f *= * neg_pow ;
237+ f *= * neg_pow ;
199238 }
200239 }
201240
@@ -259,17 +298,17 @@ int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, cha
259298
260299 // Print the digits of the mantissa
261300 for (int i = 0 ; i < num_digits ; ++ i , -- dec ) {
262- int32_t d = num . f ;
301+ int32_t d = f ;
263302 * s ++ = '0' + d ;
264303 if (dec == 0 && prec > 0 ) {
265304 * s ++ = '.' ;
266305 }
267- num . f -= (float )d ;
268- num . f *= 10.0F ;
306+ f -= (FPTYPE )d ;
307+ f *= FPCONST ( 10.0 ) ;
269308 }
270309
271310 // Round
272- if (num . f >= 5.0F ) {
311+ if (f >= FPCONST ( 5.0 ) ) {
273312 char * rs = s ;
274313 rs -- ;
275314 while (1 ) {
@@ -313,7 +352,7 @@ int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, cha
313352 }
314353 * rs = '1' ;
315354 }
316- if (num . u < 0x3f800000 && fmt == 'f' ) {
355+ if (fp_isless1 ( f ) && fmt == 'f' ) {
317356 // We rounded up to 1.0
318357 prec -- ;
319358 }
@@ -340,76 +379,4 @@ int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, cha
340379 return s - buf ;
341380}
342381
343- #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
344-
345- #include <errno.h>
346- #include <stdio.h>
347-
348- #ifdef _MSC_VER
349- // For msvc we need to address some quirks in the snprintf implementation:
350- // - there is no standard snprintf, it is named _snprintf instead
351- // - 'F' format isn't handled so use 'f'
352- // - nan and inf are printed as 1.#QNAN and 1.#INF
353- #include <math.h>
354- #include <string.h>
355-
356- STATIC int copy_with_sign (char * dest , size_t bufSize , const char * value , char sign ) {
357- if (bufSize == 0 ) {
358- return 0 ;
359- }
360- size_t numSignChars = 0 ;
361- if (sign ) {
362- * dest = sign ;
363- ++ numSignChars ;
364- }
365- // check total length including terminator
366- size_t length = strlen (value ) + 1 + numSignChars ;
367- if (length > bufSize ) {
368- length = bufSize ;
369- }
370- // length without terminator
371- -- length ;
372- if (length > numSignChars ) {
373- memcpy (dest + numSignChars , value , length - numSignChars );
374- }
375- dest [length ] = 0 ;
376- return length ;
377- }
378-
379- #define snprintf _snprintf
380- #endif
381-
382- int mp_format_float (double value , char * buf , size_t bufSize , char fmt , int prec , char sign ) {
383- if (!buf ) {
384- errno = EINVAL ;
385- return -1 ;
386- }
387- #ifdef _MSC_VER
388- if (isnan (value )) {
389- return copy_with_sign (buf , bufSize , "nan" , sign );
390- } else if (isinf (value )) {
391- return copy_with_sign (buf , bufSize , "inf" , value > 0.0 ? sign : '-' );
392- } else {
393- if (fmt == 'F' ) {
394- fmt = 'f' ;
395- }
396- #endif
397- char fmt_buf [6 ];
398- char * fmt_s = fmt_buf ;
399-
400- * fmt_s ++ = '%' ;
401- if (sign ) {
402- * fmt_s ++ = sign ;
403- }
404- * fmt_s ++ = '.' ;
405- * fmt_s ++ = '*' ;
406- * fmt_s ++ = fmt ;
407- * fmt_s = '\0' ;
408-
409- return snprintf (buf , bufSize , fmt_buf , prec , value );
410- #ifdef _MSC_VER
411- }
412- #endif
413- }
414-
415- #endif
382+ #endif // MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE
0 commit comments