Colin Hogben / micropython

Dependents:   micropython-repl

Committer:
pythontech
Date:
Sat Apr 16 17:11:56 2016 +0000
Revision:
0:5868e8752d44
Split off library from repl

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pythontech 0:5868e8752d44 1 /*
pythontech 0:5868e8752d44 2 * This file is part of the Micro Python project, http://micropython.org/
pythontech 0:5868e8752d44 3 *
pythontech 0:5868e8752d44 4 * The MIT License (MIT)
pythontech 0:5868e8752d44 5 *
pythontech 0:5868e8752d44 6 * Copyright (c) 2013, 2014 Damien P. George
pythontech 0:5868e8752d44 7 *
pythontech 0:5868e8752d44 8 * Permission is hereby granted, free of charge, to any person obtaining a copy
pythontech 0:5868e8752d44 9 * of this software and associated documentation files (the "Software"), to deal
pythontech 0:5868e8752d44 10 * in the Software without restriction, including without limitation the rights
pythontech 0:5868e8752d44 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
pythontech 0:5868e8752d44 12 * copies of the Software, and to permit persons to whom the Software is
pythontech 0:5868e8752d44 13 * furnished to do so, subject to the following conditions:
pythontech 0:5868e8752d44 14 *
pythontech 0:5868e8752d44 15 * The above copyright notice and this permission notice shall be included in
pythontech 0:5868e8752d44 16 * all copies or substantial portions of the Software.
pythontech 0:5868e8752d44 17 *
pythontech 0:5868e8752d44 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
pythontech 0:5868e8752d44 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
pythontech 0:5868e8752d44 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
pythontech 0:5868e8752d44 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
pythontech 0:5868e8752d44 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
pythontech 0:5868e8752d44 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
pythontech 0:5868e8752d44 24 * THE SOFTWARE.
pythontech 0:5868e8752d44 25 */
pythontech 0:5868e8752d44 26
pythontech 0:5868e8752d44 27 #include "py/mpconfig.h"
pythontech 0:5868e8752d44 28 #if MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE
pythontech 0:5868e8752d44 29
pythontech 0:5868e8752d44 30 #include <assert.h>
pythontech 0:5868e8752d44 31 #include <stdlib.h>
pythontech 0:5868e8752d44 32 #include <stdint.h>
pythontech 0:5868e8752d44 33 #include "py/formatfloat.h"
pythontech 0:5868e8752d44 34
pythontech 0:5868e8752d44 35 /***********************************************************************
pythontech 0:5868e8752d44 36
pythontech 0:5868e8752d44 37 Routine for converting a arbitrary floating
pythontech 0:5868e8752d44 38 point number into a string.
pythontech 0:5868e8752d44 39
pythontech 0:5868e8752d44 40 The code in this funcion was inspired from Fred Bayer's pdouble.c.
pythontech 0:5868e8752d44 41 Since pdouble.c was released as Public Domain, I'm releasing this
pythontech 0:5868e8752d44 42 code as public domain as well.
pythontech 0:5868e8752d44 43
pythontech 0:5868e8752d44 44 The original code can be found in https://github.com/dhylands/format-float
pythontech 0:5868e8752d44 45
pythontech 0:5868e8752d44 46 Dave Hylands
pythontech 0:5868e8752d44 47
pythontech 0:5868e8752d44 48 ***********************************************************************/
pythontech 0:5868e8752d44 49
pythontech 0:5868e8752d44 50 #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
pythontech 0:5868e8752d44 51 // 1 sign bit, 8 exponent bits, and 23 mantissa bits.
pythontech 0:5868e8752d44 52 // exponent values 0 and 255 are reserved, exponent can be 1 to 254.
pythontech 0:5868e8752d44 53 // exponent is stored with a bias of 127.
pythontech 0:5868e8752d44 54 // The min and max floats are on the order of 1x10^37 and 1x10^-37
pythontech 0:5868e8752d44 55
pythontech 0:5868e8752d44 56 #define FPTYPE float
pythontech 0:5868e8752d44 57 #define FPCONST(x) x##F
pythontech 0:5868e8752d44 58 #define FPROUND_TO_ONE 0.9999995F
pythontech 0:5868e8752d44 59 #define FPDECEXP 32
pythontech 0:5868e8752d44 60 #define FPMIN_BUF_SIZE 6 // +9e+99
pythontech 0:5868e8752d44 61
pythontech 0:5868e8752d44 62 #define FLT_SIGN_MASK 0x80000000
pythontech 0:5868e8752d44 63 #define FLT_EXP_MASK 0x7F800000
pythontech 0:5868e8752d44 64 #define FLT_MAN_MASK 0x007FFFFF
pythontech 0:5868e8752d44 65
pythontech 0:5868e8752d44 66 union floatbits {
pythontech 0:5868e8752d44 67 float f;
pythontech 0:5868e8752d44 68 uint32_t u;
pythontech 0:5868e8752d44 69 };
pythontech 0:5868e8752d44 70 static inline int fp_signbit(float x) { union floatbits fb = {x}; return fb.u & FLT_SIGN_MASK; }
pythontech 0:5868e8752d44 71 static inline int fp_isspecial(float x) { union floatbits fb = {x}; return (fb.u & FLT_EXP_MASK) == FLT_EXP_MASK; }
pythontech 0:5868e8752d44 72 static inline int fp_isinf(float x) { union floatbits fb = {x}; return (fb.u & FLT_MAN_MASK) == 0; }
pythontech 0:5868e8752d44 73 static inline int fp_iszero(float x) { union floatbits fb = {x}; return fb.u == 0; }
pythontech 0:5868e8752d44 74 static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u < 0x3f800000; }
pythontech 0:5868e8752d44 75 // Assumes both fp_isspecial() and fp_isinf() were applied before
pythontech 0:5868e8752d44 76 #define fp_isnan(x) 1
pythontech 0:5868e8752d44 77
pythontech 0:5868e8752d44 78 #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
pythontech 0:5868e8752d44 79
pythontech 0:5868e8752d44 80 #define FPTYPE double
pythontech 0:5868e8752d44 81 #define FPCONST(x) x
pythontech 0:5868e8752d44 82 #define FPROUND_TO_ONE 0.999999999995
pythontech 0:5868e8752d44 83 #define FPDECEXP 256
pythontech 0:5868e8752d44 84 #define FPMIN_BUF_SIZE 7 // +9e+199
pythontech 0:5868e8752d44 85 #include <math.h>
pythontech 0:5868e8752d44 86 #define fp_signbit(x) signbit(x)
pythontech 0:5868e8752d44 87 #define fp_isspecial(x) 1
pythontech 0:5868e8752d44 88 #define fp_isnan(x) isnan(x)
pythontech 0:5868e8752d44 89 #define fp_isinf(x) isinf(x)
pythontech 0:5868e8752d44 90 #define fp_iszero(x) (x == 0)
pythontech 0:5868e8752d44 91 #define fp_isless1(x) (x < 1.0)
pythontech 0:5868e8752d44 92
pythontech 0:5868e8752d44 93 #endif
pythontech 0:5868e8752d44 94
pythontech 0:5868e8752d44 95 static const FPTYPE g_pos_pow[] = {
pythontech 0:5868e8752d44 96 #if FPDECEXP > 32
pythontech 0:5868e8752d44 97 1e256, 1e128, 1e64,
pythontech 0:5868e8752d44 98 #endif
pythontech 0:5868e8752d44 99 1e32, 1e16, 1e8, 1e4, 1e2, 1e1
pythontech 0:5868e8752d44 100 };
pythontech 0:5868e8752d44 101 static const FPTYPE g_neg_pow[] = {
pythontech 0:5868e8752d44 102 #if FPDECEXP > 32
pythontech 0:5868e8752d44 103 1e-256, 1e-128, 1e-64,
pythontech 0:5868e8752d44 104 #endif
pythontech 0:5868e8752d44 105 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1
pythontech 0:5868e8752d44 106 };
pythontech 0:5868e8752d44 107
pythontech 0:5868e8752d44 108 int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
pythontech 0:5868e8752d44 109
pythontech 0:5868e8752d44 110 char *s = buf;
pythontech 0:5868e8752d44 111
pythontech 0:5868e8752d44 112 if (buf_size <= FPMIN_BUF_SIZE) {
pythontech 0:5868e8752d44 113 // FPMIN_BUF_SIZE is the minimum size needed to store any FP number.
pythontech 0:5868e8752d44 114 // If the buffer does not have enough room for this (plus null terminator)
pythontech 0:5868e8752d44 115 // then don't try to format the float.
pythontech 0:5868e8752d44 116
pythontech 0:5868e8752d44 117 if (buf_size >= 2) {
pythontech 0:5868e8752d44 118 *s++ = '?';
pythontech 0:5868e8752d44 119 }
pythontech 0:5868e8752d44 120 if (buf_size >= 1) {
pythontech 0:5868e8752d44 121 *s++ = '\0';
pythontech 0:5868e8752d44 122 }
pythontech 0:5868e8752d44 123 return buf_size >= 2;
pythontech 0:5868e8752d44 124 }
pythontech 0:5868e8752d44 125 if (fp_signbit(f)) {
pythontech 0:5868e8752d44 126 *s++ = '-';
pythontech 0:5868e8752d44 127 f = -f;
pythontech 0:5868e8752d44 128 } else {
pythontech 0:5868e8752d44 129 if (sign) {
pythontech 0:5868e8752d44 130 *s++ = sign;
pythontech 0:5868e8752d44 131 }
pythontech 0:5868e8752d44 132 }
pythontech 0:5868e8752d44 133
pythontech 0:5868e8752d44 134 // buf_remaining contains bytes available for digits and exponent.
pythontech 0:5868e8752d44 135 // It is buf_size minus room for the sign and null byte.
pythontech 0:5868e8752d44 136 int buf_remaining = buf_size - 1 - (s - buf);
pythontech 0:5868e8752d44 137
pythontech 0:5868e8752d44 138 if (fp_isspecial(f)) {
pythontech 0:5868e8752d44 139 char uc = fmt & 0x20;
pythontech 0:5868e8752d44 140 if (fp_isinf(f)) {
pythontech 0:5868e8752d44 141 *s++ = 'I' ^ uc;
pythontech 0:5868e8752d44 142 *s++ = 'N' ^ uc;
pythontech 0:5868e8752d44 143 *s++ = 'F' ^ uc;
pythontech 0:5868e8752d44 144 goto ret;
pythontech 0:5868e8752d44 145 } else if (fp_isnan(f)) {
pythontech 0:5868e8752d44 146 *s++ = 'N' ^ uc;
pythontech 0:5868e8752d44 147 *s++ = 'A' ^ uc;
pythontech 0:5868e8752d44 148 *s++ = 'N' ^ uc;
pythontech 0:5868e8752d44 149 ret:
pythontech 0:5868e8752d44 150 *s = '\0';
pythontech 0:5868e8752d44 151 return s - buf;
pythontech 0:5868e8752d44 152 }
pythontech 0:5868e8752d44 153 }
pythontech 0:5868e8752d44 154
pythontech 0:5868e8752d44 155 if (prec < 0) {
pythontech 0:5868e8752d44 156 prec = 6;
pythontech 0:5868e8752d44 157 }
pythontech 0:5868e8752d44 158 char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt
pythontech 0:5868e8752d44 159 fmt |= 0x20; // Force fmt to be lowercase
pythontech 0:5868e8752d44 160 char org_fmt = fmt;
pythontech 0:5868e8752d44 161 if (fmt == 'g' && prec == 0) {
pythontech 0:5868e8752d44 162 prec = 1;
pythontech 0:5868e8752d44 163 }
pythontech 0:5868e8752d44 164 int e, e1;
pythontech 0:5868e8752d44 165 int dec = 0;
pythontech 0:5868e8752d44 166 char e_sign = '\0';
pythontech 0:5868e8752d44 167 int num_digits = 0;
pythontech 0:5868e8752d44 168 const FPTYPE *pos_pow = g_pos_pow;
pythontech 0:5868e8752d44 169 const FPTYPE *neg_pow = g_neg_pow;
pythontech 0:5868e8752d44 170
pythontech 0:5868e8752d44 171 if (fp_iszero(f)) {
pythontech 0:5868e8752d44 172 e = 0;
pythontech 0:5868e8752d44 173 if (fmt == 'f') {
pythontech 0:5868e8752d44 174 // Truncate precision to prevent buffer overflow
pythontech 0:5868e8752d44 175 if (prec + 2 > buf_remaining) {
pythontech 0:5868e8752d44 176 prec = buf_remaining - 2;
pythontech 0:5868e8752d44 177 }
pythontech 0:5868e8752d44 178 num_digits = prec + 1;
pythontech 0:5868e8752d44 179 } else {
pythontech 0:5868e8752d44 180 // Truncate precision to prevent buffer overflow
pythontech 0:5868e8752d44 181 if (prec + 6 > buf_remaining) {
pythontech 0:5868e8752d44 182 prec = buf_remaining - 6;
pythontech 0:5868e8752d44 183 }
pythontech 0:5868e8752d44 184 if (fmt == 'e') {
pythontech 0:5868e8752d44 185 e_sign = '+';
pythontech 0:5868e8752d44 186 }
pythontech 0:5868e8752d44 187 }
pythontech 0:5868e8752d44 188 } else if (fp_isless1(f)) {
pythontech 0:5868e8752d44 189 // We need to figure out what an integer digit will be used
pythontech 0:5868e8752d44 190 // in case 'f' is used (or we revert other format to it below).
pythontech 0:5868e8752d44 191 // As we just tested number to be <1, this is obviously 0,
pythontech 0:5868e8752d44 192 // but we can round it up to 1 below.
pythontech 0:5868e8752d44 193 char first_dig = '0';
pythontech 0:5868e8752d44 194 if (f >= FPROUND_TO_ONE) {
pythontech 0:5868e8752d44 195 first_dig = '1';
pythontech 0:5868e8752d44 196 }
pythontech 0:5868e8752d44 197
pythontech 0:5868e8752d44 198 // Build negative exponent
pythontech 0:5868e8752d44 199 for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {
pythontech 0:5868e8752d44 200 if (*neg_pow > f) {
pythontech 0:5868e8752d44 201 e += e1;
pythontech 0:5868e8752d44 202 f *= *pos_pow;
pythontech 0:5868e8752d44 203 }
pythontech 0:5868e8752d44 204 }
pythontech 0:5868e8752d44 205 char e_sign_char = '-';
pythontech 0:5868e8752d44 206 if (fp_isless1(f) && f >= FPROUND_TO_ONE) {
pythontech 0:5868e8752d44 207 f = FPCONST(1.0);
pythontech 0:5868e8752d44 208 if (e == 0) {
pythontech 0:5868e8752d44 209 e_sign_char = '+';
pythontech 0:5868e8752d44 210 }
pythontech 0:5868e8752d44 211 } else if (fp_isless1(f)) {
pythontech 0:5868e8752d44 212 e++;
pythontech 0:5868e8752d44 213 f *= FPCONST(10.0);
pythontech 0:5868e8752d44 214 }
pythontech 0:5868e8752d44 215
pythontech 0:5868e8752d44 216 // If the user specified 'g' format, and e is <= 4, then we'll switch
pythontech 0:5868e8752d44 217 // to the fixed format ('f')
pythontech 0:5868e8752d44 218
pythontech 0:5868e8752d44 219 if (fmt == 'f' || (fmt == 'g' && e <= 4)) {
pythontech 0:5868e8752d44 220 fmt = 'f';
pythontech 0:5868e8752d44 221 dec = -1;
pythontech 0:5868e8752d44 222 *s++ = first_dig;
pythontech 0:5868e8752d44 223
pythontech 0:5868e8752d44 224 if (org_fmt == 'g') {
pythontech 0:5868e8752d44 225 prec += (e - 1);
pythontech 0:5868e8752d44 226 }
pythontech 0:5868e8752d44 227
pythontech 0:5868e8752d44 228 // truncate precision to prevent buffer overflow
pythontech 0:5868e8752d44 229 if (prec + 2 > buf_remaining) {
pythontech 0:5868e8752d44 230 prec = buf_remaining - 2;
pythontech 0:5868e8752d44 231 }
pythontech 0:5868e8752d44 232
pythontech 0:5868e8752d44 233 num_digits = prec;
pythontech 0:5868e8752d44 234 if (num_digits) {
pythontech 0:5868e8752d44 235 *s++ = '.';
pythontech 0:5868e8752d44 236 while (--e && num_digits) {
pythontech 0:5868e8752d44 237 *s++ = '0';
pythontech 0:5868e8752d44 238 num_digits--;
pythontech 0:5868e8752d44 239 }
pythontech 0:5868e8752d44 240 }
pythontech 0:5868e8752d44 241 } else {
pythontech 0:5868e8752d44 242 // For e & g formats, we'll be printing the exponent, so set the
pythontech 0:5868e8752d44 243 // sign.
pythontech 0:5868e8752d44 244 e_sign = e_sign_char;
pythontech 0:5868e8752d44 245 dec = 0;
pythontech 0:5868e8752d44 246
pythontech 0:5868e8752d44 247 if (prec > (buf_remaining - FPMIN_BUF_SIZE)) {
pythontech 0:5868e8752d44 248 prec = buf_remaining - FPMIN_BUF_SIZE;
pythontech 0:5868e8752d44 249 if (fmt == 'g') {
pythontech 0:5868e8752d44 250 prec++;
pythontech 0:5868e8752d44 251 }
pythontech 0:5868e8752d44 252 }
pythontech 0:5868e8752d44 253 }
pythontech 0:5868e8752d44 254 } else {
pythontech 0:5868e8752d44 255 // Build positive exponent
pythontech 0:5868e8752d44 256 for (e = 0, e1 = FPDECEXP; e1; e1 >>= 1, pos_pow++, neg_pow++) {
pythontech 0:5868e8752d44 257 if (*pos_pow <= f) {
pythontech 0:5868e8752d44 258 e += e1;
pythontech 0:5868e8752d44 259 f *= *neg_pow;
pythontech 0:5868e8752d44 260 }
pythontech 0:5868e8752d44 261 }
pythontech 0:5868e8752d44 262
pythontech 0:5868e8752d44 263 // It can be that f was right on the edge of an entry in pos_pow needs to be reduced
pythontech 0:5868e8752d44 264 if (f >= FPCONST(10.0)) {
pythontech 0:5868e8752d44 265 e += 1;
pythontech 0:5868e8752d44 266 f *= FPCONST(0.1);
pythontech 0:5868e8752d44 267 }
pythontech 0:5868e8752d44 268
pythontech 0:5868e8752d44 269 // If the user specified fixed format (fmt == 'f') and e makes the
pythontech 0:5868e8752d44 270 // number too big to fit into the available buffer, then we'll
pythontech 0:5868e8752d44 271 // switch to the 'e' format.
pythontech 0:5868e8752d44 272
pythontech 0:5868e8752d44 273 if (fmt == 'f') {
pythontech 0:5868e8752d44 274 if (e >= buf_remaining) {
pythontech 0:5868e8752d44 275 fmt = 'e';
pythontech 0:5868e8752d44 276 } else if ((e + prec + 2) > buf_remaining) {
pythontech 0:5868e8752d44 277 prec = buf_remaining - e - 2;
pythontech 0:5868e8752d44 278 if (prec < 0) {
pythontech 0:5868e8752d44 279 // This means no decimal point, so we can add one back
pythontech 0:5868e8752d44 280 // for the decimal.
pythontech 0:5868e8752d44 281 prec++;
pythontech 0:5868e8752d44 282 }
pythontech 0:5868e8752d44 283 }
pythontech 0:5868e8752d44 284 }
pythontech 0:5868e8752d44 285 if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) {
pythontech 0:5868e8752d44 286 prec = buf_remaining - FPMIN_BUF_SIZE;
pythontech 0:5868e8752d44 287 }
pythontech 0:5868e8752d44 288 if (fmt == 'g'){
pythontech 0:5868e8752d44 289 // Truncate precision to prevent buffer overflow
pythontech 0:5868e8752d44 290 if (prec + (FPMIN_BUF_SIZE - 1) > buf_remaining) {
pythontech 0:5868e8752d44 291 prec = buf_remaining - (FPMIN_BUF_SIZE - 1);
pythontech 0:5868e8752d44 292 }
pythontech 0:5868e8752d44 293 }
pythontech 0:5868e8752d44 294 // If the user specified 'g' format, and e is < prec, then we'll switch
pythontech 0:5868e8752d44 295 // to the fixed format.
pythontech 0:5868e8752d44 296
pythontech 0:5868e8752d44 297 if (fmt == 'g' && e < prec) {
pythontech 0:5868e8752d44 298 fmt = 'f';
pythontech 0:5868e8752d44 299 prec -= (e + 1);
pythontech 0:5868e8752d44 300 }
pythontech 0:5868e8752d44 301 if (fmt == 'f') {
pythontech 0:5868e8752d44 302 dec = e;
pythontech 0:5868e8752d44 303 num_digits = prec + e + 1;
pythontech 0:5868e8752d44 304 } else {
pythontech 0:5868e8752d44 305 e_sign = '+';
pythontech 0:5868e8752d44 306 }
pythontech 0:5868e8752d44 307 }
pythontech 0:5868e8752d44 308 if (prec < 0) {
pythontech 0:5868e8752d44 309 // This can happen when the prec is trimmed to prevent buffer overflow
pythontech 0:5868e8752d44 310 prec = 0;
pythontech 0:5868e8752d44 311 }
pythontech 0:5868e8752d44 312
pythontech 0:5868e8752d44 313 // We now have num.f as a floating point number between >= 1 and < 10
pythontech 0:5868e8752d44 314 // (or equal to zero), and e contains the absolute value of the power of
pythontech 0:5868e8752d44 315 // 10 exponent. and (dec + 1) == the number of dgits before the decimal.
pythontech 0:5868e8752d44 316
pythontech 0:5868e8752d44 317 // For e, prec is # digits after the decimal
pythontech 0:5868e8752d44 318 // For f, prec is # digits after the decimal
pythontech 0:5868e8752d44 319 // For g, prec is the max number of significant digits
pythontech 0:5868e8752d44 320 //
pythontech 0:5868e8752d44 321 // For e & g there will be a single digit before the decimal
pythontech 0:5868e8752d44 322 // for f there will be e digits before the decimal
pythontech 0:5868e8752d44 323
pythontech 0:5868e8752d44 324 if (fmt == 'e') {
pythontech 0:5868e8752d44 325 num_digits = prec + 1;
pythontech 0:5868e8752d44 326 } else if (fmt == 'g') {
pythontech 0:5868e8752d44 327 if (prec == 0) {
pythontech 0:5868e8752d44 328 prec = 1;
pythontech 0:5868e8752d44 329 }
pythontech 0:5868e8752d44 330 num_digits = prec;
pythontech 0:5868e8752d44 331 }
pythontech 0:5868e8752d44 332
pythontech 0:5868e8752d44 333 // Print the digits of the mantissa
pythontech 0:5868e8752d44 334 for (int i = 0; i < num_digits; ++i, --dec) {
pythontech 0:5868e8752d44 335 int32_t d = f;
pythontech 0:5868e8752d44 336 *s++ = '0' + d;
pythontech 0:5868e8752d44 337 if (dec == 0 && prec > 0) {
pythontech 0:5868e8752d44 338 *s++ = '.';
pythontech 0:5868e8752d44 339 }
pythontech 0:5868e8752d44 340 f -= (FPTYPE)d;
pythontech 0:5868e8752d44 341 f *= FPCONST(10.0);
pythontech 0:5868e8752d44 342 }
pythontech 0:5868e8752d44 343
pythontech 0:5868e8752d44 344 // Round
pythontech 0:5868e8752d44 345 // If we print non-exponential format (i.e. 'f'), but a digit we're going
pythontech 0:5868e8752d44 346 // to round by (e) is too far away, then there's nothing to round.
pythontech 0:5868e8752d44 347 if ((org_fmt != 'f' || e <= 1) && f >= FPCONST(5.0)) {
pythontech 0:5868e8752d44 348 char *rs = s;
pythontech 0:5868e8752d44 349 rs--;
pythontech 0:5868e8752d44 350 while (1) {
pythontech 0:5868e8752d44 351 if (*rs == '.') {
pythontech 0:5868e8752d44 352 rs--;
pythontech 0:5868e8752d44 353 continue;
pythontech 0:5868e8752d44 354 }
pythontech 0:5868e8752d44 355 if (*rs < '0' || *rs > '9') {
pythontech 0:5868e8752d44 356 // + or -
pythontech 0:5868e8752d44 357 rs++; // So we sit on the digit to the right of the sign
pythontech 0:5868e8752d44 358 break;
pythontech 0:5868e8752d44 359 }
pythontech 0:5868e8752d44 360 if (*rs < '9') {
pythontech 0:5868e8752d44 361 (*rs)++;
pythontech 0:5868e8752d44 362 break;
pythontech 0:5868e8752d44 363 }
pythontech 0:5868e8752d44 364 *rs = '0';
pythontech 0:5868e8752d44 365 if (rs == buf) {
pythontech 0:5868e8752d44 366 break;
pythontech 0:5868e8752d44 367 }
pythontech 0:5868e8752d44 368 rs--;
pythontech 0:5868e8752d44 369 }
pythontech 0:5868e8752d44 370 if (*rs == '0') {
pythontech 0:5868e8752d44 371 // We need to insert a 1
pythontech 0:5868e8752d44 372 if (rs[1] == '.' && fmt != 'f') {
pythontech 0:5868e8752d44 373 // We're going to round 9.99 to 10.00
pythontech 0:5868e8752d44 374 // Move the decimal point
pythontech 0:5868e8752d44 375 rs[0] = '.';
pythontech 0:5868e8752d44 376 rs[1] = '0';
pythontech 0:5868e8752d44 377 if (e_sign == '-') {
pythontech 0:5868e8752d44 378 e--;
pythontech 0:5868e8752d44 379 } else {
pythontech 0:5868e8752d44 380 e++;
pythontech 0:5868e8752d44 381 }
pythontech 0:5868e8752d44 382 }
pythontech 0:5868e8752d44 383 s++;
pythontech 0:5868e8752d44 384 char *ss = s;
pythontech 0:5868e8752d44 385 while (ss > rs) {
pythontech 0:5868e8752d44 386 *ss = ss[-1];
pythontech 0:5868e8752d44 387 ss--;
pythontech 0:5868e8752d44 388 }
pythontech 0:5868e8752d44 389 *rs = '1';
pythontech 0:5868e8752d44 390 }
pythontech 0:5868e8752d44 391 if (fp_isless1(f) && fmt == 'f') {
pythontech 0:5868e8752d44 392 // We rounded up to 1.0
pythontech 0:5868e8752d44 393 prec--;
pythontech 0:5868e8752d44 394 }
pythontech 0:5868e8752d44 395 }
pythontech 0:5868e8752d44 396
pythontech 0:5868e8752d44 397 // verify that we did not overrun the input buffer so far
pythontech 0:5868e8752d44 398 assert((size_t)(s + 1 - buf) <= buf_size);
pythontech 0:5868e8752d44 399
pythontech 0:5868e8752d44 400 if (org_fmt == 'g' && prec > 0) {
pythontech 0:5868e8752d44 401 // Remove trailing zeros and a trailing decimal point
pythontech 0:5868e8752d44 402 while (s[-1] == '0') {
pythontech 0:5868e8752d44 403 s--;
pythontech 0:5868e8752d44 404 }
pythontech 0:5868e8752d44 405 if (s[-1] == '.') {
pythontech 0:5868e8752d44 406 s--;
pythontech 0:5868e8752d44 407 }
pythontech 0:5868e8752d44 408 }
pythontech 0:5868e8752d44 409 // Append the exponent
pythontech 0:5868e8752d44 410 if (e_sign) {
pythontech 0:5868e8752d44 411 *s++ = e_char;
pythontech 0:5868e8752d44 412 *s++ = e_sign;
pythontech 0:5868e8752d44 413 if (FPMIN_BUF_SIZE == 7 && e >= 100) {
pythontech 0:5868e8752d44 414 *s++ = '0' + (e / 100);
pythontech 0:5868e8752d44 415 }
pythontech 0:5868e8752d44 416 *s++ = '0' + ((e / 10) % 10);
pythontech 0:5868e8752d44 417 *s++ = '0' + (e % 10);
pythontech 0:5868e8752d44 418 }
pythontech 0:5868e8752d44 419 *s = '\0';
pythontech 0:5868e8752d44 420
pythontech 0:5868e8752d44 421 // verify that we did not overrun the input buffer
pythontech 0:5868e8752d44 422 assert((size_t)(s + 1 - buf) <= buf_size);
pythontech 0:5868e8752d44 423
pythontech 0:5868e8752d44 424 return s - buf;
pythontech 0:5868e8752d44 425 }
pythontech 0:5868e8752d44 426
pythontech 0:5868e8752d44 427 #endif // MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE