You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

336 line
9.1 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cppunit/extensions/HelperMacros.h>
  14. #include <cppunit/TestCaller.h>
  15. #include <cppunit/TestCase.h>
  16. #include <cppunit/TestSuite.h>
  17. #include <cmath>
  18. #include "core.h"
  19. /* Ensure isnan() is present even on systems that don't define it, or
  20. * when -ffast-math is being used. */
  21. #if defined __FAST_MATH__
  22. # undef isnan
  23. #endif
  24. #if !defined isnan
  25. static inline int isnan(float f)
  26. {
  27. union { float f; uint32_t x; } u = { f };
  28. return (u.x << 1) > 0xff000000u;
  29. }
  30. #endif
  31. namespace lol
  32. {
  33. class HalfTest : public CppUnit::TestCase
  34. {
  35. CPPUNIT_TEST_SUITE(HalfTest);
  36. CPPUNIT_TEST(test_half_from_float);
  37. CPPUNIT_TEST(test_half_makeaccurate);
  38. CPPUNIT_TEST(test_half_makebits);
  39. CPPUNIT_TEST(test_half_is_nan);
  40. CPPUNIT_TEST(test_half_is_inf);
  41. CPPUNIT_TEST(test_half_is_finite);
  42. CPPUNIT_TEST(test_half_is_normal);
  43. CPPUNIT_TEST(test_half_classify);
  44. CPPUNIT_TEST(test_half_to_float);
  45. CPPUNIT_TEST(test_half_to_int);
  46. CPPUNIT_TEST(test_float_op_half);
  47. CPPUNIT_TEST(test_half_op_float);
  48. CPPUNIT_TEST_SUITE_END();
  49. public:
  50. HalfTest() : CppUnit::TestCase("Matrix Test") {}
  51. void setUp()
  52. {
  53. }
  54. void tearDown() {}
  55. void test_half_from_float()
  56. {
  57. for (size_t i = 0; i < sizeof(pairs) / sizeof(*pairs); i++)
  58. {
  59. half a = (half)pairs[i].f;
  60. uint16_t b = pairs[i].x;
  61. CPPUNIT_ASSERT_EQUAL(a.bits, b);
  62. }
  63. }
  64. void test_half_makeaccurate()
  65. {
  66. for (size_t i = 0; i < sizeof(pairs) / sizeof(*pairs); i++)
  67. {
  68. half a = half::makeaccurate(pairs[i].f);
  69. uint16_t b = pairs[i].x;
  70. CPPUNIT_ASSERT_EQUAL(a.bits, b);
  71. }
  72. }
  73. void test_half_makebits()
  74. {
  75. for (unsigned int i = 0; i < 0x10000; i++)
  76. {
  77. half a = half::makebits(i);
  78. uint16_t b = i;
  79. CPPUNIT_ASSERT_EQUAL(a.bits, b);
  80. }
  81. }
  82. void test_half_is_nan()
  83. {
  84. CPPUNIT_ASSERT(half::makebits(0x7c01).is_nan());
  85. CPPUNIT_ASSERT(half::makebits(0xfc01).is_nan());
  86. CPPUNIT_ASSERT(half::makebits(0x7e00).is_nan());
  87. CPPUNIT_ASSERT(half::makebits(0xfe00).is_nan());
  88. CPPUNIT_ASSERT(!half::makebits(0x7c00).is_nan());
  89. CPPUNIT_ASSERT(!half::makebits(0xfc00).is_nan());
  90. CPPUNIT_ASSERT(!half(0.0f).is_nan());
  91. CPPUNIT_ASSERT(!half(-0.0f).is_nan());
  92. CPPUNIT_ASSERT(!half(2.0f).is_nan());
  93. CPPUNIT_ASSERT(!half(-2.0f).is_nan());
  94. }
  95. void test_half_is_inf()
  96. {
  97. CPPUNIT_ASSERT(half(65536.0f).is_inf());
  98. CPPUNIT_ASSERT(half(-65536.0f).is_inf());
  99. CPPUNIT_ASSERT(!half(0.0f).is_inf());
  100. CPPUNIT_ASSERT(!half(-0.0f).is_inf());
  101. CPPUNIT_ASSERT(!half(65535.0f).is_inf());
  102. CPPUNIT_ASSERT(!half(-65535.0f).is_inf());
  103. CPPUNIT_ASSERT(half::makebits(0x7c00).is_inf());
  104. CPPUNIT_ASSERT(half::makebits(0xfc00).is_inf());
  105. CPPUNIT_ASSERT(!half::makebits(0x7e00).is_inf());
  106. CPPUNIT_ASSERT(!half::makebits(0xfe00).is_inf());
  107. }
  108. void test_half_is_finite()
  109. {
  110. CPPUNIT_ASSERT(half(0.0f).is_finite());
  111. CPPUNIT_ASSERT(half(-0.0f).is_finite());
  112. CPPUNIT_ASSERT(half(65535.0f).is_finite());
  113. CPPUNIT_ASSERT(half(-65535.0f).is_finite());
  114. CPPUNIT_ASSERT(!half(65536.0f).is_finite());
  115. CPPUNIT_ASSERT(!half(-65536.0f).is_finite());
  116. CPPUNIT_ASSERT(!half::makebits(0x7c00).is_finite());
  117. CPPUNIT_ASSERT(!half::makebits(0xfc00).is_finite());
  118. CPPUNIT_ASSERT(!half::makebits(0x7e00).is_finite());
  119. CPPUNIT_ASSERT(!half::makebits(0xfe00).is_finite());
  120. }
  121. void test_half_is_normal()
  122. {
  123. CPPUNIT_ASSERT(half(0.0f).is_normal());
  124. CPPUNIT_ASSERT(half(-0.0f).is_normal());
  125. CPPUNIT_ASSERT(half(65535.0f).is_normal());
  126. CPPUNIT_ASSERT(half(-65535.0f).is_normal());
  127. CPPUNIT_ASSERT(!half(65536.0f).is_normal());
  128. CPPUNIT_ASSERT(!half(-65536.0f).is_normal());
  129. CPPUNIT_ASSERT(!half::makebits(0x7c00).is_normal());
  130. CPPUNIT_ASSERT(!half::makebits(0xfc00).is_normal());
  131. CPPUNIT_ASSERT(!half::makebits(0x7e00).is_normal());
  132. CPPUNIT_ASSERT(!half::makebits(0xfe00).is_normal());
  133. }
  134. void test_half_classify()
  135. {
  136. for (uint32_t i = 0; i < 0x10000; i++)
  137. {
  138. half h = half::makebits(i);
  139. if (h.is_nan())
  140. {
  141. CPPUNIT_ASSERT(!h.is_inf());
  142. CPPUNIT_ASSERT(!h.is_normal());
  143. CPPUNIT_ASSERT(!h.is_finite());
  144. }
  145. else if (h.is_inf())
  146. {
  147. CPPUNIT_ASSERT(!h.is_normal());
  148. CPPUNIT_ASSERT(!h.is_finite());
  149. }
  150. else
  151. {
  152. CPPUNIT_ASSERT(h.is_finite());
  153. }
  154. }
  155. }
  156. void test_half_to_float()
  157. {
  158. for (size_t i = 0; i < sizeof(pairs) / sizeof(*pairs); i++)
  159. {
  160. float a = (float)half::makebits(pairs[i].x);
  161. float b = pairs[i].f;
  162. CPPUNIT_ASSERT_EQUAL(a, b);
  163. }
  164. for (uint32_t i = 0; i < 0x10000; i++)
  165. {
  166. half h = half::makebits(i);
  167. float f = (float)h;
  168. half g = (half)f;
  169. if (h.is_nan())
  170. {
  171. CPPUNIT_ASSERT(isnan(f));
  172. CPPUNIT_ASSERT(g.is_nan());
  173. }
  174. else
  175. {
  176. CPPUNIT_ASSERT(!isnan(f));
  177. CPPUNIT_ASSERT_EQUAL(g.bits, h.bits);
  178. }
  179. }
  180. }
  181. void test_half_to_int()
  182. {
  183. CPPUNIT_ASSERT_EQUAL((int)(half)(0.0f), 0);
  184. CPPUNIT_ASSERT_EQUAL((int)(half)(-0.0f), 0);
  185. CPPUNIT_ASSERT_EQUAL((int)(half)(0.9f), 0);
  186. CPPUNIT_ASSERT_EQUAL((int)(half)(-0.9f), 0);
  187. CPPUNIT_ASSERT_EQUAL((int)(half)(1.0f), 1);
  188. CPPUNIT_ASSERT_EQUAL((int)(half)(-1.0f), -1);
  189. CPPUNIT_ASSERT_EQUAL((int)(half)(1.9f), 1);
  190. CPPUNIT_ASSERT_EQUAL((int)(half)(-1.9f), -1);
  191. CPPUNIT_ASSERT_EQUAL((int)(half)(65504.0f), 65504);
  192. CPPUNIT_ASSERT_EQUAL((int)(half)(-65504.0f), -65504);
  193. }
  194. void test_float_op_half()
  195. {
  196. half zero = 0;
  197. half one = 1;
  198. half two = 2;
  199. float a = zero + one;
  200. CPPUNIT_ASSERT_EQUAL(1.0f, a);
  201. a += zero;
  202. CPPUNIT_ASSERT_EQUAL(1.0f, a);
  203. a -= zero;
  204. CPPUNIT_ASSERT_EQUAL(1.0f, a);
  205. a *= one;
  206. CPPUNIT_ASSERT_EQUAL(1.0f, a);
  207. a /= one;
  208. CPPUNIT_ASSERT_EQUAL(1.0f, a);
  209. float b = one + zero;
  210. CPPUNIT_ASSERT_EQUAL(1.0f, b);
  211. b += one;
  212. CPPUNIT_ASSERT_EQUAL(2.0f, b);
  213. b *= two;
  214. CPPUNIT_ASSERT_EQUAL(4.0f, b);
  215. b -= two;
  216. CPPUNIT_ASSERT_EQUAL(2.0f, b);
  217. b /= two;
  218. CPPUNIT_ASSERT_EQUAL(1.0f, b);
  219. float c = one - zero;
  220. CPPUNIT_ASSERT_EQUAL(1.0f, c);
  221. float d = two - one;
  222. CPPUNIT_ASSERT_EQUAL(1.0f, d);
  223. float e = two + (-one);
  224. CPPUNIT_ASSERT_EQUAL(1.0f, e);
  225. float f = (two * two) / (one + one);
  226. CPPUNIT_ASSERT_EQUAL(2.0f, f);
  227. }
  228. void test_half_op_float()
  229. {
  230. half zero = 0;
  231. half one = 1;
  232. half two = 2;
  233. half four = 4;
  234. half a = one + 0.0f;
  235. CPPUNIT_ASSERT_EQUAL(one.bits, a.bits);
  236. a += 0.0f;
  237. CPPUNIT_ASSERT_EQUAL(one.bits, a.bits);
  238. a -= 0.0f;
  239. CPPUNIT_ASSERT_EQUAL(one.bits, a.bits);
  240. a *= 1.0f;
  241. CPPUNIT_ASSERT_EQUAL(one.bits, a.bits);
  242. a /= 1.0f;
  243. CPPUNIT_ASSERT_EQUAL(one.bits, a.bits);
  244. half b = one + 0.0f;
  245. CPPUNIT_ASSERT_EQUAL(one.bits, b.bits);
  246. b += 1.0f;
  247. CPPUNIT_ASSERT_EQUAL(two.bits, b.bits);
  248. b *= 2.0f;
  249. CPPUNIT_ASSERT_EQUAL(four.bits, b.bits);
  250. b -= 2.0f;
  251. CPPUNIT_ASSERT_EQUAL(two.bits, b.bits);
  252. b /= 2.0f;
  253. CPPUNIT_ASSERT_EQUAL(one.bits, b.bits);
  254. half c = 1.0f - zero;
  255. CPPUNIT_ASSERT_EQUAL(one.bits, c.bits);
  256. half d = 2.0f - one;
  257. CPPUNIT_ASSERT_EQUAL(one.bits, d.bits);
  258. half e = 2.0f + (-one);
  259. CPPUNIT_ASSERT_EQUAL(one.bits, e.bits);
  260. half f = (2.0f * two) / (1.0f + one);
  261. CPPUNIT_ASSERT_EQUAL(two.bits, f.bits);
  262. }
  263. private:
  264. struct TestPair { float f; uint16_t x; };
  265. static TestPair const pairs[11];
  266. };
  267. HalfTest::TestPair const HalfTest::pairs[] =
  268. {
  269. /* All these values have exact half representations */
  270. { 0.0f, 0x0000 },
  271. { -0.0f, 0x8000 }, /* negative zero */
  272. { 1.0f, 0x3c00 },
  273. { -1.0f, 0xbc00 },
  274. { 2.0f, 0x4000 },
  275. { 0.5f, 0x3800 },
  276. { 0.125f, 0x3000 },
  277. { 15.9375f, 0x4bf8 },
  278. { 0x1.fp-10, 0x17c0 },
  279. { 0x1.fp-14, 0x07c0 }, /* denormal */
  280. { 0x1.fp-15, 0x03e0 }, /* denormal */
  281. };
  282. CPPUNIT_TEST_SUITE_REGISTRATION(HalfTest);
  283. } /* namespace lol */