Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

357 righe
10 KiB

  1. //
  2. // Lol Engine — Unit tests
  3. //
  4. // Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net>
  5. //
  6. // Lol Engine is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #include <lol/engine-internal.h>
  13. #include <lol/math/real.h>
  14. #include <lolunit.h>
  15. namespace lol
  16. {
  17. lolunit_declare_fixture(polynomial_test)
  18. {
  19. lolunit_declare_test(declaration)
  20. {
  21. polynomial<float> p;
  22. polynomial<real> q;
  23. }
  24. lolunit_declare_test(init)
  25. {
  26. polynomial<float> p { };
  27. lolunit_assert_equal(p[0], 0.f);
  28. lolunit_assert_equal(p[1], 0.f);
  29. lolunit_assert_equal(p[2], 0.f);
  30. lolunit_assert_equal(p.degree(), -1);
  31. polynomial<float> q { 1.f };
  32. lolunit_assert_equal(q[0], 1.f);
  33. lolunit_assert_equal(q[1], 0.f);
  34. lolunit_assert_equal(q[2], 0.f);
  35. lolunit_assert_equal(q.degree(), 0);
  36. polynomial<float> r { 1.f, 2.f };
  37. lolunit_assert_equal(r[0], 1.f);
  38. lolunit_assert_equal(r[1], 2.f);
  39. lolunit_assert_equal(r[2], 0.f);
  40. lolunit_assert_equal(r.degree(), 1);
  41. polynomial<float> s { 0.f };
  42. lolunit_assert_equal(s[0], 0.f);
  43. lolunit_assert_equal(s[1], 0.f);
  44. lolunit_assert_equal(s[2], 0.f);
  45. lolunit_assert_equal(s.degree(), -1);
  46. }
  47. lolunit_declare_test(derive)
  48. {
  49. polynomial<float> p {};
  50. p = p.derive();
  51. lolunit_assert_equal(p.degree(), -1);
  52. polynomial<float> q { 1.f };
  53. q = q.derive();
  54. lolunit_assert_equal(q.degree(), -1);
  55. polynomial<float> r { 1.f, 2.f };
  56. r = r.derive();
  57. lolunit_assert_equal(r.degree(), 0);
  58. lolunit_assert_equal(r[0], 2.f);
  59. polynomial<float> s { 1.f, 2.f, 3.f, 4.f };
  60. s = s.derive();
  61. lolunit_assert_equal(s.degree(), 2);
  62. lolunit_assert_equal(s[0], 2.f);
  63. lolunit_assert_equal(s[1], 6.f);
  64. lolunit_assert_equal(s[2], 12.f);
  65. }
  66. lolunit_declare_test(eval)
  67. {
  68. /* Special null polynomial */
  69. polynomial<float> p;
  70. float a = p.eval(42.f);
  71. lolunit_assert_equal(a, 0.f);
  72. }
  73. lolunit_declare_test(eval_degree_0)
  74. {
  75. /* Constant polynomial p(x) = 1 */
  76. polynomial<float> p { 1.f };
  77. float a = p.eval(42.f);
  78. lolunit_assert_equal(a, 1.f);
  79. }
  80. lolunit_declare_test(eval_degree_1)
  81. {
  82. /* p(x) = 1 + 2x */
  83. polynomial<float> p { 1.f, 2.f };
  84. float a = p.eval(0.f);
  85. lolunit_assert_equal(a, 1.f);
  86. float b = p.eval(1.f);
  87. lolunit_assert_equal(b, 3.f);
  88. float c = p.eval(2.f);
  89. lolunit_assert_equal(c, 5.f);
  90. }
  91. lolunit_declare_test(eval_degree_2)
  92. {
  93. /* p(x) = 1 + 2x + 3x² */
  94. polynomial<float> p { 1.f, 2.f, 3.f };
  95. float a = p.eval(0.f);
  96. lolunit_assert_equal(a, 1.f);
  97. float b = p.eval(1.f);
  98. lolunit_assert_equal(b, 6.f);
  99. float c = p.eval(2.f);
  100. lolunit_assert_equal(c, 17.f);
  101. }
  102. lolunit_declare_test(unary_plus_and_minus)
  103. {
  104. /* p(x) = 1 + 2x + 3x² */
  105. polynomial<float> p { 1.f, 2.f, 3.f };
  106. polynomial<float> q = +p;
  107. polynomial<float> r = -p;
  108. lolunit_assert_equal(q[0], 1.f);
  109. lolunit_assert_equal(q[1], 2.f);
  110. lolunit_assert_equal(q[2], 3.f);
  111. lolunit_assert_equal(r[0], -1.f);
  112. lolunit_assert_equal(r[1], -2.f);
  113. lolunit_assert_equal(r[2], -3.f);
  114. }
  115. lolunit_declare_test(addition)
  116. {
  117. /* p(x) = 1 + 2x + 3x² */
  118. /* q(x) = 4 + 5x */
  119. polynomial<float> p { 1.f, 2.f, 3.f };
  120. polynomial<float> q { 4.f, 5.f };
  121. /* r(x) = 5 + 7x + 3x² */
  122. polynomial<float> r = p + q;
  123. lolunit_assert_equal(r.degree(), 2);
  124. lolunit_assert_equal(r[0], 5.f);
  125. lolunit_assert_equal(r[1], 7.f);
  126. lolunit_assert_equal(r[2], 3.f);
  127. }
  128. lolunit_declare_test(subtraction)
  129. {
  130. /* p(x) = 1 + 2x + 3x² */
  131. /* q(x) = 4 + 5x */
  132. polynomial<float> p { 1.f, 2.f, 3.f };
  133. polynomial<float> q { 4.f, 5.f };
  134. /* r(x) = -3 + -3x + 3x² */
  135. polynomial<float> r = p - q;
  136. lolunit_assert_equal(r.degree(), 2);
  137. lolunit_assert_equal(r[0], -3.f);
  138. lolunit_assert_equal(r[1], -3.f);
  139. lolunit_assert_equal(r[2], 3.f);
  140. }
  141. lolunit_declare_test(multiplication)
  142. {
  143. /* p(x) = 1 + 2x + 3x² */
  144. /* q(x) = 4 + 5x */
  145. polynomial<float> p { 1.f, 2.f, 3.f };
  146. polynomial<float> q { 4.f, 5.f };
  147. /* r(x) = 4 + 13x + 22x² + 15x³ */
  148. polynomial<float> r = p * q;
  149. lolunit_assert_equal(r.degree(), 3);
  150. lolunit_assert_equal(r[0], 4.f);
  151. lolunit_assert_equal(r[1], 13.f);
  152. lolunit_assert_equal(r[2], 22.f);
  153. lolunit_assert_equal(r[3], 15.f);
  154. }
  155. lolunit_declare_test(division)
  156. {
  157. /* p(x) = -4 - 2x² + x³ */
  158. /* q(x) = -3 + x */
  159. polynomial<float> p { -4.f, 0.f, -2.f, 1.f };
  160. polynomial<float> q { -3.f, 1.f };
  161. /* p(x) = r(x) q(x) + s(x)
  162. * r(x) = 3 + x + x²
  163. * s(x) = 5 */
  164. auto r = p / q;
  165. lolunit_assert_equal(std::get<0>(r).degree(), 2);
  166. lolunit_assert_doubles_equal(std::get<0>(r)[0], 3.f, 1e-5f);
  167. lolunit_assert_doubles_equal(std::get<0>(r)[1], 1.f, 1e-5f);
  168. lolunit_assert_doubles_equal(std::get<0>(r)[2], 1.f, 1e-5f);
  169. lolunit_assert_equal(std::get<1>(r).degree(), 0);
  170. lolunit_assert_doubles_equal(std::get<1>(r)[0], 5.f, 1e-5f);
  171. }
  172. lolunit_declare_test(composition_degree_2_2)
  173. {
  174. /* p(x) = 1 + x² */
  175. polynomial<float> p({ 1, 0, 1 });
  176. /* q(x) = (p o p)(x) = 2 + 2x² + x⁴ */
  177. polynomial<float> q = p.eval(p);
  178. lolunit_assert_equal(q.degree(), 4);
  179. lolunit_assert_equal(q[0], 2.f);
  180. lolunit_assert_equal(q[1], 0.f);
  181. lolunit_assert_equal(q[2], 2.f);
  182. lolunit_assert_equal(q[3], 0.f);
  183. lolunit_assert_equal(q[4], 1.f);
  184. }
  185. lolunit_declare_test(composition_degree_2_3)
  186. {
  187. /* p(x) = 1 + x */
  188. polynomial<float> p({ 1, 1 });
  189. /* q(x) = 1 + x + x² */
  190. polynomial<float> q({ 1, 1, 1 });
  191. /* r(x) = (q o p)(x) = 3 + 3x + x² */
  192. polynomial<float> r = q.eval(p);
  193. lolunit_assert_equal(r.degree(), 2);
  194. lolunit_assert_equal(r[0], 3.f);
  195. lolunit_assert_equal(r[1], 3.f);
  196. lolunit_assert_equal(r[2], 1.f);
  197. }
  198. lolunit_declare_test(degree_0_root)
  199. {
  200. /* p(x) = 42 */
  201. polynomial<float> p { 42.f };
  202. auto roots = p.roots();
  203. lolunit_assert_equal(roots.size(), 0);
  204. }
  205. lolunit_declare_test(degree_1_root)
  206. {
  207. /* p(x) = -6 + 2x */
  208. polynomial<float> p { -6.f, 2.f };
  209. auto roots = p.roots();
  210. lolunit_assert_equal(roots.size(), 1);
  211. lolunit_assert_equal(roots[0], 3.f);
  212. }
  213. lolunit_declare_test(degree_2_root)
  214. {
  215. /* p(x) = 81 - 18x + x² */
  216. polynomial<float> p { 81.f, -18.f, 1.f };
  217. auto roots1 = p.roots();
  218. lolunit_assert_equal(roots1.size(), 1);
  219. lolunit_assert_equal(roots1[0], 9.f);
  220. /* p(x) = 42 - 20x + 2x² */
  221. polynomial<float> q { 42.f, -20.f, 2.f };
  222. auto roots2 = q.roots();
  223. lolunit_assert_equal(roots2.size(), 2);
  224. lolunit_assert_equal(roots2[0], 3.f);
  225. lolunit_assert_equal(roots2[1], 7.f);
  226. }
  227. lolunit_declare_test(degree_3_triple_root)
  228. {
  229. polynomial<float> p { 1.f, 3.f, 3.f, 1.f };
  230. auto roots1 = p.roots();
  231. lolunit_assert_equal(roots1.size(), 1);
  232. lolunit_assert_doubles_equal(roots1[0], -1, 0);
  233. }
  234. lolunit_declare_test(degree_3_double_root)
  235. {
  236. polynomial<float> p { 2.f, 5.f, 4.f, 1.f };
  237. auto roots1 = p.roots();
  238. // Should have 2 solutions only, but precision leads to 3 solutions
  239. lolunit_assert_equal(roots1.size(), 2);
  240. lolunit_assert_doubles_equal(roots1[0], -1, 1e-6);
  241. lolunit_assert_doubles_equal(roots1[1], -2, 1e-6);
  242. }
  243. lolunit_declare_test(degree_3_three_roots)
  244. {
  245. polynomial<float> p { 6.f, 11.f, 6.f, 1.f };
  246. auto roots1 = p.roots();
  247. lolunit_assert_equal(roots1.size(), 3);
  248. lolunit_assert_doubles_equal(roots1[0], -1, 1e-8);
  249. lolunit_assert_doubles_equal(roots1[1], -3, 1e-8);
  250. lolunit_assert_doubles_equal(roots1[2], -2, 1e-8);
  251. }
  252. lolunit_declare_test(degree_3_three_large_roots)
  253. {
  254. polynomial<float> p { -12000.f, 1000.f - 1200.f - 120.f, 100.f + 10.0f - 12.f, 1.f };
  255. auto roots1 = p.roots();
  256. lolunit_assert_equal(roots1.size(), 3);
  257. lolunit_assert_doubles_equal(roots1[0], 12, 1e-5);
  258. lolunit_assert_doubles_equal(roots1[1], -100, 1e-5);
  259. lolunit_assert_doubles_equal(roots1[2], -10, 1e-5);
  260. }
  261. lolunit_declare_test(chebyshev)
  262. {
  263. polynomial<float> t0 = polynomial<float>::chebyshev(0);
  264. polynomial<float> t1 = polynomial<float>::chebyshev(1);
  265. polynomial<float> t2 = polynomial<float>::chebyshev(2);
  266. polynomial<float> t3 = polynomial<float>::chebyshev(3);
  267. polynomial<float> t4 = polynomial<float>::chebyshev(4);
  268. /* Taken from the sequence at http://oeis.org/A028297 */
  269. lolunit_assert_equal(t0.degree(), 0);
  270. lolunit_assert_equal(t0[0], 1.f);
  271. lolunit_assert_equal(t1.degree(), 1);
  272. lolunit_assert_equal(t1[0], 0.f);
  273. lolunit_assert_equal(t1[1], 1.f);
  274. lolunit_assert_equal(t2.degree(), 2);
  275. lolunit_assert_equal(t2[0], -1.f);
  276. lolunit_assert_equal(t2[1], 0.f);
  277. lolunit_assert_equal(t2[2], 2.f);
  278. lolunit_assert_equal(t3.degree(), 3);
  279. lolunit_assert_equal(t3[0], 0.f);
  280. lolunit_assert_equal(t3[1], -3.f);
  281. lolunit_assert_equal(t3[2], 0.f);
  282. lolunit_assert_equal(t3[3], 4.f);
  283. lolunit_assert_equal(t4.degree(), 4);
  284. lolunit_assert_equal(t4[0], 1.f);
  285. lolunit_assert_equal(t4[1], 0.f);
  286. lolunit_assert_equal(t4[2], -8.f);
  287. lolunit_assert_equal(t4[3], 0.f);
  288. lolunit_assert_equal(t4[4], 8.f);
  289. }
  290. };
  291. } /* namespace lol */