/labWeb/LabWeb/ftoa.c

http://github.com/meshula/LabWeb · C · 253 lines · 196 code · 42 blank · 15 comment · 59 complexity · 39a409ca059a453b7401970a4ec3e190 MD5 · raw file

  1. /*
  2. Copyright (c) 2009 NetAllied Systems GmbH
  3. This file is part of Common libftoa.
  4. Licensed under the MIT Open Source License,
  5. for details please see LICENSE file or the website
  6. http://www.opensource.org/licenses/mit-license.php
  7. */
  8. #include "ftoa.h"
  9. #include "itoa.h"
  10. #include <float.h>
  11. #include <stdbool.h>
  12. #include <math.h>
  13. typedef union {
  14. long L;
  15. float F;
  16. } LF_t;
  17. _Bool isPositiveInfinity(float v)
  18. {
  19. LF_t x;
  20. x.F = v;
  21. return x.L == 0x7F800000L;
  22. }
  23. _Bool isNegativeInfinity(float v)
  24. {
  25. LF_t x;
  26. x.F = v;
  27. return x.L == (long)0xFF800000L;
  28. }
  29. _Bool isNaN(float v)
  30. {
  31. return v!=v;
  32. }
  33. float roundingSummand(float f, int maxLength, int* dezmialPointPos)
  34. {
  35. float fabs = abs(f);
  36. *dezmialPointPos = 0;
  37. if ( fabs < 0.00001 )
  38. *dezmialPointPos = -6;
  39. else if ( fabs < 0.0001 )
  40. *dezmialPointPos = -5;
  41. else if ( fabs < 0.001 )
  42. *dezmialPointPos = -4;
  43. else if ( fabs < 0.01 )
  44. *dezmialPointPos = -3;
  45. else if ( fabs < 0.1 )
  46. *dezmialPointPos = -2;
  47. else if ( fabs < 1 )
  48. *dezmialPointPos = -1;
  49. else if ( fabs < 10 )
  50. *dezmialPointPos = 0;
  51. else if ( fabs < 100 )
  52. *dezmialPointPos = 1;
  53. else if ( fabs < 1000 )
  54. *dezmialPointPos = 2;
  55. else if ( fabs < 10000 )
  56. *dezmialPointPos = 3;
  57. else if ( fabs < 100000 )
  58. *dezmialPointPos = 4;
  59. else if ( fabs < 1000000 )
  60. *dezmialPointPos = 5;
  61. static const float roundingSummands[] = { 0.5e-11f, // < 0.00001
  62. 0.5e-10f, // 0.00001 - 0.0001
  63. 0.5e-9f, // 0.0001 - 0.001
  64. 0.5e-8f, // 0.001 - 0.01
  65. 0.5e-7f, // 0.01 - 0.1
  66. 0.5e-6f, // 0.1 - 1
  67. 0.5e-5f, // 1 - 10 : 0.000005
  68. 0.5e-4f, // 10 - 100
  69. 0.5e-3f, // 100 - 1000
  70. 0.5e-2f, // 1000 - 10000
  71. 0.5e-1f, // 10000 - 100000
  72. 0.5e0f, // 100000 - 1000000
  73. };
  74. float rS = roundingSummands[*dezmialPointPos + 12 - maxLength];
  75. return (f > 0) ? rS : -rS;
  76. }
  77. char* ftoa_no_exponent(float f, char* buffer, int maxLength)
  78. {
  79. long mantissa, int_part, frac_part;
  80. short exp2;
  81. LF_t x;
  82. char *p = buffer;
  83. int dezmialPointPos = 0;
  84. float rS = roundingSummand(f, maxLength, &dezmialPointPos);
  85. if ( dezmialPointPos < 0 )
  86. {
  87. maxLength = maxLength - dezmialPointPos;
  88. }
  89. x.F = f + rS;
  90. exp2 = (unsigned char)(x.L >> 23) - 127;
  91. mantissa = (x.L & 0xFFFFFF) | 0x800000;
  92. frac_part = 0;
  93. int_part = 0;
  94. // handle numbers in non exponential representation
  95. if (exp2 >= 23)
  96. int_part = mantissa << (exp2 - 23);
  97. else if (exp2 >= 0)
  98. {
  99. int_part = mantissa >> (23 - exp2);
  100. frac_part = (mantissa << (exp2 + 1)) & 0xFFFFFF;
  101. }
  102. else /* if (exp2 < 0) */
  103. frac_part = (mantissa & 0xFFFFFF) >> -(exp2 + 1);
  104. p = buffer;
  105. if (x.L < 0)
  106. {
  107. *p++ = '-';
  108. maxLength++;
  109. }
  110. if (int_part == 0)
  111. *p++ = '0';
  112. else
  113. {
  114. size_t bytesWritten = itoa( int_part, p, 10);
  115. p += bytesWritten;
  116. }
  117. char m = (char)(p - buffer);
  118. if ((frac_part != 0) && (maxLength > m))
  119. {
  120. *p++ = '.';
  121. char max;
  122. max = (char)(FTOA_BUFFER_SIZE - (p - buffer) - 1);
  123. if (max > maxLength)
  124. max = maxLength;
  125. /* print BCD */
  126. for (; m < max; m++)
  127. {
  128. /* frac_part *= 10; */
  129. frac_part *= 10;// (frac_part << 3) + (frac_part << 1);
  130. *p++ = (char)(frac_part >> 24) + '0';
  131. frac_part &= 0xFFFFFF;
  132. }
  133. /* delete ending zeros and decimal point if necessary */
  134. for (--p; p[0] == '0' ; --p)
  135. {
  136. if ( p[-1] == '.' )
  137. {
  138. p -= 2;
  139. break;
  140. }
  141. }
  142. if ( p[0] == '.' )
  143. {
  144. --p;
  145. }
  146. ++p;
  147. }
  148. return p;
  149. }
  150. int ftoa(float f, char* buffer)
  151. {
  152. static const float lowerLimitForNonExponetialNotation = 0.001f; // Positive numbers smaller will be expressed in exponential representation
  153. static const float upperLimitForNonExponetialNotation = 999999; // Positive numbers bigger will be expressed in exponential representation
  154. static const float negativeLowerLimitForNonExponetialNotation = -999999; // Negative numbers smaller will be expressed in exponential representation
  155. static const float negativeUpperLimitForNonExponetialNotation = -0.001f; // Negative numbers bigger will be expressed in exponential representation
  156. int exp10 = 0;
  157. char *p = 0;
  158. if (f == 0.0)
  159. {
  160. buffer[0] = '0';
  161. buffer[1] = 0;
  162. return 1;
  163. }
  164. else if ( isNaN(f) )
  165. {
  166. buffer[0] = 'N';
  167. buffer[1] = 'a';
  168. buffer[2] = 'N';
  169. buffer[3] = 0;
  170. return 3;
  171. }
  172. else if ( isPositiveInfinity(f) )
  173. {
  174. buffer[0] = 'I';
  175. buffer[1] = 'N';
  176. buffer[2] = 'F';
  177. buffer[3] = 0;
  178. return 3;
  179. }
  180. else if ( isNegativeInfinity(f) )
  181. {
  182. buffer[0] = '-';
  183. buffer[1] = 'I';
  184. buffer[2] = 'N';
  185. buffer[3] = 'F';
  186. buffer[4] = 0;
  187. return 4;
  188. }
  189. if ( ((f > 0) && ((f > upperLimitForNonExponetialNotation) || (f < lowerLimitForNonExponetialNotation)))
  190. || ((f < 0) && ((f > negativeUpperLimitForNonExponetialNotation) || (f < negativeLowerLimitForNonExponetialNotation))) )
  191. {
  192. // handle big numbers in exponential representation
  193. // we determine the exponent in exponential representation
  194. exp10 = (int)log10(f > 0 ? f : -f);
  195. if ( exp10 < 0)
  196. exp10--;
  197. float factor = pow((float)10, -exp10);
  198. p = ftoa_no_exponent(f*factor, buffer,6);
  199. *p++ = 'e';
  200. size_t bytesWritten = itoa( exp10, p, 10);
  201. p += bytesWritten;
  202. }
  203. else
  204. {
  205. p = ftoa_no_exponent(f, buffer,7);
  206. }
  207. *p = 0;
  208. return (int)(p - buffer);
  209. }