fast_atof.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // Copyright (C) 2008-2012 Colin MacDonald
  2. // No rights reserved: this software is in the public domain.
  3. #include "testUtils.h"
  4. using namespace irr;
  5. using namespace core;
  6. //! This was an older Irrlicht implementation, tested against for reference.
  7. static inline u32 old_strtol10(const char* in, const char** out=0)
  8. {
  9. u32 value = 0;
  10. while ( ( *in >= '0') && ( *in <= '9' ))
  11. {
  12. value = ( value * 10 ) + ( *in - '0' );
  13. ++in;
  14. }
  15. if (out)
  16. *out = in;
  17. return value;
  18. }
  19. //! This was an older Irrlicht implementation, tested against for reference.
  20. static inline const char* old_fast_atof_move( const char* c, float& out)
  21. {
  22. bool inv = false;
  23. const char *t;
  24. float f;
  25. if (*c=='-')
  26. {
  27. ++c;
  28. inv = true;
  29. }
  30. //f = (float)strtol(c, &t, 10);
  31. f = (float) old_strtol10 ( c, &c );
  32. if (*c == '.')
  33. {
  34. ++c;
  35. //float pl = (float)strtol(c, &t, 10);
  36. float pl = (float) old_strtol10 ( c, &t );
  37. pl *= fast_atof_table[t-c];
  38. f += pl;
  39. c = t;
  40. if (*c == 'e')
  41. {
  42. ++c;
  43. //float exp = (float)strtol(c, &t, 10);
  44. bool einv = (*c=='-');
  45. if (einv)
  46. ++c;
  47. float exp = (float)old_strtol10(c, &c);
  48. if (einv)
  49. exp *= -1.0f;
  50. f *= (float)pow(10.0f, exp);
  51. }
  52. }
  53. if (inv)
  54. f *= -1.0f;
  55. out = f;
  56. return c;
  57. }
  58. //! This was an older Irrlicht implementation, tested against for reference.
  59. static inline float old_fast_atof(const char* c)
  60. {
  61. float ret;
  62. old_fast_atof_move(c, ret);
  63. return ret;
  64. }
  65. static bool testCalculation_atof(const char * valueString)
  66. {
  67. const f32 newFastValue = fast_atof(valueString);
  68. const f32 oldFastValue = old_fast_atof(valueString);
  69. const f32 atofValue = (f32)atof(valueString);
  70. logTestString("\n String '%s'\n New fast %.40f\n Old fast %.40f\n atof %.40f\n",
  71. valueString, newFastValue, oldFastValue, atofValue);
  72. const f32 diffNew = fabs(newFastValue - atofValue) ;
  73. const f32 diffOld = fabs(oldFastValue - atofValue) ;
  74. bool accurate = diffNew <= diffOld || equalsByUlp(diffNew, diffOld, 1);
  75. if(!accurate)
  76. logTestString("*** ERROR - less accurate than old method ***\n\n");
  77. return accurate;
  78. }
  79. static bool testCalculation_strtol(const char * valueString)
  80. {
  81. const s32 newFastValue = strtol10(valueString);
  82. const s32 oldFastValue = old_strtol10(valueString);
  83. const s32 strtolValue = (s32)clamp(strtol(valueString, 0, 10), (long int)INT_MIN, (long int)INT_MAX);
  84. logTestString("\n String '%s'\n New fast %d\n Old fast %d\n strtol %d\n",
  85. valueString, newFastValue, oldFastValue, strtolValue);
  86. bool accurate = (newFastValue == strtolValue) || (oldFastValue != strtolValue);
  87. if (!accurate)
  88. logTestString("*** ERROR - wrong calculation in new method ***\n\n");
  89. return accurate;
  90. }
  91. //! Test both the accuracy and speed of Irrlicht's fast_atof() implementation.
  92. bool test_fast_atof(void)
  93. {
  94. bool accurate = true;
  95. accurate &= testCalculation_atof("340282346638528859811704183484516925440.000000");
  96. accurate &= testCalculation_atof("3.402823466e+38F");
  97. accurate &= testCalculation_atof("3402823466e+29F");
  98. accurate &= testCalculation_atof("-340282346638528859811704183484516925440.000000");
  99. accurate &= testCalculation_atof("-3.402823466e+38F");
  100. accurate &= testCalculation_atof("-3402823466e+29F");
  101. accurate &= testCalculation_atof("34028234663852885981170418348451692544.000000");
  102. accurate &= testCalculation_atof("3.402823466e+37F");
  103. accurate &= testCalculation_atof("3402823466e+28F");
  104. accurate &= testCalculation_atof("-34028234663852885981170418348451692544.000000");
  105. accurate &= testCalculation_atof("-3.402823466e+37F");
  106. accurate &= testCalculation_atof("-3402823466e+28F");
  107. accurate &= testCalculation_atof(".00234567");
  108. accurate &= testCalculation_atof("-.00234567");
  109. accurate &= testCalculation_atof("0.00234567");
  110. accurate &= testCalculation_atof("-0.00234567");
  111. accurate &= testCalculation_atof("1.175494351e-38F");
  112. accurate &= testCalculation_atof("1175494351e-47F");
  113. accurate &= testCalculation_atof("1.175494351e-37F");
  114. accurate &= testCalculation_atof("1.175494351e-36F");
  115. accurate &= testCalculation_atof("-1.175494351e-36F");
  116. accurate &= testCalculation_atof("123456.789");
  117. accurate &= testCalculation_atof("-123456.789");
  118. accurate &= testCalculation_atof("0000123456.789");
  119. accurate &= testCalculation_atof("-0000123456.789");
  120. accurate &= testCalculation_atof("-0.0690462109446526");
  121. accurate &= testCalculation_atof("0.11999999731779099"); // more numbers past dot than in lookup table
  122. accurate &= testCalculation_atof("0.119999997317790999");
  123. if (!accurate)
  124. {
  125. logTestString("Calculation is not accurate, so the speed is irrelevant\n");
  126. return false;
  127. }
  128. #ifndef _DEBUG // it's only faster in release
  129. IrrlichtDevice* device = createDevice(video::EDT_NULL);
  130. if (!device)
  131. return false;
  132. ITimer* timer = device->getTimer();
  133. const int ITERATIONS = 100000;
  134. int i;
  135. f32 value;
  136. u32 then = timer->getRealTime();
  137. for(i = 0; i < ITERATIONS; ++i)
  138. value = (f32)atof("-340282346638528859811704183484516925440.000000");
  139. const u32 atofTime = timer->getRealTime() - then;
  140. then += atofTime;
  141. for(i = 0; i < ITERATIONS; ++i)
  142. value = fast_atof("-340282346638528859811704183484516925440.000000");
  143. const u32 fastAtofTime = timer->getRealTime() - then;
  144. then += fastAtofTime;
  145. for(i = 0; i < ITERATIONS; ++i)
  146. value = old_fast_atof("-340282346638528859811704183484516925440.000000");
  147. const u32 oldFastAtofTime = timer->getRealTime() - then;
  148. logTestString("Speed test\n atof time = %d\n fast_atof Time = %d\nold fast_atof time = %d\n",
  149. atofTime, fastAtofTime, oldFastAtofTime);
  150. device->closeDevice();
  151. device->run();
  152. device->drop();
  153. if(fastAtofTime > (1.2f*atofTime))
  154. {
  155. logTestString("The fast method is slower than atof()\n");
  156. return false;
  157. }
  158. #endif // #ifndef _DEBUG
  159. return true;
  160. }
  161. //! Test both the accuracy and speed of Irrlicht's strtol10() implementation.
  162. bool test_strtol(void)
  163. {
  164. bool accurate = true;
  165. accurate &= testCalculation_strtol("340282346638528859811704183484516925440");
  166. accurate &= testCalculation_strtol("3402823466");
  167. accurate &= testCalculation_strtol("3402823466e+29F");
  168. accurate &= testCalculation_strtol("-340282346638528859811704183484516925440");
  169. accurate &= testCalculation_strtol("-3402823466");
  170. accurate &= testCalculation_strtol("-3402823466e+29F");
  171. accurate &= testCalculation_strtol("402823466385288598117");
  172. accurate &= testCalculation_strtol("402823466");
  173. accurate &= testCalculation_strtol("402823466e+28F");
  174. accurate &= testCalculation_strtol("402823466385288598117");
  175. accurate &= testCalculation_strtol("-402823466");
  176. accurate &= testCalculation_strtol("-402823466e+28F");
  177. accurate &= testCalculation_strtol(".00234567");
  178. accurate &= testCalculation_strtol("-234567");
  179. accurate &= testCalculation_strtol("234567");
  180. accurate &= testCalculation_strtol("-234567");
  181. accurate &= testCalculation_strtol("1175494351");
  182. accurate &= testCalculation_strtol("11754943512");
  183. accurate &= testCalculation_strtol("11754943513");
  184. accurate &= testCalculation_strtol("11754943514");
  185. accurate &= testCalculation_strtol("-1175494351");
  186. accurate &= testCalculation_strtol("123456789");
  187. accurate &= testCalculation_strtol("-123456789");
  188. accurate &= testCalculation_strtol("123456.789");
  189. accurate &= testCalculation_strtol("-123456.789");
  190. accurate &= testCalculation_strtol("-109446526");
  191. if(!accurate)
  192. {
  193. logTestString("Calculation is not accurate, so the speed is irrelevant\n");
  194. return false;
  195. }
  196. #ifndef _DEBUG // it's only faster in release
  197. IrrlichtDevice* device = createDevice(video::EDT_NULL);
  198. if (!device)
  199. return false;
  200. ITimer* timer = device->getTimer();
  201. const int ITERATIONS = 1000000;
  202. int i;
  203. s32 value;
  204. u32 then = timer->getRealTime();
  205. for(i = 0; i < ITERATIONS; ++i)
  206. value = strtol("-3402823466", 0, 10);
  207. const u32 strtolTime = timer->getRealTime() - then;
  208. then += strtolTime;
  209. for(i = 0; i < ITERATIONS; ++i)
  210. value = strtol10("-3402823466");
  211. const u32 strtol10Time = timer->getRealTime() - then;
  212. then += strtol10Time;
  213. for(i = 0; i < ITERATIONS; ++i)
  214. value = old_strtol10("-3402823466");
  215. const u32 oldstrtol10Time = timer->getRealTime() - then;
  216. logTestString("Speed test\n strtol time = %d\n strtol10 time = %d\nold strtol10 time = %d\n",
  217. strtolTime, strtol10Time, oldstrtol10Time);
  218. device->closeDevice();
  219. device->run();
  220. device->drop();
  221. if (strtol10Time > (1.2f*strtolTime))
  222. {
  223. logTestString("The fast method is slower than strtol()\n");
  224. return false;
  225. }
  226. #endif // #ifndef _DEBUG
  227. return true;
  228. }
  229. bool fast_atof(void)
  230. {
  231. bool ok = true;
  232. ok &= test_fast_atof() ;
  233. ok &= test_strtol();
  234. return ok;
  235. }