storage_number.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "../libnetdata.h"
  3. #define get_storage_number_flags(value) \
  4. ((((storage_number)(value)) & (1 << 24)) | \
  5. (((storage_number)(value)) & (1 << 25)) | \
  6. (((storage_number)(value)) & (1 << 26)))
  7. storage_number pack_storage_number(calculated_number value, uint32_t flags) {
  8. // bit 32 = sign 0:positive, 1:negative
  9. // bit 31 = 0:divide, 1:multiply
  10. // bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total)
  11. // bit 27 SN_EXISTS_100
  12. // bit 26 SN_EXISTS_RESET
  13. // bit 25 SN_ANOMALY_BIT = 0: anomalous, 1: not anomalous
  14. // bit 24 to bit 1 = the value
  15. storage_number r = get_storage_number_flags(flags);
  16. if(!value)
  17. goto RET_SN;
  18. int m = 0;
  19. calculated_number n = value, factor = 10;
  20. // if the value is negative
  21. // add the sign bit and make it positive
  22. if(n < 0) {
  23. r += (1 << 31); // the sign bit 32
  24. n = -n;
  25. }
  26. if(n / 10000000.0 > 0x00ffffff) {
  27. factor = 100;
  28. r |= SN_EXISTS_100;
  29. }
  30. // make its integer part fit in 0x00ffffff
  31. // by dividing it by 10 up to 7 times
  32. // and increasing the multiplier
  33. while(m < 7 && n > (calculated_number)0x00ffffff) {
  34. n /= factor;
  35. m++;
  36. }
  37. if(m) {
  38. // the value was too big and we divided it
  39. // so we add a multiplier to unpack it
  40. r += (1 << 30) + (m << 27); // the multiplier m
  41. if(n > (calculated_number)0x00ffffff) {
  42. #ifdef NETDATA_INTERNAL_CHECKS
  43. error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
  44. #endif
  45. r += 0x00ffffff;
  46. goto RET_SN;
  47. }
  48. }
  49. else {
  50. // 0x0019999e is the number that can be multiplied
  51. // by 10 to give 0x00ffffff
  52. // while the value is below 0x0019999e we can
  53. // multiply it by 10, up to 7 times, increasing
  54. // the multiplier
  55. while(m < 7 && n < (calculated_number)0x0019999e) {
  56. n *= 10;
  57. m++;
  58. }
  59. if (unlikely(n > (calculated_number) (0x00ffffff))) {
  60. n /= 10;
  61. m--;
  62. }
  63. // the value was small enough and we multiplied it
  64. // so we add a divider to unpack it
  65. r += (0 << 30) + (m << 27); // the divider m
  66. }
  67. #ifdef STORAGE_WITH_MATH
  68. // without this there are rounding problems
  69. // example: 0.9 becomes 0.89
  70. r += lrint((double) n);
  71. #else
  72. r += (storage_number)n;
  73. #endif
  74. RET_SN:
  75. if (r == SN_EMPTY_SLOT)
  76. r = SN_ANOMALOUS_ZERO;
  77. return r;
  78. }
  79. calculated_number unpack_storage_number(storage_number value) {
  80. if(!value) return 0;
  81. int sign = 0, exp = 0;
  82. int factor = 10;
  83. // bit 32 = 0:positive, 1:negative
  84. if(unlikely(value & (1 << 31)))
  85. sign = 1;
  86. // bit 31 = 0:divide, 1:multiply
  87. if(unlikely(value & (1 << 30)))
  88. exp = 1;
  89. // bit 27 SN_EXISTS_100
  90. if(unlikely(value & (1 << 26)))
  91. factor = 100;
  92. // bit 26 SN_EXISTS_RESET
  93. // bit 25 SN_ANOMALY_BIT
  94. // bit 30, 29, 28 = (multiplier or divider) 0-7 (8 total)
  95. int mul = (value & ((1<<29)|(1<<28)|(1<<27))) >> 27;
  96. // bit 24 to bit 1 = the value, so remove all other bits
  97. value ^= value & ((1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(1<<26)|(1<<25)|(1<<24));
  98. calculated_number n = value;
  99. // fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, factor = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, factor, n);
  100. if(exp) {
  101. for(; mul; mul--)
  102. n *= factor;
  103. }
  104. else {
  105. for( ; mul ; mul--)
  106. n /= 10;
  107. }
  108. if(sign) n = -n;
  109. return n;
  110. }
  111. /*
  112. int print_calculated_number(char *str, calculated_number value)
  113. {
  114. char *wstr = str;
  115. int sign = (value < 0) ? 1 : 0;
  116. if(sign) value = -value;
  117. #ifdef STORAGE_WITH_MATH
  118. // without llrintl() there are rounding problems
  119. // for example 0.9 becomes 0.89
  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. wstr = print_number_llu_r_smart(str, uvalue);
  125. // make sure we have 6 bytes at least
  126. while((wstr - str) < 6) *wstr++ = '0';
  127. // put the sign back
  128. if(sign) *wstr++ = '-';
  129. // reverse it
  130. char *begin = str, *end = --wstr, aux;
  131. while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
  132. // wstr--;
  133. // strreverse(str, wstr);
  134. // remove trailing zeros
  135. int decimal = 5;
  136. while(decimal > 0 && *wstr == '0') {
  137. *wstr-- = '\0';
  138. decimal--;
  139. }
  140. // terminate it, one position to the right
  141. // to let space for a dot
  142. wstr[2] = '\0';
  143. // make space for the dot
  144. int i;
  145. for(i = 0; i < decimal ;i++) {
  146. wstr[1] = wstr[0];
  147. wstr--;
  148. }
  149. // put the dot
  150. if(wstr[2] == '\0') { wstr[1] = '\0'; decimal--; }
  151. else wstr[1] = '.';
  152. // return the buffer length
  153. return (int) ((wstr - str) + 2 + decimal );
  154. }
  155. */
  156. int print_calculated_number(char *str, calculated_number value) {
  157. // info("printing number " CALCULATED_NUMBER_FORMAT, value);
  158. char integral_str[50], fractional_str[50];
  159. char *wstr = str;
  160. if(unlikely(value < 0)) {
  161. *wstr++ = '-';
  162. value = -value;
  163. }
  164. calculated_number integral, fractional;
  165. #ifdef STORAGE_WITH_MATH
  166. fractional = calculated_number_modf(value, &integral) * 10000000.0;
  167. #else
  168. fractional = ((unsigned long long)(value * 10000000ULL) % 10000000ULL);
  169. #endif
  170. unsigned long long integral_int = (unsigned long long)integral;
  171. unsigned long long fractional_int = (unsigned long long)calculated_number_llrint(fractional);
  172. if(unlikely(fractional_int >= 10000000)) {
  173. integral_int += 1;
  174. fractional_int -= 10000000;
  175. }
  176. // info("integral " CALCULATED_NUMBER_FORMAT " (%llu), fractional " CALCULATED_NUMBER_FORMAT " (%llu)", integral, integral_int, fractional, fractional_int);
  177. char *istre;
  178. if(unlikely(integral_int == 0)) {
  179. integral_str[0] = '0';
  180. istre = &integral_str[1];
  181. }
  182. else
  183. // convert the integral part to string (reversed)
  184. istre = print_number_llu_r_smart(integral_str, integral_int);
  185. // copy reversed the integral string
  186. istre--;
  187. while( istre >= integral_str ) *wstr++ = *istre--;
  188. if(likely(fractional_int != 0)) {
  189. // add a dot
  190. *wstr++ = '.';
  191. // convert the fractional part to string (reversed)
  192. char *fstre = print_number_llu_r_smart(fractional_str, fractional_int);
  193. // prepend zeros to reach 7 digits length
  194. int decimal = 7;
  195. int len = (int)(fstre - fractional_str);
  196. while(len < decimal) {
  197. *wstr++ = '0';
  198. len++;
  199. }
  200. char *begin = fractional_str;
  201. while(begin < fstre && *begin == '0') begin++;
  202. // copy reversed the fractional string
  203. fstre--;
  204. while( fstre >= begin ) *wstr++ = *fstre--;
  205. }
  206. *wstr = '\0';
  207. // info("printed number '%s'", str);
  208. return (int)(wstr - str);
  209. }