FreeCalypso > hg > freecalypso-sw
comparison gsm-fw/sprintf/float.c @ 146:4d629b6bbcfd
gsm-fw/sprintf: %f implemented, debug output looks correct
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Thu, 14 Nov 2013 19:03:52 +0000 |
parents | |
children | 4ac657b95f52 |
comparison
equal
deleted
inserted
replaced
145:7e45ada9c365 | 146:4d629b6bbcfd |
---|---|
1 /* | |
2 * Embedded [v]sprintf() implementation by Michael Spacefalcon, | |
3 * loosely based on the 4.3BSD-Tahoe version. | |
4 * | |
5 * This module contains the floating point conversion functions. | |
6 */ | |
7 | |
8 #include <sys/types.h> | |
9 #include <ctype.h> | |
10 #include "defs.h" | |
11 | |
12 extern double modf(); | |
13 | |
14 extern u_char * _sprintf_field(u_char *op, int width, int flags, int sign, | |
15 u_char *body, int size, int dprec, int fpprec); | |
16 | |
17 #define MAX_INT_DIGITS 10 /* 2^32-1 in decimal */ | |
18 #define MAXFRACT 16 /* max sensible for 64-bit double */ | |
19 #define DEFPREC 6 | |
20 | |
21 static char * | |
22 emit_integer_portion(unsigned number, char *endp) | |
23 { | |
24 char *t = endp; | |
25 | |
26 do { | |
27 *--t = tochar(number % 10); | |
28 number /= 10; | |
29 } while (number); | |
30 return (t); | |
31 } | |
32 | |
33 static int | |
34 f_round(double fract, char *start, char *end, int sign) | |
35 { | |
36 double tmp; | |
37 | |
38 (void)modf(fract * 10, &tmp); | |
39 if (tmp > 4) | |
40 for (;; --end) { | |
41 if (*end == '.') | |
42 --end; | |
43 if (++*end <= '9') | |
44 break; | |
45 *end = '0'; | |
46 } | |
47 /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */ | |
48 else if (sign == '-') | |
49 for (;; --end) { | |
50 if (*end == '.') | |
51 --end; | |
52 if (*end != '0') | |
53 break; | |
54 if (end == start) | |
55 return(1); /* clear the -ve */ | |
56 } | |
57 return(0); | |
58 } | |
59 | |
60 u_char * | |
61 _sprintf_percent_f(u_char *op, int width, int flags, int sign, | |
62 double number, int prec) | |
63 { | |
64 char buf[MAX_INT_DIGITS + 1 + MAXFRACT]; | |
65 int extra_prec = 0; | |
66 int origsign = sign; | |
67 double fract, tmp; | |
68 char *start, *t; | |
69 | |
70 if (number < 0) { | |
71 sign = '-'; | |
72 number = -number; | |
73 } | |
74 fract = modf(number, &tmp); | |
75 if (tmp > (double) 0xFFFFFFFF) | |
76 return _sprintf_field(op, width, flags, sign, "Toobig", 6, | |
77 0, 0); | |
78 start = emit_integer_portion((unsigned) tmp, buf + MAX_INT_DIGITS); | |
79 if (prec > MAXFRACT) { | |
80 extra_prec = prec - MAXFRACT; | |
81 prec = MAXFRACT; | |
82 } else if (prec == -1) | |
83 prec = DEFPREC; | |
84 t = buf + MAX_INT_DIGITS; | |
85 /* | |
86 * if precision required or alternate flag set, add in a | |
87 * decimal point. | |
88 */ | |
89 if (prec || flags&ALT) | |
90 *t++ = '.'; | |
91 /* if requires more precision and some fraction left */ | |
92 if (fract) { | |
93 if (prec) | |
94 do { | |
95 fract = modf(fract * 10, &tmp); | |
96 *t++ = tochar((int)tmp); | |
97 } while (--prec && fract); | |
98 if (fract && f_round(fract, start, t - 1, sign)) | |
99 sign = origsign; | |
100 } | |
101 return _sprintf_field(op, width, flags, sign, start, t - start, | |
102 0, prec + extra_prec); | |
103 } |