1 /*
2 * This file is in the Public Domain
3 *
4 * Based on code from Public Domain snprintf.c from mutt
5 * http://dev.mutt.org/hg/mutt/file/55cd4cb611d9/snprintf.c
6 * Tue Aug 08 22:49:12 2006 +0000
7 *
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include <raptor_config.h>
12 #endif
13
14 #include "raptor.h"
15 #include "raptor_internal.h"
16
17 #include <float.h>
18 #define __USE_ISOC99 1
19 #include <math.h>
20
21 #ifndef HAVE_ROUND
22 /* round (C99): round x to the nearest integer, away from zero */
23 #define round(x) (((x) < 0) ? (long)((x)-0.5) : (long)((x)+0.5))
24 #endif
25
26 #ifndef HAVE_TRUNC
27 /* trunc (C99): round x to the nearest integer, towards zero */
28 #define trunc(x) (((x) < 0) ? ceil((x)) : floor((x)))
29 #endif
30
31 /* Convert a double to xsd:decimal representation.
32 * Returned is a pointer to the first character of the number
33 * in buffer (don't free it).
34 */
35 char*
raptor_format_float(char * buffer,size_t * currlen,size_t maxlen,double fvalue,unsigned int min,unsigned int max,int flags)36 raptor_format_float(char *buffer, size_t *currlen, size_t maxlen,
37 double fvalue, unsigned int min, unsigned int max,
38 int flags)
39 {
40 /* DBL_EPSILON = 52 digits */
41 #define FRAC_MAX_LEN 52
42
43 double ufvalue;
44 double intpart;
45 double fracpart = 0;
46 double frac;
47 double frac_delta = 10;
48 double mod_10;
49 size_t exp_len;
50 size_t frac_len = 0;
51 size_t idx;
52
53 if (max < min)
54 max = min;
55
56 /* index to the last char */
57 idx = maxlen - 1;
58
59 buffer[idx--] = '\0';
60
61 ufvalue = fabs (fvalue);
62 intpart = round(ufvalue);
63
64 /* We "cheat" by converting the fractional part to integer by
65 * multiplying by a factor of 10
66 */
67
68
69 frac = (ufvalue - intpart);
70
71 for (exp_len=0; exp_len <= max; ++exp_len) {
72 frac *= 10;
73
74 mod_10 = trunc(fmod(trunc(frac), 10));
75
76 if (fabs(frac_delta - (fracpart / pow(10, exp_len))) < (DBL_EPSILON * 2.0)) {
77 break;
78 }
79
80 frac_delta = fracpart / pow(10, exp_len);
81
82 /* Only "append" (numerically) if digit is not a zero */
83 if (mod_10 > 0 && mod_10 < 10) {
84 fracpart = round(frac);
85 frac_len = exp_len;
86 }
87 }
88
89 if (frac_len < min) {
90 buffer[idx--] = '0';
91 } else {
92 /* Convert/write fractional part (right to left) */
93 do {
94 mod_10 = fmod(trunc(fracpart), 10);
95 --frac_len;
96
97 buffer[idx--] = "0123456789"[(unsigned)mod_10];
98 fracpart /= 10;
99
100 } while(fracpart > 1 && (frac_len + 1) > 0);
101 }
102
103 buffer[idx--] = '.';
104
105 /* Convert/write integer part (right to left) */
106 do {
107 buffer[idx--] = "0123456789"[(int)fmod(intpart, 10)];
108 intpart /= 10;
109 } while(round(intpart));
110
111 /* Write a sign, if requested */
112 if(fvalue < 0)
113 buffer[idx--] = '-';
114 else if(flags)
115 buffer[idx--] = '+';
116
117 *currlen = maxlen - idx - 2;
118 return buffer + idx + 1;
119 }
120