py/formatfloat: Add ability to format doubles with exponents > 99.

For single prec, exponents never get larger than about 37.  For double
prec, exponents can be larger than 99 and need 3 bytes to format.  This
patch makes the number of bytes needed configurable.

Addresses issue #1772.
This commit is contained in:
Damien George 2016-01-29 11:39:12 +00:00
parent d3b1f0b627
commit 7417ccfb0d
1 changed files with 18 additions and 10 deletions

View File

@ -56,6 +56,7 @@
#define FPCONST(x) x##F #define FPCONST(x) x##F
#define FPROUND_TO_ONE 0.9999995F #define FPROUND_TO_ONE 0.9999995F
#define FPDECEXP 32 #define FPDECEXP 32
#define FPMIN_BUF_SIZE 6 // +9e+99
#define FLT_SIGN_MASK 0x80000000 #define FLT_SIGN_MASK 0x80000000
#define FLT_EXP_MASK 0x7F800000 #define FLT_EXP_MASK 0x7F800000
@ -79,6 +80,7 @@ static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u <
#define FPCONST(x) x #define FPCONST(x) x
#define FPROUND_TO_ONE 0.999999999995 #define FPROUND_TO_ONE 0.999999999995
#define FPDECEXP 256 #define FPDECEXP 256
#define FPMIN_BUF_SIZE 7 // +9e+199
#include <math.h> #include <math.h>
#define fp_signbit(x) signbit(x) #define fp_signbit(x) signbit(x)
#define fp_isspecial(x) 1 #define fp_isspecial(x) 1
@ -105,11 +107,11 @@ static const FPTYPE g_neg_pow[] = {
int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) { int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
char *s = buf; char *s = buf;
int buf_remaining = buf_size - 1;
if (buf_size < 7) { if (buf_size <= FPMIN_BUF_SIZE) {
// Smallest exp notion is -9e+99 which is 6 chars plus terminating // FPMIN_BUF_SIZE is the minimum size needed to store any FP number.
// null. // If the buffer does not have enough room for this (plus null terminator)
// then don't try to format the float.
if (buf_size >= 2) { if (buf_size >= 2) {
*s++ = '?'; *s++ = '?';
@ -127,7 +129,10 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
*s++ = sign; *s++ = sign;
} }
} }
buf_remaining -= (s - buf); // Adjust for sign
// buf_remaining contains bytes available for digits and exponent.
// It is buf_size minus room for the sign and null byte.
int buf_remaining = buf_size - 1 - (s - buf);
if (fp_isspecial(f)) { if (fp_isspecial(f)) {
char uc = fmt & 0x20; char uc = fmt & 0x20;
@ -226,8 +231,8 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
e_sign = e_sign_char; e_sign = e_sign_char;
dec = 0; dec = 0;
if (prec > (buf_remaining - 6)) { if (prec > (buf_remaining - FPMIN_BUF_SIZE)) {
prec = buf_remaining - 6; prec = buf_remaining - FPMIN_BUF_SIZE;
if (fmt == 'g') { if (fmt == 'g') {
prec++; prec++;
} }
@ -258,8 +263,8 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
} }
} }
} }
if (fmt == 'e' && prec > (buf_remaining - 6)) { if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) {
prec = buf_remaining - 6; prec = buf_remaining - FPMIN_BUF_SIZE;
} }
// If the user specified 'g' format, and e is < prec, then we'll switch // If the user specified 'g' format, and e is < prec, then we'll switch
// to the fixed format. // to the fixed format.
@ -377,7 +382,10 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
if (e_sign) { if (e_sign) {
*s++ = e_char; *s++ = e_char;
*s++ = e_sign; *s++ = e_sign;
*s++ = '0' + (e / 10); if (FPMIN_BUF_SIZE == 7 && e >= 100) {
*s++ = '0' + (e / 100);
}
*s++ = '0' + ((e / 10) % 10);
*s++ = '0' + (e % 10); *s++ = '0' + (e % 10);
} }
*s = '\0'; *s = '\0';