No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

416 líneas
11KB

  1. /* FatLib Library
  2. * Copyright (C) 2013 by William Greiman
  3. *
  4. * This file is part of the FatLib Library
  5. *
  6. * This Library is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This Library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the FatLib Library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. #include "FmtNumber.h"
  21. // Use Stimmer div/mod 10 on avr
  22. #ifdef __AVR__
  23. #include <avr/pgmspace.h>
  24. #define USE_STIMMER
  25. #endif // __AVR__
  26. //------------------------------------------------------------------------------
  27. // Stimmer div/mod 10 for AVR
  28. // this code fragment works out i/10 and i%10 by calculating
  29. // i*(51/256)*(256/255)/2 == i*51/510 == i/10
  30. // by "j.k" I mean 32.8 fixed point, j is integer part, k is fractional part
  31. // j.k = ((j+1.0)*51.0)/256.0
  32. // (we add 1 because we will be using the floor of the result later)
  33. // divmod10_asm16 and divmod10_asm32 are public domain code by Stimmer.
  34. // http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
  35. #define divmod10_asm16(in32, mod8, tmp8) \
  36. asm volatile( \
  37. " ldi %2,51 \n\t" \
  38. " mul %A0,%2 \n\t" \
  39. " clr %A0 \n\t" \
  40. " add r0,%2 \n\t" \
  41. " adc %A0,r1 \n\t" \
  42. " mov %1,r0 \n\t" \
  43. " mul %B0,%2 \n\t" \
  44. " clr %B0 \n\t" \
  45. " add %A0,r0 \n\t" \
  46. " adc %B0,r1 \n\t" \
  47. " clr r1 \n\t" \
  48. " add %1,%A0 \n\t" \
  49. " adc %A0,%B0 \n\t" \
  50. " adc %B0,r1 \n\t" \
  51. " add %1,%B0 \n\t" \
  52. " adc %A0,r1 \n\t" \
  53. " adc %B0,r1 \n\t" \
  54. " lsr %B0 \n\t" \
  55. " ror %A0 \n\t" \
  56. " ror %1 \n\t" \
  57. " ldi %2,10 \n\t" \
  58. " mul %1,%2 \n\t" \
  59. " mov %1,r1 \n\t" \
  60. " clr r1 \n\t" \
  61. :"+r"(in32), "=d"(mod8), "=d"(tmp8) : : "r0")
  62. #define divmod10_asm32(in32, mod8, tmp8) \
  63. asm volatile( \
  64. " ldi %2,51 \n\t" \
  65. " mul %A0,%2 \n\t" \
  66. " clr %A0 \n\t" \
  67. " add r0,%2 \n\t" \
  68. " adc %A0,r1 \n\t" \
  69. " mov %1,r0 \n\t" \
  70. " mul %B0,%2 \n\t" \
  71. " clr %B0 \n\t" \
  72. " add %A0,r0 \n\t" \
  73. " adc %B0,r1 \n\t" \
  74. " mul %C0,%2 \n\t" \
  75. " clr %C0 \n\t" \
  76. " add %B0,r0 \n\t" \
  77. " adc %C0,r1 \n\t" \
  78. " mul %D0,%2 \n\t" \
  79. " clr %D0 \n\t" \
  80. " add %C0,r0 \n\t" \
  81. " adc %D0,r1 \n\t" \
  82. " clr r1 \n\t" \
  83. " add %1,%A0 \n\t" \
  84. " adc %A0,%B0 \n\t" \
  85. " adc %B0,%C0 \n\t" \
  86. " adc %C0,%D0 \n\t" \
  87. " adc %D0,r1 \n\t" \
  88. " add %1,%B0 \n\t" \
  89. " adc %A0,%C0 \n\t" \
  90. " adc %B0,%D0 \n\t" \
  91. " adc %C0,r1 \n\t" \
  92. " adc %D0,r1 \n\t" \
  93. " add %1,%D0 \n\t" \
  94. " adc %A0,r1 \n\t" \
  95. " adc %B0,r1 \n\t" \
  96. " adc %C0,r1 \n\t" \
  97. " adc %D0,r1 \n\t" \
  98. " lsr %D0 \n\t" \
  99. " ror %C0 \n\t" \
  100. " ror %B0 \n\t" \
  101. " ror %A0 \n\t" \
  102. " ror %1 \n\t" \
  103. " ldi %2,10 \n\t" \
  104. " mul %1,%2 \n\t" \
  105. " mov %1,r1 \n\t" \
  106. " clr r1 \n\t" \
  107. :"+r"(in32), "=d"(mod8), "=d"(tmp8) : : "r0")
  108. //------------------------------------------------------------------------------
  109. /*
  110. // C++ code is based on this version of divmod10 by robtillaart.
  111. // http://forum.arduino.cc/index.php?topic=167414.msg1246851#msg1246851
  112. // from robtillaart post:
  113. // The code is based upon the divu10() code from the book Hackers Delight1.
  114. // My insight was that the error formula in divu10() was in fact modulo 10
  115. // but not always. Sometimes it was 10 more.
  116. void divmod10(uint32_t in, uint32_t &div, uint32_t &mod)
  117. {
  118. // q = in * 0.8;
  119. uint32_t q = (in >> 1) + (in >> 2);
  120. q = q + (q >> 4);
  121. q = q + (q >> 8);
  122. q = q + (q >> 16); // not needed for 16 bit version
  123. // q = q / 8; ==> q = in *0.1;
  124. q = q >> 3;
  125. // determine error
  126. uint32_t r = in - ((q << 3) + (q << 1)); // r = in - q*10;
  127. div = q + (r > 9);
  128. if (r > 9) mod = r - 10;
  129. else mod = r;
  130. }
  131. // Hackers delight function is here:
  132. // http://www.hackersdelight.org/hdcodetxt/divuc.c.txt
  133. // Code below uses 8/10 = 0.1100 1100 1100 1100 1100 1100 1100 1100.
  134. // 15 ops including the multiply, or 17 elementary ops.
  135. unsigned divu10(unsigned n) {
  136. unsigned q, r;
  137. q = (n >> 1) + (n >> 2);
  138. q = q + (q >> 4);
  139. q = q + (q >> 8);
  140. q = q + (q >> 16);
  141. q = q >> 3;
  142. r = n - q*10;
  143. return q + ((r + 6) >> 4);
  144. // return q + (r > 9);
  145. }
  146. */
  147. //------------------------------------------------------------------------------
  148. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  149. #ifdef __AVR__
  150. static const float m[] PROGMEM = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
  151. static const float p[] PROGMEM = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
  152. #else // __AVR__
  153. static const float m[] = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
  154. static const float p[] = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
  155. #endif // __AVR__
  156. #endif // DOXYGEN_SHOULD_SKIP_THIS
  157. // scale float v by power of ten. return v*10^n
  158. float scale10(float v, int8_t n) {
  159. const float *s;
  160. if (n < 0) {
  161. n = -n;
  162. s = m;
  163. } else {
  164. s = p;
  165. }
  166. n &= 63;
  167. for (uint8_t i = 0; n; n >>= 1, i++) {
  168. #ifdef __AVR__
  169. if (n & 1) v *= pgm_read_float(&s[i]);
  170. #else // __AVR__
  171. if (n & 1) v *= s[i];
  172. #endif // __AVR__
  173. }
  174. return v;
  175. }
  176. //------------------------------------------------------------------------------
  177. // Format 16-bit unsigned
  178. char* fmtDec(uint16_t n, char* p) {
  179. while (n > 9) {
  180. #ifdef USE_STIMMER
  181. uint8_t tmp8, r;
  182. divmod10_asm16(n, r, tmp8);
  183. #else // USE_STIMMER
  184. uint16_t t = n;
  185. n = (n >> 1) + (n >> 2);
  186. n = n + (n >> 4);
  187. n = n + (n >> 8);
  188. // n = n + (n >> 16); // no code for 16-bit n
  189. n = n >> 3;
  190. uint8_t r = t - (((n << 2) + n) << 1);
  191. if (r > 9) {
  192. n++;
  193. r -= 10;
  194. }
  195. #endif // USE_STIMMER
  196. *--p = r + '0';
  197. }
  198. *--p = n + '0';
  199. return p;
  200. }
  201. //------------------------------------------------------------------------------
  202. // format 32-bit unsigned
  203. char* fmtDec(uint32_t n, char* p) {
  204. while (n >> 16) {
  205. #ifdef USE_STIMMER
  206. uint8_t tmp8, r;
  207. divmod10_asm32(n, r, tmp8);
  208. #else // USE_STIMMER
  209. uint32_t t = n;
  210. n = (n >> 1) + (n >> 2);
  211. n = n + (n >> 4);
  212. n = n + (n >> 8);
  213. n = n + (n >> 16);
  214. n = n >> 3;
  215. uint8_t r = t - (((n << 2) + n) << 1);
  216. if (r > 9) {
  217. n++;
  218. r -= 10;
  219. }
  220. #endif // USE_STIMMER
  221. *--p = r + '0';
  222. }
  223. return fmtDec((uint16_t)n, p);
  224. }
  225. //------------------------------------------------------------------------------
  226. char* fmtFloat(float value, char* p, uint8_t prec) {
  227. char sign = value < 0 ? '-' : 0;
  228. if (sign) value = -value;
  229. if (isnan(value)) {
  230. *--p = 'n';
  231. *--p = 'a';
  232. *--p = 'n';
  233. return p;
  234. }
  235. if (isinf(value)) {
  236. *--p = 'f';
  237. *--p = 'n';
  238. *--p = 'i';
  239. return p;
  240. }
  241. if (value > 4294967040.0) {
  242. *--p = 'f';
  243. *--p = 'v';
  244. *--p = 'o';
  245. return p;
  246. }
  247. if (prec > 9) prec = 9;
  248. value += scale10(0.5, -prec);
  249. uint32_t whole = value;
  250. if (prec) {
  251. char* tmp = p - prec;
  252. uint32_t fraction = scale10(value - whole, prec);
  253. p = fmtDec(fraction, p);
  254. while (p > tmp) *--p = '0';
  255. *--p = '.';
  256. }
  257. p = fmtDec(whole, p);
  258. if (sign) *--p = sign;
  259. return p;
  260. }
  261. //------------------------------------------------------------------------------
  262. /** Print a number followed by a field terminator.
  263. * \param[in] value The number to be printed.
  264. * \param[in] ptr Pointer to last char in buffer.
  265. * \param[in] prec Number of digits after decimal point.
  266. * \param[in] expChar Use exp format if non zero.
  267. * \return Pointer to first character of result.
  268. */
  269. char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
  270. bool neg = value < 0;
  271. if (neg) value = -value;
  272. // check for nan inf ovf
  273. if (isnan(value)) {
  274. *--ptr = 'n';
  275. *--ptr = 'a';
  276. *--ptr = 'n';
  277. return ptr;
  278. }
  279. if (isinf(value)) {
  280. *--ptr = 'f';
  281. *--ptr = 'n';
  282. *--ptr = 'i';
  283. return ptr;
  284. }
  285. if (!expChar && value > 4294967040.0) {
  286. *--ptr = 'f';
  287. *--ptr = 'v';
  288. *--ptr = 'o';
  289. return ptr;
  290. }
  291. if (prec > 9) prec = 9;
  292. float round = scale10(0.5, -prec);
  293. if (expChar) {
  294. int8_t exp = 0;
  295. bool expNeg = false;
  296. if (value) {
  297. while (value > 10.0) {
  298. value *= 0.1;
  299. exp++;
  300. }
  301. while (value < 1.0) {
  302. value *= 10.0;
  303. exp--;
  304. }
  305. value += round;
  306. if (value > 10.0) {
  307. value *= 0.1;
  308. exp++;
  309. }
  310. expNeg = exp < 0;
  311. if (expNeg) exp = -exp;
  312. }
  313. ptr = fmtDec((uint16_t)exp, ptr);
  314. if (exp < 10) *--ptr = '0';
  315. *--ptr = expNeg ? '-' : '+';
  316. *--ptr = expChar;
  317. } else {
  318. // round value
  319. value += round;
  320. }
  321. uint32_t whole = value;
  322. if (prec) {
  323. char* tmp = ptr - prec;
  324. uint32_t fraction = scale10(value - whole, prec);
  325. ptr = fmtDec(fraction, ptr);
  326. while (ptr > tmp) *--ptr = '0';
  327. *--ptr = '.';
  328. }
  329. ptr = fmtDec(whole, ptr);
  330. if (neg) *--ptr = '-';
  331. return ptr;
  332. }
  333. //------------------------------------------------------------------------------
  334. char* fmtHex(uint32_t n, char* p) {
  335. do {
  336. uint8_t h = n & 0XF;
  337. *--p = h + (h < 10 ? '0' : 'A' - 10);
  338. n >>= 4;
  339. } while (n);
  340. return p;
  341. }
  342. //------------------------------------------------------------------------------
  343. float scanFloat(const char* str, char** ptr) {
  344. int16_t const EXP_LIMIT = 100;
  345. bool digit = false;
  346. bool dot = false;
  347. uint32_t fract = 0;
  348. int fracExp = 0;
  349. uint8_t nd = 0;
  350. bool neg;
  351. int c;
  352. float v;
  353. const char* successPtr;
  354. if (ptr) *ptr = const_cast<char*>(str);
  355. while (isspace((c = *str++))) {}
  356. neg = c == '-';
  357. if (c == '-' || c == '+') c = *str++;
  358. // Skip leading zeros
  359. while (c == '0') {
  360. c = *str++;
  361. digit = true;
  362. }
  363. for (;;) {
  364. if (isdigit(c)) {
  365. digit = true;
  366. if (nd < 9) {
  367. fract = 10*fract + c - '0';
  368. nd++;
  369. if (dot) fracExp--;
  370. } else {
  371. if (!dot) fracExp++;
  372. }
  373. } else if (c == '.') {
  374. if (dot) goto fail;
  375. dot = true;
  376. } else {
  377. if (!digit) goto fail;
  378. break;
  379. }
  380. successPtr = str;
  381. c = *str++;
  382. }
  383. if (c == 'e' || c == 'E') {
  384. int exp = 0;
  385. c = *str++;
  386. bool expNeg = c == '-';
  387. if (c == '-' || c == '+') {
  388. c = *str++;
  389. }
  390. while (isdigit(c)) {
  391. if (exp > EXP_LIMIT) goto fail;
  392. exp = 10*exp + c - '0';
  393. successPtr = str;
  394. c = *str++;
  395. }
  396. fracExp += expNeg ? -exp : exp;
  397. }
  398. if (ptr) *ptr = const_cast<char*>(successPtr);
  399. v = scale10(static_cast<float>(fract), fracExp);
  400. return neg ? -v: v;
  401. fail:
  402. return 0;
  403. }