summaryrefslogtreecommitdiffstats
path: root/libnetdata/storage_number
diff options
context:
space:
mode:
Diffstat (limited to 'libnetdata/storage_number')
-rw-r--r--libnetdata/storage_number/README.md2
-rw-r--r--libnetdata/storage_number/storage_number.c142
-rw-r--r--libnetdata/storage_number/storage_number.h90
3 files changed, 91 insertions, 143 deletions
diff --git a/libnetdata/storage_number/README.md b/libnetdata/storage_number/README.md
index da2c3ccfd..2dd6df6cf 100644
--- a/libnetdata/storage_number/README.md
+++ b/libnetdata/storage_number/README.md
@@ -4,7 +4,7 @@ custom_edit_url: https://github.com/netdata/netdata/edit/master/libnetdata/stora
sidebar_label: "Storage number"
learn_status: "Published"
learn_topic_type: "Tasks"
-learn_rel_path: "Developers/libnetdata libraries"
+learn_rel_path: "Developers/libnetdata"
-->
# Netdata storage number
diff --git a/libnetdata/storage_number/storage_number.c b/libnetdata/storage_number/storage_number.c
index 7511f3a79..ebae71d81 100644
--- a/libnetdata/storage_number/storage_number.c
+++ b/libnetdata/storage_number/storage_number.c
@@ -2,6 +2,78 @@
#include "../libnetdata.h"
+bool is_system_ieee754_double(void) {
+ static bool logged = false;
+
+ struct {
+ NETDATA_DOUBLE original;
+
+ union {
+ uint64_t i;
+ NETDATA_DOUBLE d;
+ };
+ } tests[] = {
+ { .original = 1.25, .i = 0x3FF4000000000000 },
+ { .original = 1.0, .i = 0x3FF0000000000000 },
+ { .original = 2.0, .i = 0x4000000000000000 },
+ { .original = 4.0, .i = 0x4010000000000000 },
+ { .original = 8.8, .i = 0x402199999999999A },
+ { .original = 16.16, .i = 0x403028F5C28F5C29 },
+ { .original = 32.32, .i = 0x404028F5C28F5C29 },
+ { .original = 64.64, .i = 0x405028F5C28F5C29 },
+ { .original = 128.128, .i = 0x406004189374BC6A },
+ { .original = 32768.32768, .i = 0x40E0000A7C5AC472 },
+ { .original = 65536.65536, .i = 0x40F0000A7C5AC472 },
+ { .original = -65536.65536, .i = 0xC0F0000A7C5AC472 },
+ { .original = 65535.65535, .i = 0x40EFFFF4F8A0902E },
+ { .original = -65535.65535, .i = 0xC0EFFFF4F8A0902E },
+ { .original = 4.503599627e15, .i = 0x432FFFFFFFF4B180 },
+ { .original = -4.503599627e15, .i = 0xC32FFFFFFFF4B180 },
+ { .original = 1.25e25, .i = 0x4524ADF4B7320335 },
+ { .original = 1.25e307, .i = 0x7FB1CCF385EBC8A0 },
+ { .original = 1.25e-25, .i = 0x3AC357C299A88EA7 },
+ { .original = 1.25e-100, .i = 0x2B317F7D4ED8C33E },
+ { .original = NAN, .i = 0x7FF8000000000000 },
+ { .original = -INFINITY, .i = 0xFFF0000000000000 },
+ { .original = INFINITY, .i = 0x7FF0000000000000 },
+ { .original = 1.25e-132, .i = 0x248C6463225AB7EC },
+ { .original = 0.0, .i = 0x0000000000000000 },
+ { .original = -0.0, .i = 0x8000000000000000 },
+ { .original = DBL_MIN, .i = 0x0010000000000000 },
+ { .original = DBL_MAX, .i = 0x7FEFFFFFFFFFFFFF },
+ { .original = -DBL_MIN, .i = 0x8010000000000000 },
+ { .original = -DBL_MAX, .i = 0xFFEFFFFFFFFFFFFF },
+ };
+
+ size_t errors = 0;
+ size_t elements = sizeof(tests) / sizeof(tests[0]);
+ for(size_t i = 0; i < elements ; i++) {
+ uint64_t *ptr = (uint64_t *)&tests[i].original;
+
+ if(*ptr != tests[i].i && (tests[i].original == tests[i].d || (isnan(tests[i].original) && isnan(tests[i].d)))) {
+ if(!logged)
+ info("IEEE754: test #%zu, value " NETDATA_DOUBLE_FORMAT_G " is represented in this system as %lX, but it was expected as %lX",
+ i+1, tests[i].original, *ptr, tests[i].i);
+ errors++;
+ }
+ }
+
+ if(!errors && sizeof(NETDATA_DOUBLE) == sizeof(uint64_t)) {
+ if(!logged)
+ info("IEEE754: system is using IEEE754 DOUBLE PRECISION values");
+
+ logged = true;
+ return true;
+ }
+ else {
+ if(!logged)
+ info("IEEE754: system is NOT compatible with IEEE754 DOUBLE PRECISION values");
+
+ logged = true;
+ return false;
+ }
+}
+
storage_number pack_storage_number(NETDATA_DOUBLE value, SN_FLAGS flags) {
// bit 32 = sign 0:positive, 1:negative
// bit 31 = 0:divide, 1:multiply
@@ -159,73 +231,3 @@ int print_netdata_double(char *str, NETDATA_DOUBLE value)
return (int) ((wstr - str) + 2 + decimal );
}
*/
-
-int print_netdata_double(char *str, NETDATA_DOUBLE value) {
- // info("printing number " NETDATA_DOUBLE_FORMAT, value);
- char integral_str[50], fractional_str[50];
-
- char *wstr = str;
-
- if(unlikely(value < 0)) {
- *wstr++ = '-';
- value = -value;
- }
-
- NETDATA_DOUBLE integral, fractional;
-
-#ifdef STORAGE_WITH_MATH
- fractional = modfndd(value, &integral) * 10000000.0;
-#else
- integral = (NETDATA_DOUBLE)((unsigned long long)(value * 10000000ULL) / 10000000ULL);
- fractional = (NETDATA_DOUBLE)((unsigned long long)(value * 10000000ULL) % 10000000ULL);
-#endif
-
- unsigned long long integral_int = (unsigned long long)integral;
- unsigned long long fractional_int = (unsigned long long)llrintndd(fractional);
- if(unlikely(fractional_int >= 10000000)) {
- integral_int += 1;
- fractional_int -= 10000000;
- }
-
- // info("integral " NETDATA_DOUBLE_FORMAT " (%llu), fractional " NETDATA_DOUBLE_FORMAT " (%llu)", integral, integral_int, fractional, fractional_int);
-
- char *istre;
- if(unlikely(integral_int == 0)) {
- integral_str[0] = '0';
- istre = &integral_str[1];
- }
- else
- // convert the integral part to string (reversed)
- istre = print_number_llu_r_smart(integral_str, integral_int);
-
- // copy reversed the integral string
- istre--;
- while( istre >= integral_str ) *wstr++ = *istre--;
-
- if(likely(fractional_int != 0)) {
- // add a dot
- *wstr++ = '.';
-
- // convert the fractional part to string (reversed)
- char *fstre = print_number_llu_r_smart(fractional_str, fractional_int);
-
- // prepend zeros to reach 7 digits length
- int decimal = 7;
- int len = (int)(fstre - fractional_str);
- while(len < decimal) {
- *wstr++ = '0';
- len++;
- }
-
- char *begin = fractional_str;
- while(begin < fstre && *begin == '0') begin++;
-
- // copy reversed the fractional string
- fstre--;
- while( fstre >= begin ) *wstr++ = *fstre--;
- }
-
- *wstr = '\0';
- // info("printed number '%s'", str);
- return (int)(wstr - str);
-}
diff --git a/libnetdata/storage_number/storage_number.h b/libnetdata/storage_number/storage_number.h
index faea47751..82c870d69 100644
--- a/libnetdata/storage_number/storage_number.h
+++ b/libnetdata/storage_number/storage_number.h
@@ -13,6 +13,7 @@ typedef long double NETDATA_DOUBLE;
#define NETDATA_DOUBLE_FORMAT_ZERO "%0.0Lf"
#define NETDATA_DOUBLE_FORMAT_AUTO "%Lf"
#define NETDATA_DOUBLE_MODIFIER "Lf"
+#define NETDATA_DOUBLE_FORMAT_G "%0.19Le"
#define NETDATA_DOUBLE_MAX LDBL_MAX
@@ -24,6 +25,9 @@ typedef long double NETDATA_DOUBLE;
#define copysignndd(x, y) copysignl(x, y)
#define modfndd(x, y) modfl(x, y)
#define fabsndd(x) fabsl(x)
+#define floorndd(x) floorl(x)
+#define ceilndd(x) ceill(x)
+#define log10ndd(x) log10l(x)
#else // NETDATA_WITH_LONG_DOUBLE
@@ -32,6 +36,7 @@ typedef double NETDATA_DOUBLE;
#define NETDATA_DOUBLE_FORMAT_ZERO "%0.0f"
#define NETDATA_DOUBLE_FORMAT_AUTO "%f"
#define NETDATA_DOUBLE_MODIFIER "f"
+#define NETDATA_DOUBLE_FORMAT_G "%0.19e"
#define NETDATA_DOUBLE_MAX DBL_MAX
@@ -43,6 +48,9 @@ typedef double NETDATA_DOUBLE;
#define copysignndd(x, y) copysign(x, y)
#define modfndd(x, y) modf(x, y)
#define fabsndd(x) fabs(x)
+#define floorndd(x) floor(x)
+#define ceilndd(x) ceil(x)
+#define log10ndd(x) log10(x)
#endif // NETDATA_WITH_LONG_DOUBLE
@@ -62,6 +70,9 @@ typedef long long collected_number;
#define netdata_double_isnumber(a) (fpclassify(a) != FP_NAN && fpclassify(a) != FP_INFINITE)
#endif
+#define netdata_double_is_zero(a) (!netdata_double_isnumber(a) || considered_equal_ndd(a, 0.0))
+#define netdata_double_is_nonzero(a) (!netdata_double_is_zero(a))
+
typedef uint32_t storage_number;
typedef struct storage_number_tier1 {
@@ -104,8 +115,6 @@ typedef enum {
storage_number pack_storage_number(NETDATA_DOUBLE value, SN_FLAGS flags) __attribute__((const));
static inline NETDATA_DOUBLE unpack_storage_number(storage_number value) __attribute__((const));
-int print_netdata_double(char *str, NETDATA_DOUBLE value);
-
// sign div/mul <--- multiplier / divider ---> 10/100 RESET EXISTS VALUE
#define STORAGE_NUMBER_POSITIVE_MAX_RAW (storage_number)( (0 << 31) | (1 << 30) | (1 << 29) | (1 << 28) | (1 << 27) | (1 << 26) | (0 << 25) | (1 << 24) | 0x00ffffff )
#define STORAGE_NUMBER_POSITIVE_MIN_RAW (storage_number)( (0 << 31) | (0 << 30) | (1 << 29) | (1 << 28) | (1 << 27) | (0 << 26) | (0 << 25) | (1 << 24) | 0x00000001 )
@@ -158,75 +167,12 @@ static inline NETDATA_DOUBLE unpack_storage_number(storage_number value) {
return sign * unpack_storage_number_lut10x[(factor * 16) + (exp * 8) + mul] * n;
}
-static inline NETDATA_DOUBLE str2ndd(const char *s, char **endptr) {
- int negative = 0;
- const char *start = s;
- unsigned long long integer_part = 0;
- unsigned long decimal_part = 0;
- size_t decimal_digits = 0;
-
- switch(*s) {
- case '-':
- s++;
- negative = 1;
- break;
-
- case '+':
- s++;
- break;
-
- case 'n':
- if(s[1] == 'a' && s[2] == 'n') {
- if(endptr) *endptr = (char *)&s[3];
- return NAN;
- }
- break;
-
- case 'i':
- if(s[1] == 'n' && s[2] == 'f') {
- if(endptr) *endptr = (char *)&s[3];
- return INFINITY;
- }
- break;
-
- default:
- break;
- }
-
- while (*s >= '0' && *s <= '9') {
- integer_part = (integer_part * 10) + (*s - '0');
- s++;
- }
-
- if(unlikely(*s == '.')) {
- decimal_part = 0;
- s++;
-
- while (*s >= '0' && *s <= '9') {
- decimal_part = (decimal_part * 10) + (*s - '0');
- s++;
- decimal_digits++;
- }
- }
-
- if(unlikely(*s == 'e' || *s == 'E'))
- return strtondd(start, endptr);
-
- if(unlikely(endptr))
- *endptr = (char *)s;
-
- if(unlikely(negative)) {
- if(unlikely(decimal_digits))
- return -((NETDATA_DOUBLE)integer_part + (NETDATA_DOUBLE)decimal_part / powndd(10.0, decimal_digits));
- else
- return -((NETDATA_DOUBLE)integer_part);
- }
- else {
- if(unlikely(decimal_digits))
- return (NETDATA_DOUBLE)integer_part + (NETDATA_DOUBLE)decimal_part / powndd(10.0, decimal_digits);
- else
- return (NETDATA_DOUBLE)integer_part;
- }
-}
+// all these prefixes should use characters that are not allowed in the numbers they represent
+#define HEX_PREFIX "0x" // we check 2 characters when parsing
+#define IEEE754_UINT64_B64_PREFIX "#" // we check the 1st character during parsing
+#define IEEE754_DOUBLE_B64_PREFIX "@" // we check the 1st character during parsing
+#define IEEE754_DOUBLE_HEX_PREFIX "%" // we check the 1st character during parsing
+
+bool is_system_ieee754_double(void);
#endif /* NETDATA_STORAGE_NUMBER_H */