test_core_math.odin 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // Tests "math.odin" in "core:math".
  2. // Must be run with `-collection:tests=` flag, e.g.
  3. // ./odin run tests/core/math/test_core_math.odin -collection:tests=./tests
  4. package test_core_math
  5. import "core:fmt"
  6. import "core:math"
  7. import "core:testing"
  8. import tc "tests:common"
  9. main :: proc() {
  10. t := testing.T{}
  11. test_classify_f16(&t)
  12. test_classify_f32(&t)
  13. test_classify_f64(&t)
  14. test_trunc_f16(&t)
  15. test_trunc_f32(&t)
  16. test_trunc_f64(&t)
  17. tc.report(&t)
  18. }
  19. @test
  20. test_classify_f16 :: proc(t: ^testing.T) {
  21. using math
  22. using Float_Class
  23. r: Float_Class
  24. Datum :: struct {
  25. i: int,
  26. v: f16,
  27. e: math.Float_Class,
  28. }
  29. @static data := []Datum{
  30. { 0, 1.2, Normal },
  31. { 1, 0h0001, Subnormal },
  32. { 2, 0.0, Zero },
  33. { 3, -0.0, Neg_Zero },
  34. { 4, SNAN_F16, NaN },
  35. { 5, QNAN_F16, NaN },
  36. { 6, INF_F16, Inf },
  37. { 7, NEG_INF_F16, Neg_Inf },
  38. }
  39. for d, i in data {
  40. assert(i == d.i)
  41. r = classify_f16(d.v)
  42. tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
  43. }
  44. /* Check all subnormals (exponent 0, 10-bit significand non-zero) */
  45. for i :u16 = 1; i < 0x400; i += 1 {
  46. v :f16 = transmute(f16)i
  47. r = classify_f16(v)
  48. e :Float_Class: Subnormal
  49. tc.expect(t, r == e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, v, r, e))
  50. }
  51. }
  52. @test
  53. test_classify_f32 :: proc(t: ^testing.T) {
  54. using math
  55. using Float_Class
  56. r: Float_Class
  57. Datum :: struct {
  58. i: int,
  59. v: f32,
  60. e: math.Float_Class,
  61. }
  62. @static data := []Datum{
  63. { 0, 1.2, Normal },
  64. { 1, 0h0000_0001, Subnormal },
  65. { 2, 0.0, Zero },
  66. { 3, -0.0, Neg_Zero },
  67. { 4, SNAN_F32, NaN },
  68. { 5, QNAN_F32, NaN },
  69. { 6, INF_F32, Inf },
  70. { 7, NEG_INF_F32, Neg_Inf },
  71. }
  72. for d, i in data {
  73. assert(i == d.i)
  74. r = classify_f32(d.v)
  75. tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
  76. }
  77. }
  78. @test
  79. test_classify_f64 :: proc(t: ^testing.T) {
  80. using math
  81. using Float_Class
  82. r: Float_Class
  83. Datum :: struct {
  84. i: int,
  85. v: f64,
  86. e: math.Float_Class,
  87. }
  88. @static data := []Datum{
  89. { 0, 1.2, Normal },
  90. { 1, 0h0000_0000_0000_0001, Subnormal },
  91. { 2, 0.0, Zero },
  92. { 3, -0.0, Neg_Zero },
  93. { 4, SNAN_F64, NaN },
  94. { 5, QNAN_F64, NaN },
  95. { 6, INF_F64, Inf },
  96. { 7, NEG_INF_F64, Neg_Inf },
  97. }
  98. for d, i in data {
  99. assert(i == d.i)
  100. r = classify_f64(d.v)
  101. tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
  102. }
  103. }
  104. @test
  105. test_trunc_f16 :: proc(t: ^testing.T) {
  106. using math
  107. r, v: f16
  108. Datum :: struct {
  109. i: int,
  110. v: f16,
  111. e: f16,
  112. }
  113. @static data := []Datum{
  114. { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
  115. { 1, -10.5, -10 },
  116. { 2, F16_MAX, F16_MAX },
  117. { 3, -F16_MAX, -F16_MAX },
  118. { 4, F16_MIN, 0.0 },
  119. { 5, -F16_MIN, -0.0 },
  120. { 6, 0.0, 0.0 },
  121. { 7, -0.0, -0.0 },
  122. { 8, 1, 1 },
  123. { 9, -1, -1 },
  124. { 10, INF_F16, INF_F16 },
  125. { 11, NEG_INF_F16, NEG_INF_F16 },
  126. /* From https://en.wikipedia.org/wiki/Half-precision_floating-point_format */
  127. { 12, 0h3C01, 1 }, // 0x1.004p+0 (smallest > 1)
  128. { 13, -0h3C01, -1 },
  129. { 14, 0h3BFF, 0.0 }, // 0x1.ffcp-1 (largest < 1)
  130. { 15, -0h3BFF, -0.0 },
  131. { 16, 0h0001, 0.0 }, // 0x0.004p-14 (smallest subnormal)
  132. { 17, -0h0001, -0.0 },
  133. { 18, 0h03FF, 0.0 }, // 0x0.ffcp-14 (largest subnormal)
  134. { 19, -0h03FF, -0.0 },
  135. { 20, 0hC809, -8 }, // -0x1.024p+3
  136. { 21, 0h4458, 4 }, // 0x1.16p+2
  137. }
  138. for d, i in data {
  139. assert(i == d.i)
  140. r = trunc_f16(d.v)
  141. tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
  142. }
  143. v = SNAN_F16
  144. r = trunc_f16(v)
  145. tc.expect(t, is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
  146. v = QNAN_F16
  147. r = trunc_f16(v)
  148. tc.expect(t, is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
  149. }
  150. @test
  151. test_trunc_f32 :: proc(t: ^testing.T) {
  152. using math
  153. r, v: f32
  154. Datum :: struct {
  155. i: int,
  156. v: f32,
  157. e: f32,
  158. }
  159. @static data := []Datum{
  160. { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
  161. { 1, -10.5, -10 },
  162. { 2, F32_MAX, F32_MAX },
  163. { 3, -F32_MAX, -F32_MAX },
  164. { 4, F32_MIN, 0.0 },
  165. { 5, -F32_MIN, -0.0 },
  166. { 6, 0.0, 0.0 },
  167. { 7, -0.0, -0.0 },
  168. { 8, 1, 1 },
  169. { 9, -1, -1 },
  170. { 10, INF_F32, INF_F32 },
  171. { 11, NEG_INF_F32, NEG_INF_F32 },
  172. /* From https://en.wikipedia.org/wiki/Single-precision_floating-point_format */
  173. { 12, 0h3F80_0001, 1 }, // 0x1.000002p+0 (smallest > 1)
  174. { 13, -0h3F80_0001, -1 },
  175. { 14, 0h3F7F_FFFF, 0.0 }, // 0x1.fffffep-1 (largest < 1)
  176. { 15, -0h3F7F_FFFF, -0.0 },
  177. { 16, 0h0000_0001, 0.0 }, // 0x0.000002p-126 (smallest subnormal)
  178. { 17, -0h0000_0001, -0.0 },
  179. { 18, 0h007F_FFFF, 0.0 }, // 0x0.fffffep-126 (largest subnormal)
  180. { 19, -0h007F_FFFF, -0.0 },
  181. /* From libc-test src/math/sanity/truncf.h */
  182. { 20, 0hC101_11D0, -8 }, // -0x1.0223ap+3
  183. { 21, 0h408B_0C34, 4 }, // 0x1.161868p+2
  184. { 22, 0hC106_1A5A, -8 }, // -0x1.0c34b4p+3
  185. { 23, 0hC0D1_0378, -6 }, // -0x1.a206fp+2
  186. { 24, 0h4114_45DE, 9 }, // 0x1.288bbcp+3
  187. { 25, 0h3F29_77E8, 0.0 }, // 0x1.52efdp-1
  188. { 26, 0hBED0_2E64, -0.0 }, // -0x1.a05cc8p-2
  189. { 27, 0h3F0F_CF7D, 0.0 }, // 0x1.1f9efap-1
  190. { 28, 0h3F46_2ED8, 0.0 }, // 0x1.8c5dbp-1
  191. { 29, 0hBF2D_C375, -0.0 }, // -0x1.5b86eap-1
  192. }
  193. for d, i in data {
  194. assert(i == d.i)
  195. r = trunc_f32(d.v)
  196. tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
  197. }
  198. v = SNAN_F32
  199. r = trunc_f32(v)
  200. tc.expect(t, is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
  201. v = QNAN_F32
  202. r = trunc_f32(v)
  203. tc.expect(t, is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
  204. }
  205. @test
  206. test_trunc_f64 :: proc(t: ^testing.T) {
  207. using math
  208. r, v: f64
  209. Datum :: struct {
  210. i: int,
  211. v: f64,
  212. e: f64,
  213. }
  214. data := []Datum{
  215. { 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
  216. { 1, -10.5, -10 },
  217. { 2, F64_MAX, F64_MAX },
  218. { 3, -F64_MAX, -F64_MAX },
  219. { 4, F64_MIN, 0.0 },
  220. { 5, -F64_MIN, -0.0 },
  221. { 6, 0.0, 0.0 },
  222. { 7, -0.0, -0.0 },
  223. { 8, 1, 1 },
  224. { 9, -1, -1 },
  225. { 10, INF_F64, INF_F64 },
  226. { 11, NEG_INF_F64, NEG_INF_F64 },
  227. /* From https://en.wikipedia.org/wiki/Double-precision_floating-point_format */
  228. { 12, 0h3FF0_0000_0000_0001, 1 }, // 0x1.0000000000001p+0 (smallest > 1)
  229. { 13, -0h3FF0_0000_0000_0001, -1 },
  230. { 14, 0h3FEF_FFFF_FFFF_FFFF, 0.0 }, // 0x1.fffffffffffffp-1 (largest < 1)
  231. { 15, -0h3FEF_FFFF_FFFF_FFFF, -0.0 },
  232. { 16, 0h0000_0000_0000_0001, 0.0 }, // 0x0.0000000000001p-1022 (smallest subnormal)
  233. { 17, -0h0000_0000_0000_0001, -0.0 },
  234. { 18, 0h000F_FFFF_FFFF_FFFF, 0.0 }, // 0x0.fffffffffffffp-1022 (largest subnormal)
  235. { 19, -0h000F_FFFF_FFFF_FFFF, -0.0 },
  236. /* From libc-test src/math/sanity/trunc.h */
  237. { 20, 0hC020_2239_F3C6_A8F1, -8 }, // -0x1.02239f3c6a8f1p+3
  238. { 21, 0h4011_6186_8E18_BC67, 4 }, // 0x1.161868e18bc67p+2
  239. { 22, 0hC020_C34B_3E01_E6E7, -8 }, // -0x1.0c34b3e01e6e7p+3
  240. { 23, 0hC01A_206F_0A19_DCC4, -6 }, // -0x1.a206f0a19dcc4p+2
  241. { 24, 0h4022_88BB_B0D6_A1E6, 9 }, // 0x1.288bbb0d6a1e6p+3
  242. { 25, 0h3FE5_2EFD_0CD8_0497, 0.0 }, // 0x1.52efd0cd80497p-1
  243. { 26, 0hBFDA_05CC_7544_81D1, -0.0 }, // -0x1.a05cc754481d1p-2
  244. { 27, 0h3FE1_F9EF_9347_45CB, 0.0 }, // 0x1.1f9ef934745cbp-1
  245. { 28, 0h3FE8_C5DB_097F_7442, 0.0 }, // 0x1.8c5db097f7442p-1
  246. { 29, 0hBFE5_B86E_A811_8A0E, -0.0 }, // -0x1.5b86ea8118a0ep-1
  247. }
  248. for d, i in data {
  249. assert(i == d.i)
  250. r = trunc_f64(d.v)
  251. tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
  252. }
  253. v = SNAN_F64
  254. r = trunc_f64(v)
  255. tc.expect(t, is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
  256. v = QNAN_F64
  257. r = trunc_f64(v)
  258. tc.expect(t, is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
  259. }