|
1 |
| -#include <stdlib.h> |
2 |
| -#include <math.h> |
3 |
| -#include <fenv.h> |
4 |
| - |
5 | 1 | #if __ANDROID_API__ < 18
|
| 2 | +#include <math.h> |
6 | 3 | double log2(double x) {
|
7 | 4 | return log(x) * 1.442695040888963407359924681001892137L;
|
8 | 5 | }
|
9 | 6 | #endif /* __ANDROID_API__ < 18 */
|
10 |
| - |
11 |
| -#define MAX_EE 500 |
12 |
| - |
13 |
| -static inline int ee(double x) { |
14 |
| - return ((int) (log10(fabs(x)) + MAX_EE)) - MAX_EE; |
15 |
| -} |
16 |
| - |
17 |
| -#undef MAX_EE |
18 |
| - |
19 |
| -static unsigned int base_two_digits(unsigned int x) { |
20 |
| - return x ? 32 - __builtin_clz(x) : 0; |
21 |
| -} |
22 |
| - |
23 |
| -// https://stackoverflow.com/a/25934909 |
24 |
| -static int eel(int x) { |
25 |
| - static const unsigned char guess[33] = { |
26 |
| - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, |
27 |
| - 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, |
28 |
| - 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, |
29 |
| - 9, 9, 9 |
30 |
| - }; |
31 |
| - static const unsigned int ten_to_the[] = { |
32 |
| - 1, 10, 100, 1000, 10000, 100000, |
33 |
| - 1000000, 10000000, 100000000, 1000000000, |
34 |
| - }; |
35 |
| - unsigned int ux = (unsigned int) abs(x); |
36 |
| - unsigned int digits = guess[base_two_digits(ux)]; |
37 |
| - return digits + (ux >= ten_to_the[digits]) - 1; |
38 |
| -} |
39 |
| - |
40 |
| -// d * pow(10, n) |
41 |
| -static inline double multiply_pow10(double d, int n) { |
42 |
| - if (n > 0) { |
43 |
| - long long multiple = 1; |
44 |
| - while (--n >= 0) { |
45 |
| - multiple *= 10; |
46 |
| - } |
47 |
| - d *= multiple; |
48 |
| - } else if (n < 0) { |
49 |
| - long long multiple = 1; |
50 |
| - while (++n <= 0) { |
51 |
| - multiple *= 10; |
52 |
| - } |
53 |
| - d /= multiple; |
54 |
| - } |
55 |
| - return d; |
56 |
| -} |
57 |
| - |
58 |
| -static void js_e_string_zero(int sign, int n_digits, char *buf, int buf_size) { |
59 |
| - // Check length |
60 |
| - if (buf_size <= n_digits + 5 + (n_digits > 1)) { |
61 |
| - if (buf_size > 0) { |
62 |
| - buf[0] = '\0'; |
63 |
| - } |
64 |
| - return; |
65 |
| - } |
66 |
| - |
67 |
| - *buf++ = (char) (sign == 0 ? '+' : '-'); |
68 |
| - *buf++ = '0'; |
69 |
| - if (n_digits > 1) { |
70 |
| - *buf++ = (char) '.'; |
71 |
| - while (--n_digits > 0) { |
72 |
| - *buf++ = '0'; |
73 |
| - } |
74 |
| - } |
75 |
| - *buf++ = 'e'; |
76 |
| - *buf++ = '+'; |
77 |
| - *buf++ = '0'; |
78 |
| - *buf++ = '0'; |
79 |
| - *buf = '\0'; |
80 |
| -} |
81 |
| - |
82 |
| -static void js_e_string_by_hand(double d, int n_digits, char *buf, int buf_size) { |
83 |
| - if (n_digits <= 0) { |
84 |
| - n_digits = 7; |
85 |
| - } |
86 |
| - |
87 |
| - if (d == 0) { |
88 |
| - js_e_string_zero(signbit(d), n_digits, buf, buf_size); |
89 |
| - return; |
90 |
| - } |
91 |
| - |
92 |
| - int old_ee = ee(d); |
93 |
| - int new_int = (int) rint(multiply_pow10(d, n_digits - old_ee - 1)); |
94 |
| - int new_ee = eel(new_int) + 1 - n_digits + old_ee; |
95 |
| - |
96 |
| - if (new_ee > old_ee) { |
97 |
| - new_int /= 10; |
98 |
| - } |
99 |
| - |
100 |
| - char new_ee_sign = (char) (new_ee >= 0 ? '+' : '-'); |
101 |
| - int new_ee_number = abs(new_ee); |
102 |
| - |
103 |
| - if (n_digits == 1) { |
104 |
| - snprintf(buf, buf_size, "%+de%c%02d", new_int, new_ee_sign, new_ee_number); |
105 |
| - } else { |
106 |
| - snprintf(buf, buf_size, ".%+de%c%02d", new_int, new_ee_sign, new_ee_number); |
107 |
| - buf[0] = buf[1]; |
108 |
| - buf[1] = buf[2]; |
109 |
| - buf[2] = '.'; |
110 |
| - } |
111 |
| -} |
112 |
| - |
113 |
| -static void js_e_string_tonearest(double d, int n_digits, char *buf, int buf_size) { |
114 |
| - snprintf(buf, buf_size, "%+.*e", n_digits - 1, d); |
115 |
| -} |
116 |
| - |
117 |
| -void js_e_string(double d, int n_digits, int rounding_mode, char *buf, int buf_size) { |
118 |
| - if (rounding_mode == FE_TONEAREST) { |
119 |
| - js_e_string_tonearest(d, n_digits, buf, buf_size); |
120 |
| - } else { |
121 |
| - js_e_string_by_hand(d, n_digits, buf, buf_size); |
122 |
| - } |
123 |
| -} |
124 |
| - |
125 |
| -static int js_f_string_zero(int sign, int n_digits, char *buf, int buf_size) { |
126 |
| - // Check length |
127 |
| - int length = sign + 1 + (n_digits > 0) + n_digits; |
128 |
| - if (buf_size <= length) { |
129 |
| - if (buf_size > 0) { |
130 |
| - buf[0] = '\0'; |
131 |
| - } |
132 |
| - return 0; |
133 |
| - } |
134 |
| - |
135 |
| - if (sign) { |
136 |
| - *buf++ = '-'; |
137 |
| - } |
138 |
| - *buf++ = '0'; |
139 |
| - if (n_digits > 0) { |
140 |
| - *buf++ = (char) '.'; |
141 |
| - while (--n_digits >= 0) { |
142 |
| - *buf++ = '0'; |
143 |
| - } |
144 |
| - } |
145 |
| - *buf = '\0'; |
146 |
| - |
147 |
| - return length; |
148 |
| -} |
149 |
| - |
150 |
| -static int js_f_string_by_hand(double d, int n_digits, char *buf, int buf_size) { |
151 |
| - if (n_digits < 0) { |
152 |
| - n_digits = 6; |
153 |
| - } |
154 |
| - |
155 |
| - long long new_int = (long long) rint(multiply_pow10(d, n_digits)); |
156 |
| - |
157 |
| - if (new_int == 0) { |
158 |
| - return js_f_string_zero(signbit(d), n_digits, buf, buf_size); |
159 |
| - } |
160 |
| - |
161 |
| - if (n_digits == 0) { |
162 |
| - return snprintf(buf, buf_size, "%lld", new_int); |
163 |
| - } else { |
164 |
| - int n = snprintf(buf, buf_size, "%0*lld.", n_digits + (new_int < 0 ? 2 : 1), new_int); |
165 |
| - for (int i = n - 2; i > 0 && i > n - 2 - n_digits; --i) { |
166 |
| - buf[i + 1] = buf[i]; |
167 |
| - if (i == n - 1 - n_digits) { |
168 |
| - buf[i] = '.'; |
169 |
| - } |
170 |
| - } |
171 |
| - return n; |
172 |
| - } |
173 |
| -} |
174 |
| - |
175 |
| -static int js_f_string_tonearest(double d, int n_digits, char *buf, int buf_size) { |
176 |
| - return snprintf(buf, buf_size, "%.*f", n_digits, d); |
177 |
| -} |
178 |
| - |
179 |
| -int js_f_string(double d, int n_digits, int rounding_mode, char *buf, int buf_size) { |
180 |
| - if (rounding_mode == FE_TONEAREST) { |
181 |
| - return js_f_string_tonearest(d, n_digits, buf, buf_size); |
182 |
| - } else { |
183 |
| - return js_f_string_by_hand(d, n_digits, buf, buf_size); |
184 |
| - } |
185 |
| -} |
0 commit comments