storage_number.c 6.7 KB

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