Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016 Mikkel F. Jørgensen, dvide.com
3 : : * Copyright author of MathGeoLib (https://github.com/juj)
4 : : *
5 : : * Licensed under the Apache License, Version 2.0 (the "License");
6 : : * you may not use this file except in compliance with the License.
7 : : * You may obtain a copy of the License at
8 : : *
9 : : * http://www.apache.org/licenses/LICENSE-2.0
10 : : *
11 : : * Unless required by applicable law or agreed to in writing, software
12 : : * distributed under the License is distributed on an "AS IS" BASIS,
13 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : : * See the License for the specific language governing permissions and
15 : : * limitations under the License. http://www.apache.org/licenses/LICENSE-2.0
16 : : */
17 : :
18 : : /*
19 : : * Extracted from MathGeoLib.
20 : : *
21 : : * mikkelfj:
22 : : * - Fixed final output when printing single digit negative exponent to
23 : : * have leading zero (important for JSON).
24 : : * - Changed formatting to prefer 0.012 over 1.2-e-2.
25 : : *
26 : : * Large portions of the original grisu3.c file has been moved to
27 : : * grisu3_math.h, the rest is placed here.
28 : : *
29 : : * See also comments in grisu3_math.h.
30 : : *
31 : : * MatGeoLib grisu3.c comment:
32 : : *
33 : : * This file is part of an implementation of the "grisu3" double to string
34 : : * conversion algorithm described in the research paper
35 : : *
36 : : * "Printing Floating-Point Numbers Quickly And Accurately with Integers"
37 : : * by Florian Loitsch, available at
38 : : * http://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
39 : : */
40 : :
41 : : #ifndef GRISU3_PRINT_H
42 : : #define GRISU3_PRINT_H
43 : :
44 : : #include <stdio.h> // sprintf
45 : : #include <assert.h> // assert
46 : :
47 : : #include "grisu3_math.h"
48 : :
49 : : /*
50 : : * The lightweight "portable" C library recognizes grisu3 support if
51 : : * included first.
52 : : */
53 : : #define grisu3_print_double_is_defined 1
54 : :
55 : : /*
56 : : * Not sure we have an exact definition, but we get up to 23
57 : : * emperically. There is some math ensuring it does not go awol though,
58 : : * like 18 digits + exponent or so.
59 : : * This max should be safe size buffer for printing, including zero term.
60 : : */
61 : : #define GRISU3_PRINT_MAX 30
62 : :
63 : 4 : static int grisu3_round_weed(char *buffer, int len, uint64_t wp_W, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t ulp)
64 : : {
65 : 4 : uint64_t wp_Wup = wp_W - ulp;
66 : 4 : uint64_t wp_Wdown = wp_W + ulp;
67 [ - + ][ # # ]: 4 : while(rest < wp_Wup && delta - rest >= ten_kappa
68 [ # # ][ # # ]: 0 : && (rest + ten_kappa < wp_Wup || wp_Wup - rest >= rest + ten_kappa - wp_Wup))
69 : : {
70 : 0 : --buffer[len-1];
71 : : rest += ten_kappa;
72 : : }
73 [ + - ][ - + ]: 4 : if (rest < wp_Wdown && delta - rest >= ten_kappa
74 [ # # ][ # # ]: 0 : && (rest + ten_kappa < wp_Wdown || wp_Wdown - rest > rest + ten_kappa - wp_Wdown))
75 : : return 0;
76 : :
77 [ + - ][ - + ]: 4 : return 2*ulp <= rest && rest <= delta - 4*ulp;
78 : : }
79 : :
80 : 8 : static int grisu3_digit_gen(grisu3_diy_fp_t low, grisu3_diy_fp_t w, grisu3_diy_fp_t high, char *buffer, int *length, int *kappa)
81 : : {
82 : : uint64_t unit = 1;
83 : 4 : grisu3_diy_fp_t too_low = { low.f - unit, low.e };
84 : 4 : grisu3_diy_fp_t too_high = { high.f + unit, high.e };
85 : : grisu3_diy_fp_t unsafe_interval = grisu3_diy_fp_minus(too_high, too_low);
86 : 4 : grisu3_diy_fp_t one = { 1ULL << -w.e, w.e };
87 : 4 : uint32_t p1 = (uint32_t)(too_high.f >> -one.e);
88 : 4 : uint64_t p2 = too_high.f & (one.f - 1);
89 : : uint32_t div;
90 : 4 : *kappa = grisu3_largest_pow10(p1, GRISU3_DIY_FP_FRACT_SIZE + one.e, &div);
91 : 4 : *length = 0;
92 : :
93 [ + - ]: 4 : while(*kappa > 0)
94 : : {
95 : : uint64_t rest;
96 : 4 : int digit = p1 / div;
97 : 4 : buffer[*length] = (char)('0' + digit);
98 : 4 : ++*length;
99 : 4 : p1 %= div;
100 : 4 : --*kappa;
101 : 4 : rest = ((uint64_t)p1 << -one.e) + p2;
102 [ + - ]: 4 : if (rest < unsafe_interval.f) return grisu3_round_weed(buffer, *length, grisu3_diy_fp_minus(too_high, w).f, unsafe_interval.f, rest, (uint64_t)div << -one.e, unit);
103 : 0 : div /= 10;
104 : : }
105 : :
106 : : for(;;)
107 : : {
108 : : int digit;
109 : 0 : p2 *= 10;
110 : 0 : unit *= 10;
111 : 0 : unsafe_interval.f *= 10;
112 : : // Integer division by one.
113 : 0 : digit = (int)(p2 >> -one.e);
114 : 0 : buffer[*length] = (char)('0' + digit);
115 : 0 : ++*length;
116 : 0 : p2 &= one.f - 1; // Modulo by one.
117 : 0 : --*kappa;
118 [ # # ]: 0 : if (p2 < unsafe_interval.f) return grisu3_round_weed(buffer, *length, grisu3_diy_fp_minus(too_high, w).f * unit, unsafe_interval.f, p2, one.f, unit);
119 : : }
120 : : }
121 : :
122 : 4 : static int grisu3(double v, char *buffer, int *length, int *d_exp)
123 : : {
124 : : int mk, kappa, success;
125 : : grisu3_diy_fp_t dfp = grisu3_cast_diy_fp_from_double(v);
126 : : grisu3_diy_fp_t w = grisu3_diy_fp_normalize(dfp);
127 : :
128 : : // normalize boundaries
129 : 4 : grisu3_diy_fp_t t = { (dfp.f << 1) + 1, dfp.e - 1 };
130 : : grisu3_diy_fp_t b_plus = grisu3_diy_fp_normalize(t);
131 : : grisu3_diy_fp_t b_minus;
132 : : grisu3_diy_fp_t c_mk; // Cached power of ten: 10^-k
133 : : uint64_t u64 = grisu3_cast_uint64_from_double(v);
134 : : assert(v > 0 && v <= 1.7976931348623157e308); // Grisu only handles strictly positive finite numbers.
135 [ + + ][ + - ]: 4 : if (!(u64 & GRISU3_D64_FRACT_MASK) && (u64 & GRISU3_D64_EXP_MASK) != 0) { b_minus.f = (dfp.f << 2) - 1; b_minus.e = dfp.e - 2;} // lower boundary is closer?
136 : 2 : else { b_minus.f = (dfp.f << 1) - 1; b_minus.e = dfp.e - 1; }
137 : 4 : b_minus.f = b_minus.f << (b_minus.e - b_plus.e);
138 : : b_minus.e = b_plus.e;
139 : :
140 : : mk = grisu3_diy_fp_cached_pow(GRISU3_MIN_TARGET_EXP - GRISU3_DIY_FP_FRACT_SIZE - w.e, &c_mk);
141 : :
142 : 4 : w = grisu3_diy_fp_multiply(w, c_mk);
143 : 4 : b_minus = grisu3_diy_fp_multiply(b_minus, c_mk);
144 : 4 : b_plus = grisu3_diy_fp_multiply(b_plus, c_mk);
145 : :
146 : 4 : success = grisu3_digit_gen(b_minus, w, b_plus, buffer, length, &kappa);
147 : 4 : *d_exp = kappa - mk;
148 : 4 : return success;
149 : : }
150 : :
151 : 0 : static int grisu3_i_to_str(int val, char *str)
152 : : {
153 : : int len, i;
154 : : char *s;
155 : : char *begin = str;
156 [ # # ]: 0 : if (val < 0) { *str++ = '-'; val = -val; }
157 : : s = str;
158 : :
159 : : for(;;)
160 : : {
161 : 0 : int ni = val / 10;
162 : 0 : int digit = val - ni*10;
163 : 0 : *s++ = (char)('0' + digit);
164 [ # # ]: 0 : if (ni == 0)
165 : : break;
166 : : val = ni;
167 : : }
168 : 0 : *s = '\0';
169 : 0 : len = (int)(s - str);
170 [ # # ]: 0 : for(i = 0; i < len/2; ++i)
171 : : {
172 : 0 : char ch = str[i];
173 : 0 : str[i] = str[len-1-i];
174 : 0 : str[len-1-i] = ch;
175 : : }
176 : :
177 : 0 : return (int)(s - begin);
178 : : }
179 : :
180 : 4 : static int grisu3_print_double(double v, char *dst)
181 : : {
182 : : int d_exp, len, success, decimals, i;
183 : : uint64_t u64 = grisu3_cast_uint64_from_double(v);
184 : : char *s2 = dst;
185 : : assert(dst);
186 : :
187 : : // Prehandle NaNs
188 [ - + ]: 4 : if ((u64 << 1) > 0xFFE0000000000000ULL) return sprintf(dst, "NaN(%08X%08X)", (uint32_t)(u64 >> 32), (uint32_t)u64);
189 : : // Prehandle negative values.
190 [ - + ]: 4 : if ((u64 & GRISU3_D64_SIGN) != 0) { *s2++ = '-'; v = -v; u64 ^= GRISU3_D64_SIGN; }
191 : : // Prehandle zero.
192 [ - + ]: 4 : if (!u64) { *s2++ = '0'; *s2 = '\0'; return (int)(s2 - dst); }
193 : : // Prehandle infinity.
194 [ - + ]: 4 : if (u64 == GRISU3_D64_EXP_MASK) { *s2++ = 'i'; *s2++ = 'n'; *s2++ = 'f'; *s2 = '\0'; return (int)(s2 - dst); }
195 : :
196 : 4 : success = grisu3(v, s2, &len, &d_exp);
197 : : // If grisu3 was not able to convert the number to a string, then use old sprintf (suboptimal).
198 [ - + ]: 4 : if (!success) return sprintf(s2, "%.17g", v) + (int)(s2 - dst);
199 : :
200 : : // We now have an integer string of form "151324135" and a base-10 exponent for that number.
201 : : // Next, decide the best presentation for that string by whether to use a decimal point, or the scientific exponent notation 'e'.
202 : : // We don't pick the absolute shortest representation, but pick a balance between readability and shortness, e.g.
203 : : // 1.545056189557677e-308 could be represented in a shorter form
204 : : // 1545056189557677e-323 but that would be somewhat unreadable.
205 [ - + ]: 4 : decimals = GRISU3_MIN(-d_exp, GRISU3_MAX(1, len-1));
206 : :
207 : : // mikkelfj:
208 : : // fix zero prefix .1 => 0.1, important for JSON export.
209 : : // prefer unscientific notation at same length:
210 : : // -1.2345e-4 over -1.00012345,
211 : : // -1.0012345 over -1.2345e-3
212 [ - + ][ # # ]: 4 : if (d_exp < 0 && (len + d_exp) > -3 && len <= -d_exp)
[ # # ]
213 : : {
214 : : // mikkelfj: fix zero prefix .1 => 0.1, and short exponents 1.3e-2 => 0.013.
215 : 0 : memmove(s2 + 2 - d_exp - len, s2, len);
216 : 0 : s2[0] = '0';
217 : 0 : s2[1] = '.';
218 [ # # ]: 0 : for (i = 2; i < 2-d_exp-len; ++i) s2[i] = '0';
219 : 0 : len += i;
220 : : }
221 [ - + ][ # # ]: 4 : else if (d_exp < 0 && len > 1) // Add decimal point?
222 : : {
223 [ # # ]: 0 : for(i = 0; i < decimals; ++i) s2[len-i] = s2[len-i-1];
224 : 0 : s2[len++ - decimals] = '.';
225 : 0 : d_exp += decimals;
226 : : // Need scientific notation as well?
227 [ # # ]: 0 : if (d_exp != 0) { s2[len++] = 'e'; len += grisu3_i_to_str(d_exp, s2+len); }
228 : : }
229 : : // Add scientific notation?
230 [ - + ]: 4 : else if (d_exp < 0 || d_exp > 2) { s2[len++] = 'e'; len += grisu3_i_to_str(d_exp, s2+len); }
231 : : // Add zeroes instead of scientific notation?
232 [ - + ][ # # ]: 4 : else if (d_exp > 0) { while(d_exp-- > 0) s2[len++] = '0'; }
233 : 4 : s2[len] = '\0'; // grisu3 doesn't null terminate, so ensure termination.
234 : 4 : return (int)(s2+len-dst);
235 : : }
236 : :
237 : : #endif /* GRISU3_PRINT_H */
|