]> arthur.barton.de Git - netdata.git/blobdiff - src/storage_number.c
renamed states family
[netdata.git] / src / storage_number.c
old mode 100755 (executable)
new mode 100644 (file)
index fa18805..27fe5f2
-#include <math.h>
+#include "common.h"
 
-#include "log.h"
-#include "storage_number.h"
+extern char *print_number_lu_r(char *str, unsigned long uvalue);
+extern char *print_number_llu_r(char *str, unsigned long long uvalue);
 
-storage_number pack_storage_number(calculated_number value)
+storage_number pack_storage_number(calculated_number value, uint32_t flags)
 {
-       storage_number r = 0;
-       if(!value) return r;
-
-       // bit 32 = sign
-       // bit 31 = 0:divide, 1:multiply
-       // bit 30, 29, 28 = (multiplier or divider) 0-7
-       // bit 27 to 25 = reserved for flags
-       // bit 24 to bit 1 = the value
-
-       storage_number sign = 0, exp = 0, mul;
-       int m = 0;
-       calculated_number n = value;
-
-       if(n < 0) {
-               sign = 1;
-               n = -n;
-       }
-
-       while(m < 7 && n > (calculated_number)0x00ffffff) {
-               n /= 10;
-               m++;
-       }
-       while(m > -7 && n < (calculated_number)0x00199999) {
-               n *= 10;
-               m--;
-       }
-
-       if(m <= 0) {
-               exp = 0;
-               m = -m;
-       }
-       else exp = 1;
-
-       if(n > (calculated_number)0x00ffffff) {
-               error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
-               n = (calculated_number)0x00ffffff;
-       }
-
-       mul = m;
-
-       // without this there are rounding problems
-       // example: 0.9 becomes 0.89
-       n = lrint(n);
-
-       r = (sign << 31) + (exp << 30) + (mul << 27) + n;
-       // fprintf(stderr, "PACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", r, sign, exp, mul, n);
-
-       return r;
+    // bit 32 = sign 0:positive, 1:negative
+    // bit 31 = 0:divide, 1:multiply
+    // bit 30, 29, 28 = (multiplier or divider) 0-6 (7 total)
+    // bit 27, 26, 25 flags
+    // bit 24 to bit 1 = the value
+
+    storage_number r = get_storage_number_flags(flags);
+    if(!value) return r;
+
+    int m = 0;
+    calculated_number n = value;
+
+    // if the value is negative
+    // add the sign bit and make it positive
+    if(n < 0) {
+        r += (1 << 31); // the sign bit 32
+        n = -n;
+    }
+
+    // make its integer part fit in 0x00ffffff
+    // by dividing it by 10 up to 7 times
+    // and increasing the multiplier
+    while(m < 7 && n > (calculated_number)0x00ffffff) {
+        n /= 10;
+        m++;
+    }
+
+    if(m) {
+        // the value was too big and we divided it
+        // so we add a multiplier to unpack it
+        r += (1 << 30) + (m << 27); // the multiplier m
+
+        if(n > (calculated_number)0x00ffffff) {
+            error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
+            r += 0x00ffffff;
+            return r;
+        }
+    }
+    else {
+        // 0x0019999e is the number that can be multiplied
+        // by 10 to give 0x00ffffff
+        // while the value is below 0x0019999e we can
+        // multiply it by 10, up to 7 times, increasing
+        // the multiplier
+        while(m < 7 && n < (calculated_number)0x0019999e) {
+            n *= 10;
+            m++;
+        }
+
+        // the value was small enough and we multiplied it
+        // so we add a divider to unpack it
+        r += (0 << 30) + (m << 27); // the divider m
+    }
+
+#ifdef STORAGE_WITH_MATH
+    // without this there are rounding problems
+    // example: 0.9 becomes 0.89
+    r += lrint((double) n);
+#else
+    r += (storage_number)n;
+#endif
+
+    return r;
 }
 
 calculated_number unpack_storage_number(storage_number value)
 {
-       if(!value) return 0;
+    if(!value) return 0;
 
-       int sign = 0;
-       int exp = 0;
+    int sign = 0, exp = 0;
 
-       if(value & (1 << 31)) {
-               sign = 1;
-               value ^= 1 << 31;
-       }
+    value ^= get_storage_number_flags(value);
 
-       if(value & (1 << 30)) {
-               exp = 1;
-               value ^= 1 << 30;
-       }
+    if(value & (1 << 31)) {
+        sign = 1;
+        value ^= 1 << 31;
+    }
 
-       int mul = value >> 27;
-       value ^= mul << 27;
+    if(value & (1 << 30)) {
+        exp = 1;
+        value ^= 1 << 30;
+    }
 
-       calculated_number n = value;
+    int mul = value >> 27;
+    value ^= mul << 27;
 
-       // fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, n);
+    calculated_number n = value;
 
-       while(mul > 0) {
-               if(exp) n *= 10;
-               else n /= 10;
-               mul--;
-       }
+    // fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, n);
 
-       if(sign) n = -n;
-       return n;
+    while(mul > 0) {
+        if(exp) n *= 10;
+        else n /= 10;
+        mul--;
+    }
+
+    if(sign) n = -n;
+    return n;
+}
+
+int print_calculated_number(char *str, calculated_number value)
+{
+    char *wstr = str;
+
+    int sign = (value < 0) ? 1 : 0;
+    if(sign) value = -value;
+
+#ifdef STORAGE_WITH_MATH
+    // without llrint() there are rounding problems
+    // for example 0.9 becomes 0.89
+    unsigned long long uvalue = (unsigned long long int) llrint(value * (calculated_number)100000);
+#else
+    unsigned long long uvalue = value * (calculated_number)100000;
+#endif
+
+#ifdef ENVIRONMENT32
+    if(uvalue > (unsigned long long)0xffffffff)
+        wstr = print_number_llu_r(str, uvalue);
+    else
+        wstr = print_number_lu_r(str, uvalue);
+#else
+    do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
+#endif
+
+    // make sure we have 6 bytes at least
+    while((wstr - str) < 6) *wstr++ = '0';
+
+    // put the sign back
+    if(sign) *wstr++ = '-';
+
+    // reverse it
+    char *begin = str, *end = --wstr, aux;
+    while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
+    // wstr--;
+    // strreverse(str, wstr);
+
+    // remove trailing zeros
+    int decimal = 5;
+    while(decimal > 0 && *wstr == '0') {
+        *wstr-- = '\0';
+        decimal--;
+    }
+
+    // terminate it, one position to the right
+    // to let space for a dot
+    wstr[2] = '\0';
+
+    // make space for the dot
+    int i;
+    for(i = 0; i < decimal ;i++) {
+        wstr[1] = wstr[0];
+        wstr--;
+    }
+
+    // put the dot
+    if(wstr[2] == '\0') { wstr[1] = '\0'; decimal--; }
+    else wstr[1] = '.';
+
+    // return the buffer length
+    return (int) ((wstr - str) + 2 + decimal );
 }