internal number printing now has 7 digits fractional resolution; fixes #2573
Costa Tsaousis (ktsaou) committed
Aug 9, 2017 at 17:38 UTC
ef8994dc69e34b7c6ac60b2c324d8b400e527899
5 files changed
+99
-18
src/storage_number.c
+65
-11
@@ -2,12 +2,13 @@
2
3
extern char *print_number_lu_r(char *str, unsigned long uvalue);
4
extern char *print_number_llu_r(char *str, unsigned long long uvalue);
5
+extern char *print_number_llu_r_smart(char *str, unsigned long long uvalue);
6
7
storage_number pack_storage_number(calculated_number value, uint32_t flags)
8
{
9
// bit 32 = sign 0:positive, 1:negative
10
// bit 31 = 0:divide, 1:multiply
10
- // bit 30, 29, 28 = (multiplier or divider) 0-6 (7 total)
11
+ // bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total)
12
// bit 27, 26, 25 flags
13
// bit 24 to bit 1 = the value
14
@@ -105,6 +106,7 @@ calculated_number unpack_storage_number(storage_number value)
106
return n;
107
}
108
109
+/*
110
int print_calculated_number(char *str, calculated_number value)
111
{
112
char *wstr = str;
@@ -113,21 +115,14 @@ int print_calculated_number(char *str, calculated_number value)
115
if(sign) value = -value;
116
117
#ifdef STORAGE_WITH_MATH
116
- // without llrint() there are rounding problems
118
+ // without llrintl() there are rounding problems
119
// for example 0.9 becomes 0.89
118
- unsigned long long uvalue = (unsigned long long int) llrint(value * (calculated_number)100000);
120
+ unsigned long long uvalue = (unsigned long long int) llrintl(value * (calculated_number)100000);
121
#else
122
unsigned long long uvalue = value * (calculated_number)100000;
123
#endif
124
123
-#ifdef ENVIRONMENT32
124
- if(uvalue > (unsigned long long)0xffffffff)
125
- wstr = print_number_llu_r(str, uvalue);
126
- else
127
- wstr = print_number_lu_r(str, uvalue);
128
-#else
129
- do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
130
-#endif
125
+ wstr = print_number_llu_r_smart(str, uvalue);
126
127
// make sure we have 6 bytes at least
128
while((wstr - str) < 6) *wstr++ = '0';
@@ -166,3 +161,62 @@ int print_calculated_number(char *str, calculated_number value)
161
// return the buffer length
162
return (int) ((wstr - str) + 2 + decimal );
163
}
164
+*/
165
+
166
+int print_calculated_number(char *str, calculated_number value) {
167
+ char integral_str[50], fractional_str[50];
168
+
169
+ char *wstr = str;
170
+
171
+ if(unlikely(value < 0)) {
172
+ *wstr++ = '-';
173
+ value = -value;
174
+ }
175
+
176
+ calculated_number integral, fractional;
177
+
178
+#ifdef STORAGE_WITH_MATH
179
+ fractional = modfl(value, &integral) * 10000000.0;
180
+#else
181
+ fractional = ((unsigned long long)(value * 10000000ULL) % 10000000ULL);
182
+#endif
183
+
184
+ char *istre;
185
+ if(integral == 0.0) {
186
+ integral_str[0] = '0';
187
+ istre = &integral_str[1];
188
+ }
189
+ else
190
+ // convert the integral part to string (reversed)
191
+ istre = print_number_llu_r_smart(integral_str, (unsigned long long)integral);
192
+
193
+ // copy reversed the integral string
194
+ istre--;
195
+ while( istre >= integral_str ) *wstr++ = *istre--;
196
+
197
+ if(fractional != 0.0) {
198
+ // add a dot
199
+ *wstr++ = '.';
200
+
201
+ // convert the fractional part to string (reversed)
202
+ char *fstre = print_number_llu_r_smart(fractional_str, (unsigned long long)llrintl(fractional));
203
+
204
+ // prepend zeros to reach 7 digits length
205
+ int decimal = 7;
206
+ int len = (int)(fstre - fractional_str);
207
+ while(len < decimal) {
208
+ *wstr++ = '0';
209
+ len++;
210
+ }
211
+
212
+ char *begin = fractional_str;
213
+ while(*begin == '0' && begin < fstre) begin++;
214
+
215
+ // copy reversed the fractional string
216
+ fstre--;
217
+ while( fstre >= begin ) *wstr++ = *fstre--;
218
+ }
219
+
220
+ *wstr = '\0';
221
+ return (int)(wstr - str);
222
+}
src/storage_number.h
+2
-2
@@ -41,8 +41,8 @@ calculated_number unpack_storage_number(storage_number value);
41
int print_calculated_number(char *str, calculated_number value);
42
43
#define STORAGE_NUMBER_POSITIVE_MAX 167772150000000.0
44
-#define STORAGE_NUMBER_POSITIVE_MIN 0.00001
45
-#define STORAGE_NUMBER_NEGATIVE_MAX -0.00001
44
+#define STORAGE_NUMBER_POSITIVE_MIN 0.0000001
45
+#define STORAGE_NUMBER_NEGATIVE_MAX -0.0000001
46
#define STORAGE_NUMBER_NEGATIVE_MIN -167772150000000.0
47
48
// accepted accuracy loss
src/unit_test.c
+18
-5
@@ -31,8 +31,8 @@ int check_storage_number(calculated_number n, int debug) {
31
CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n",
32
n,
33
d, s, ddiff, dcdiff,
34
- buffer,
35
- len, p, pdiff, pcdiff
34
+ buffer, len,
35
+ p, pdiff, pcdiff
36
);
37
if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %zu but it has %zu\n", buffer, len, strlen(buffer));
38
if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, dcdiff);
@@ -45,6 +45,19 @@ int check_storage_number(calculated_number n, int debug) {
45
return 0;
46
}
47
48
+calculated_number storage_number_min(calculated_number n) {
49
+ calculated_number r = 1, last;
50
+
51
+ do {
52
+ last = n;
53
+ n /= 2.0;
54
+ storage_number t = pack_storage_number(n, SN_EXISTS);
55
+ r = unpack_storage_number(t);
56
+ } while(r != 0.0 && r != last);
57
+
58
+ return last;
59
+}
60
+
61
void benchmark_storage_number(int loop, int multiplier) {
62
int i, j;
63
calculated_number n, d;
@@ -73,10 +86,10 @@ void benchmark_storage_number(int loop, int multiplier) {
86
}
87
88
fprintf(stderr, "\nNETDATA FLOATING POINT\n");
76
- fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MIN);
89
+ fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", storage_number_min(1));
90
fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX);
91
fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN);
79
- fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MAX);
92
+ fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", -storage_number_min(1));
93
fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS);
94
95
// ------------------------------------------------------------------------
@@ -231,7 +244,7 @@ int unit_test_storage()
244
245
int unit_test_str2ld() {
246
char *values[] = {
234
- "1.234567", "-35.6", "0.00123", "23842384234234.2", ".1", "1.2e-10",
247
+ "1.2345678", "-35.6", "0.00123", "23842384234234.2", ".1", "1.2e-10",
248
"hello", "1wrong", "nan", "inf", NULL
249
};
250
src/web_buffer.c
+13
@@ -84,6 +84,19 @@ inline char *print_number_llu_r(char *str, unsigned long long uvalue) {
84
return wstr;
85
}
86
87
+inline char *print_number_llu_r_smart(char *str, unsigned long long uvalue) {
88
+#ifdef ENVIRONMENT32
89
+ if(uvalue > (unsigned long long)0xffffffff)
90
+ str = print_number_llu_r(str, uvalue);
91
+ else
92
+ str = print_number_lu_r(str, uvalue);
93
+#else
94
+ do *str++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
95
+#endif
96
+
97
+ return str;
98
+}
99
+
100
void buffer_print_llu(BUFFER *wb, unsigned long long uvalue)
101
{
102
buffer_need_bytes(wb, 50);
src/web_buffer.h
+1
@@ -71,6 +71,7 @@ extern void buffer_char_replace(BUFFER *wb, char from, char to);
71
72
extern char *print_number_lu_r(char *str, unsigned long uvalue);
73
extern char *print_number_llu_r(char *str, unsigned long long uvalue);
74
+extern char *print_number_llu_r_smart(char *str, unsigned long long uvalue);
75
76
extern void buffer_print_llu(BUFFER *wb, unsigned long long uvalue);
77