FmtNumber.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /**
  2. * Copyright (c) 2011-2018 Bill Greiman
  3. * This file is part of the SdFat library for SD memory cards.
  4. *
  5. * MIT License
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #include "FmtNumber.h"
  26. // Use Stimmer div/mod 10 on avr
  27. #ifdef __AVR__
  28. #include <avr/pgmspace.h>
  29. #define USE_STIMMER
  30. #endif // __AVR__
  31. //------------------------------------------------------------------------------
  32. // Stimmer div/mod 10 for AVR
  33. // this code fragment works out i/10 and i%10 by calculating
  34. // i*(51/256)*(256/255)/2 == i*51/510 == i/10
  35. // by "j.k" I mean 32.8 fixed point, j is integer part, k is fractional part
  36. // j.k = ((j+1.0)*51.0)/256.0
  37. // (we add 1 because we will be using the floor of the result later)
  38. // divmod10_asm16 and divmod10_asm32 are public domain code by Stimmer.
  39. // http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
  40. #define divmod10_asm16(in32, mod8, tmp8) \
  41. asm volatile( \
  42. " ldi %2,51 \n\t" \
  43. " mul %A0,%2 \n\t" \
  44. " clr %A0 \n\t" \
  45. " add r0,%2 \n\t" \
  46. " adc %A0,r1 \n\t" \
  47. " mov %1,r0 \n\t" \
  48. " mul %B0,%2 \n\t" \
  49. " clr %B0 \n\t" \
  50. " add %A0,r0 \n\t" \
  51. " adc %B0,r1 \n\t" \
  52. " clr r1 \n\t" \
  53. " add %1,%A0 \n\t" \
  54. " adc %A0,%B0 \n\t" \
  55. " adc %B0,r1 \n\t" \
  56. " add %1,%B0 \n\t" \
  57. " adc %A0,r1 \n\t" \
  58. " adc %B0,r1 \n\t" \
  59. " lsr %B0 \n\t" \
  60. " ror %A0 \n\t" \
  61. " ror %1 \n\t" \
  62. " ldi %2,10 \n\t" \
  63. " mul %1,%2 \n\t" \
  64. " mov %1,r1 \n\t" \
  65. " clr r1 \n\t" \
  66. :"+r"(in32), "=d"(mod8), "=d"(tmp8) : : "r0")
  67. #define divmod10_asm32(in32, mod8, tmp8) \
  68. asm volatile( \
  69. " ldi %2,51 \n\t" \
  70. " mul %A0,%2 \n\t" \
  71. " clr %A0 \n\t" \
  72. " add r0,%2 \n\t" \
  73. " adc %A0,r1 \n\t" \
  74. " mov %1,r0 \n\t" \
  75. " mul %B0,%2 \n\t" \
  76. " clr %B0 \n\t" \
  77. " add %A0,r0 \n\t" \
  78. " adc %B0,r1 \n\t" \
  79. " mul %C0,%2 \n\t" \
  80. " clr %C0 \n\t" \
  81. " add %B0,r0 \n\t" \
  82. " adc %C0,r1 \n\t" \
  83. " mul %D0,%2 \n\t" \
  84. " clr %D0 \n\t" \
  85. " add %C0,r0 \n\t" \
  86. " adc %D0,r1 \n\t" \
  87. " clr r1 \n\t" \
  88. " add %1,%A0 \n\t" \
  89. " adc %A0,%B0 \n\t" \
  90. " adc %B0,%C0 \n\t" \
  91. " adc %C0,%D0 \n\t" \
  92. " adc %D0,r1 \n\t" \
  93. " add %1,%B0 \n\t" \
  94. " adc %A0,%C0 \n\t" \
  95. " adc %B0,%D0 \n\t" \
  96. " adc %C0,r1 \n\t" \
  97. " adc %D0,r1 \n\t" \
  98. " add %1,%D0 \n\t" \
  99. " adc %A0,r1 \n\t" \
  100. " adc %B0,r1 \n\t" \
  101. " adc %C0,r1 \n\t" \
  102. " adc %D0,r1 \n\t" \
  103. " lsr %D0 \n\t" \
  104. " ror %C0 \n\t" \
  105. " ror %B0 \n\t" \
  106. " ror %A0 \n\t" \
  107. " ror %1 \n\t" \
  108. " ldi %2,10 \n\t" \
  109. " mul %1,%2 \n\t" \
  110. " mov %1,r1 \n\t" \
  111. " clr r1 \n\t" \
  112. :"+r"(in32), "=d"(mod8), "=d"(tmp8) : : "r0")
  113. //------------------------------------------------------------------------------
  114. /*
  115. // C++ code is based on this version of divmod10 by robtillaart.
  116. // http://forum.arduino.cc/index.php?topic=167414.msg1246851#msg1246851
  117. // from robtillaart post:
  118. // The code is based upon the divu10() code from the book Hackers Delight1.
  119. // My insight was that the error formula in divu10() was in fact modulo 10
  120. // but not always. Sometimes it was 10 more.
  121. void divmod10(uint32_t in, uint32_t &div, uint32_t &mod)
  122. {
  123. // q = in * 0.8;
  124. uint32_t q = (in >> 1) + (in >> 2);
  125. q = q + (q >> 4);
  126. q = q + (q >> 8);
  127. q = q + (q >> 16); // not needed for 16 bit version
  128. // q = q / 8; ==> q = in *0.1;
  129. q = q >> 3;
  130. // determine error
  131. uint32_t r = in - ((q << 3) + (q << 1)); // r = in - q*10;
  132. div = q + (r > 9);
  133. if (r > 9) mod = r - 10;
  134. else mod = r;
  135. }
  136. // Hackers delight function is here:
  137. // http://www.hackersdelight.org/hdcodetxt/divuc.c.txt
  138. // Code below uses 8/10 = 0.1100 1100 1100 1100 1100 1100 1100 1100.
  139. // 15 ops including the multiply, or 17 elementary ops.
  140. unsigned divu10(unsigned n) {
  141. unsigned q, r;
  142. q = (n >> 1) + (n >> 2);
  143. q = q + (q >> 4);
  144. q = q + (q >> 8);
  145. q = q + (q >> 16);
  146. q = q >> 3;
  147. r = n - q*10;
  148. return q + ((r + 6) >> 4);
  149. // return q + (r > 9);
  150. }
  151. */
  152. //------------------------------------------------------------------------------
  153. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  154. #ifdef __AVR__
  155. static const float m[] PROGMEM = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
  156. static const float p[] PROGMEM = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
  157. #else // __AVR__
  158. static const float m[] = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
  159. static const float p[] = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
  160. #endif // __AVR__
  161. #endif // DOXYGEN_SHOULD_SKIP_THIS
  162. // scale float v by power of ten. return v*10^n
  163. float scale10(float v, int8_t n) {
  164. const float *s;
  165. if (n < 0) {
  166. n = -n;
  167. s = m;
  168. } else {
  169. s = p;
  170. }
  171. n &= 63;
  172. for (uint8_t i = 0; n; n >>= 1, i++) {
  173. #ifdef __AVR__
  174. if (n & 1) {
  175. v *= pgm_read_float(&s[i]);
  176. }
  177. #else // __AVR__
  178. if (n & 1) {
  179. v *= s[i];
  180. }
  181. #endif // __AVR__
  182. }
  183. return v;
  184. }
  185. //------------------------------------------------------------------------------
  186. // Format 16-bit unsigned
  187. char* fmtDec(uint16_t n, char* p) {
  188. while (n > 9) {
  189. #ifdef USE_STIMMER
  190. uint8_t tmp8, r;
  191. divmod10_asm16(n, r, tmp8);
  192. #else // USE_STIMMER
  193. uint16_t t = n;
  194. n = (n >> 1) + (n >> 2);
  195. n = n + (n >> 4);
  196. n = n + (n >> 8);
  197. // n = n + (n >> 16); // no code for 16-bit n
  198. n = n >> 3;
  199. uint8_t r = t - (((n << 2) + n) << 1);
  200. if (r > 9) {
  201. n++;
  202. r -= 10;
  203. }
  204. #endif // USE_STIMMER
  205. *--p = r + '0';
  206. }
  207. *--p = n + '0';
  208. return p;
  209. }
  210. //------------------------------------------------------------------------------
  211. // format 32-bit unsigned
  212. char* fmtDec(uint32_t n, char* p) {
  213. while (n >> 16) {
  214. #ifdef USE_STIMMER
  215. uint8_t tmp8, r;
  216. divmod10_asm32(n, r, tmp8);
  217. #else // USE_STIMMER
  218. uint32_t t = n;
  219. n = (n >> 1) + (n >> 2);
  220. n = n + (n >> 4);
  221. n = n + (n >> 8);
  222. n = n + (n >> 16);
  223. n = n >> 3;
  224. uint8_t r = t - (((n << 2) + n) << 1);
  225. if (r > 9) {
  226. n++;
  227. r -= 10;
  228. }
  229. #endif // USE_STIMMER
  230. *--p = r + '0';
  231. }
  232. return fmtDec((uint16_t)n, p);
  233. }
  234. //------------------------------------------------------------------------------
  235. char* fmtFloat(float value, char* p, uint8_t prec) {
  236. char sign = value < 0 ? '-' : 0;
  237. if (sign) {
  238. value = -value;
  239. }
  240. if (isnan(value)) {
  241. *--p = 'n';
  242. *--p = 'a';
  243. *--p = 'n';
  244. return p;
  245. }
  246. if (isinf(value)) {
  247. *--p = 'f';
  248. *--p = 'n';
  249. *--p = 'i';
  250. return p;
  251. }
  252. if (value > 4294967040.0) {
  253. *--p = 'f';
  254. *--p = 'v';
  255. *--p = 'o';
  256. return p;
  257. }
  258. if (prec > 9) {
  259. prec = 9;
  260. }
  261. value += scale10(0.5, -prec);
  262. uint32_t whole = value;
  263. if (prec) {
  264. char* tmp = p - prec;
  265. uint32_t fraction = scale10(value - whole, prec);
  266. p = fmtDec(fraction, p);
  267. while (p > tmp) {
  268. *--p = '0';
  269. }
  270. *--p = '.';
  271. }
  272. p = fmtDec(whole, p);
  273. if (sign) {
  274. *--p = sign;
  275. }
  276. return p;
  277. }
  278. //------------------------------------------------------------------------------
  279. /** Print a number followed by a field terminator.
  280. * \param[in] value The number to be printed.
  281. * \param[in] ptr Pointer to last char in buffer.
  282. * \param[in] prec Number of digits after decimal point.
  283. * \param[in] expChar Use exp format if non zero.
  284. * \return Pointer to first character of result.
  285. */
  286. char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
  287. bool neg = value < 0;
  288. if (neg) {
  289. value = -value;
  290. }
  291. // check for nan inf ovf
  292. if (isnan(value)) {
  293. *--ptr = 'n';
  294. *--ptr = 'a';
  295. *--ptr = 'n';
  296. return ptr;
  297. }
  298. if (isinf(value)) {
  299. *--ptr = 'f';
  300. *--ptr = 'n';
  301. *--ptr = 'i';
  302. return ptr;
  303. }
  304. if (!expChar && value > 4294967040.0) {
  305. *--ptr = 'f';
  306. *--ptr = 'v';
  307. *--ptr = 'o';
  308. return ptr;
  309. }
  310. if (prec > 9) {
  311. prec = 9;
  312. }
  313. float round = scale10(0.5, -prec);
  314. if (expChar) {
  315. int8_t exp = 0;
  316. bool expNeg = false;
  317. if (value) {
  318. while (value > 10.0) {
  319. value *= 0.1;
  320. exp++;
  321. }
  322. while (value < 1.0) {
  323. value *= 10.0;
  324. exp--;
  325. }
  326. value += round;
  327. if (value > 10.0) {
  328. value *= 0.1;
  329. exp++;
  330. }
  331. expNeg = exp < 0;
  332. if (expNeg) {
  333. exp = -exp;
  334. }
  335. }
  336. ptr = fmtDec((uint16_t)exp, ptr);
  337. if (exp < 10) {
  338. *--ptr = '0';
  339. }
  340. *--ptr = expNeg ? '-' : '+';
  341. *--ptr = expChar;
  342. } else {
  343. // round value
  344. value += round;
  345. }
  346. uint32_t whole = value;
  347. if (prec) {
  348. char* tmp = ptr - prec;
  349. uint32_t fraction = scale10(value - whole, prec);
  350. ptr = fmtDec(fraction, ptr);
  351. while (ptr > tmp) {
  352. *--ptr = '0';
  353. }
  354. *--ptr = '.';
  355. }
  356. ptr = fmtDec(whole, ptr);
  357. if (neg) {
  358. *--ptr = '-';
  359. }
  360. return ptr;
  361. }
  362. //------------------------------------------------------------------------------
  363. char* fmtHex(uint32_t n, char* p) {
  364. do {
  365. uint8_t h = n & 0XF;
  366. *--p = h + (h < 10 ? '0' : 'A' - 10);
  367. n >>= 4;
  368. } while (n);
  369. return p;
  370. }
  371. //------------------------------------------------------------------------------
  372. float scanFloat(const char* str, char** ptr) {
  373. int16_t const EXP_LIMIT = 100;
  374. bool digit = false;
  375. bool dot = false;
  376. uint32_t fract = 0;
  377. int fracExp = 0;
  378. uint8_t nd = 0;
  379. bool neg;
  380. int c;
  381. float v;
  382. const char* successPtr = str;
  383. if (ptr) {
  384. *ptr = const_cast<char*>(str);
  385. }
  386. while (isSpace((c = *str++))) {}
  387. neg = c == '-';
  388. if (c == '-' || c == '+') {
  389. c = *str++;
  390. }
  391. // Skip leading zeros
  392. while (c == '0') {
  393. c = *str++;
  394. digit = true;
  395. }
  396. for (;;) {
  397. if (isDigit(c)) {
  398. digit = true;
  399. if (nd < 9) {
  400. fract = 10*fract + c - '0';
  401. nd++;
  402. if (dot) {
  403. fracExp--;
  404. }
  405. } else {
  406. if (!dot) {
  407. fracExp++;
  408. }
  409. }
  410. } else if (c == '.') {
  411. if (dot) {
  412. goto fail;
  413. }
  414. dot = true;
  415. } else {
  416. if (!digit) {
  417. goto fail;
  418. }
  419. break;
  420. }
  421. successPtr = str;
  422. c = *str++;
  423. }
  424. if (c == 'e' || c == 'E') {
  425. int exp = 0;
  426. c = *str++;
  427. bool expNeg = c == '-';
  428. if (c == '-' || c == '+') {
  429. c = *str++;
  430. }
  431. while (isDigit(c)) {
  432. if (exp > EXP_LIMIT) {
  433. goto fail;
  434. }
  435. exp = 10*exp + c - '0';
  436. successPtr = str;
  437. c = *str++;
  438. }
  439. fracExp += expNeg ? -exp : exp;
  440. }
  441. if (ptr) {
  442. *ptr = const_cast<char*>(successPtr);
  443. }
  444. v = scale10(static_cast<float>(fract), fracExp);
  445. return neg ? -v : v;
  446. fail:
  447. return 0;
  448. }