Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
10 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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) {
  170. v *= pgm_read_float(&s[i]);
  171. }
  172. #else // __AVR__
  173. if (n & 1) {
  174. v *= s[i];
  175. }
  176. #endif // __AVR__
  177. }
  178. return v;
  179. }
  180. //------------------------------------------------------------------------------
  181. // Format 16-bit unsigned
  182. char* fmtDec(uint16_t n, char* p) {
  183. while (n > 9) {
  184. #ifdef USE_STIMMER
  185. uint8_t tmp8, r;
  186. divmod10_asm16(n, r, tmp8);
  187. #else // USE_STIMMER
  188. uint16_t t = n;
  189. n = (n >> 1) + (n >> 2);
  190. n = n + (n >> 4);
  191. n = n + (n >> 8);
  192. // n = n + (n >> 16); // no code for 16-bit n
  193. n = n >> 3;
  194. uint8_t r = t - (((n << 2) + n) << 1);
  195. if (r > 9) {
  196. n++;
  197. r -= 10;
  198. }
  199. #endif // USE_STIMMER
  200. *--p = r + '0';
  201. }
  202. *--p = n + '0';
  203. return p;
  204. }
  205. //------------------------------------------------------------------------------
  206. // format 32-bit unsigned
  207. char* fmtDec(uint32_t n, char* p) {
  208. while (n >> 16) {
  209. #ifdef USE_STIMMER
  210. uint8_t tmp8, r;
  211. divmod10_asm32(n, r, tmp8);
  212. #else // USE_STIMMER
  213. uint32_t t = n;
  214. n = (n >> 1) + (n >> 2);
  215. n = n + (n >> 4);
  216. n = n + (n >> 8);
  217. n = n + (n >> 16);
  218. n = n >> 3;
  219. uint8_t r = t - (((n << 2) + n) << 1);
  220. if (r > 9) {
  221. n++;
  222. r -= 10;
  223. }
  224. #endif // USE_STIMMER
  225. *--p = r + '0';
  226. }
  227. return fmtDec((uint16_t)n, p);
  228. }
  229. //------------------------------------------------------------------------------
  230. char* fmtFloat(float value, char* p, uint8_t prec) {
  231. char sign = value < 0 ? '-' : 0;
  232. if (sign) {
  233. value = -value;
  234. }
  235. if (isnan(value)) {
  236. *--p = 'n';
  237. *--p = 'a';
  238. *--p = 'n';
  239. return p;
  240. }
  241. if (isinf(value)) {
  242. *--p = 'f';
  243. *--p = 'n';
  244. *--p = 'i';
  245. return p;
  246. }
  247. if (value > 4294967040.0) {
  248. *--p = 'f';
  249. *--p = 'v';
  250. *--p = 'o';
  251. return p;
  252. }
  253. if (prec > 9) {
  254. prec = 9;
  255. }
  256. value += scale10(0.5, -prec);
  257. uint32_t whole = value;
  258. if (prec) {
  259. char* tmp = p - prec;
  260. uint32_t fraction = scale10(value - whole, prec);
  261. p = fmtDec(fraction, p);
  262. while (p > tmp) {
  263. *--p = '0';
  264. }
  265. *--p = '.';
  266. }
  267. p = fmtDec(whole, p);
  268. if (sign) {
  269. *--p = sign;
  270. }
  271. return p;
  272. }
  273. //------------------------------------------------------------------------------
  274. /** Print a number followed by a field terminator.
  275. * \param[in] value The number to be printed.
  276. * \param[in] ptr Pointer to last char in buffer.
  277. * \param[in] prec Number of digits after decimal point.
  278. * \param[in] expChar Use exp format if non zero.
  279. * \return Pointer to first character of result.
  280. */
  281. char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
  282. bool neg = value < 0;
  283. if (neg) {
  284. value = -value;
  285. }
  286. // check for nan inf ovf
  287. if (isnan(value)) {
  288. *--ptr = 'n';
  289. *--ptr = 'a';
  290. *--ptr = 'n';
  291. return ptr;
  292. }
  293. if (isinf(value)) {
  294. *--ptr = 'f';
  295. *--ptr = 'n';
  296. *--ptr = 'i';
  297. return ptr;
  298. }
  299. if (!expChar && value > 4294967040.0) {
  300. *--ptr = 'f';
  301. *--ptr = 'v';
  302. *--ptr = 'o';
  303. return ptr;
  304. }
  305. if (prec > 9) {
  306. prec = 9;
  307. }
  308. float round = scale10(0.5, -prec);
  309. if (expChar) {
  310. int8_t exp = 0;
  311. bool expNeg = false;
  312. if (value) {
  313. while (value > 10.0) {
  314. value *= 0.1;
  315. exp++;
  316. }
  317. while (value < 1.0) {
  318. value *= 10.0;
  319. exp--;
  320. }
  321. value += round;
  322. if (value > 10.0) {
  323. value *= 0.1;
  324. exp++;
  325. }
  326. expNeg = exp < 0;
  327. if (expNeg) {
  328. exp = -exp;
  329. }
  330. }
  331. ptr = fmtDec((uint16_t)exp, ptr);
  332. if (exp < 10) {
  333. *--ptr = '0';
  334. }
  335. *--ptr = expNeg ? '-' : '+';
  336. *--ptr = expChar;
  337. } else {
  338. // round value
  339. value += round;
  340. }
  341. uint32_t whole = value;
  342. if (prec) {
  343. char* tmp = ptr - prec;
  344. uint32_t fraction = scale10(value - whole, prec);
  345. ptr = fmtDec(fraction, ptr);
  346. while (ptr > tmp) {
  347. *--ptr = '0';
  348. }
  349. *--ptr = '.';
  350. }
  351. ptr = fmtDec(whole, ptr);
  352. if (neg) {
  353. *--ptr = '-';
  354. }
  355. return ptr;
  356. }
  357. //------------------------------------------------------------------------------
  358. char* fmtHex(uint32_t n, char* p) {
  359. do {
  360. uint8_t h = n & 0XF;
  361. *--p = h + (h < 10 ? '0' : 'A' - 10);
  362. n >>= 4;
  363. } while (n);
  364. return p;
  365. }
  366. //------------------------------------------------------------------------------
  367. float scanFloat(const char* str, char** ptr) {
  368. int16_t const EXP_LIMIT = 100;
  369. bool digit = false;
  370. bool dot = false;
  371. uint32_t fract = 0;
  372. int fracExp = 0;
  373. uint8_t nd = 0;
  374. bool neg;
  375. int c;
  376. float v;
  377. const char* successPtr = str;
  378. if (ptr) {
  379. *ptr = const_cast<char*>(str);
  380. }
  381. while (isSpace((c = *str++))) {}
  382. neg = c == '-';
  383. if (c == '-' || c == '+') {
  384. c = *str++;
  385. }
  386. // Skip leading zeros
  387. while (c == '0') {
  388. c = *str++;
  389. digit = true;
  390. }
  391. for (;;) {
  392. if (isDigit(c)) {
  393. digit = true;
  394. if (nd < 9) {
  395. fract = 10*fract + c - '0';
  396. nd++;
  397. if (dot) {
  398. fracExp--;
  399. }
  400. } else {
  401. if (!dot) {
  402. fracExp++;
  403. }
  404. }
  405. } else if (c == '.') {
  406. if (dot) {
  407. goto fail;
  408. }
  409. dot = true;
  410. } else {
  411. if (!digit) {
  412. goto fail;
  413. }
  414. break;
  415. }
  416. successPtr = str;
  417. c = *str++;
  418. }
  419. if (c == 'e' || c == 'E') {
  420. int exp = 0;
  421. c = *str++;
  422. bool expNeg = c == '-';
  423. if (c == '-' || c == '+') {
  424. c = *str++;
  425. }
  426. while (isDigit(c)) {
  427. if (exp > EXP_LIMIT) {
  428. goto fail;
  429. }
  430. exp = 10*exp + c - '0';
  431. successPtr = str;
  432. c = *str++;
  433. }
  434. fracExp += expNeg ? -exp : exp;
  435. }
  436. if (ptr) {
  437. *ptr = const_cast<char*>(successPtr);
  438. }
  439. v = scale10(static_cast<float>(fract), fracExp);
  440. return neg ? -v : v;
  441. fail:
  442. return 0;
  443. }