From 6b15089e24c8c333c59187937495e3d3ff934def Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Tue, 24 Mar 2026 04:41:03 +0100 Subject: [PATCH] more F16 tests --- interfaces/Crafter.Math-VectorF16.cppm | 3 +- tests/VectorF16.cpp | 240 +++++++++++++++++++++---- 2 files changed, 203 insertions(+), 40 deletions(-) diff --git a/interfaces/Crafter.Math-VectorF16.cppm b/interfaces/Crafter.Math-VectorF16.cppm index 8b5d9d7..57c944c 100755 --- a/interfaces/Crafter.Math-VectorF16.cppm +++ b/interfaces/Crafter.Math-VectorF16.cppm @@ -467,11 +467,12 @@ namespace Crafter { } } - constexpr static _Float16 Dot(VectorF16 a, VectorF16 b) { + constexpr static _Float16 Dot(VectorF16 a, VectorF16 b) requires(Packing == 1) { if constexpr(std::is_same_v) { __m128h mul = _mm_mul_ph(a.v, b.v); return _mm_reduce_add_ph(mul); } else if constexpr(std::is_same_v) { + static_assert(std::is_same_v, "a.v is NOT VectorType"); __m256h mul = _mm256_mul_ph(a.v, b.v); return _mm256_reduce_add_ph(mul); } else { diff --git a/tests/VectorF16.cpp b/tests/VectorF16.cpp index 2345e8a..37c16f7 100644 --- a/tests/VectorF16.cpp +++ b/tests/VectorF16.cpp @@ -21,42 +21,11 @@ import Crafter.Math; import std; using namespace Crafter; -template -std::string* TestLoadStore() { - _Float16 floats[Len * Packing]; - for (std::uint32_t i = 0; i < Len * Packing; i++) { - floats[i] = static_cast<_Float16>(i); - } - - VectorF16 vec(floats); - auto stored = vec.Store(); - for (std::uint32_t i = 0; i < Len * Packing; i++) { - if (stored.v[i] != floats[i]) { - return new std::string(std::format("Load/Store mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i]), (float)stored.v[i])); - } - } - return nullptr; +// Helper function to compare floating point values with tolerance +bool FloatEquals(_Float16 a, _Float16 b, _Float16 epsilon = 0.001f) { + return std::abs(static_cast(a) - static_cast(b)) < static_cast(epsilon); } -template -std::string* TestAdd() { - _Float16 floats[Len * Packing]; - for (std::uint32_t i = 0; i < Len * Packing; i++) { - floats[i] = static_cast<_Float16>(i); - } - - VectorF16 vec(floats); - vec = vec + vec; - auto stored = vec.Store(); - for (std::uint32_t i = 0; i < Len * Packing; i++) { - if (stored.v[i] != floats[i] + floats[i]) { - return new std::string(std::format("Add mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] + floats[i]), (float)stored.v[i])); - } - } - return nullptr; -} - - template std::string* TestAllCombinations() { if constexpr (Len > MaxSize) { @@ -64,15 +33,208 @@ std::string* TestAllCombinations() { } else if constexpr (Len * Packing > MaxSize) { return TestAllCombinations(); } else { - std::string* result = TestLoadStore(); - if (result) return result; - result = TestAdd(); - if (result) return result; + _Float16 floats[VectorF16::Alignment]; + _Float16 floats1[VectorF16::Alignment]; + _Float16 floats2[VectorF16::Alignment]; + for (std::uint32_t i = 0; i < VectorF16::Alignment; i++) { + floats[i] = static_cast<_Float16>(i+1); + } + for (std::uint32_t i = 0; i < Packing*Len; i++) { + floats1[i] = static_cast<_Float16>(i+1); + } + for (std::uint32_t i = 0; i < Packing*Len; i++) { + floats2[i] = static_cast<_Float16>(i+1+Len); + } + for (std::uint32_t i = Len*Packing; i < VectorF16::Alignment; i++) { + floats1[i] = 0; + floats2[i] = 0; + } + + std::string* result = nullptr; + constexpr auto total = Len * Packing; + if constexpr(total > 0 && (total & (total - 1)) == 0) { + { + VectorF16 vec(floats); + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i])) { + return new std::string(std::format("Load/Store mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i]), (float)stored.v[i])); + } + } + } + + { + VectorF16 vec(floats); + vec = vec + vec; + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] + floats[i])) { + return new std::string(std::format("Add mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] + floats[i]), (float)stored.v[i])); + } + } + } + + { + VectorF16 vec(floats); + vec = vec - vec; + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], _Float16(0))) { + return new std::string(std::format("Subtract mismatch at Len={} Packing={}, Expected: 0, Got: {}", Len, Packing, (float)stored.v[i])); + } + } + } + + { + VectorF16 vec(floats); + vec = vec * vec; + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] * floats[i])) { + return new std::string(std::format("Multiply mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] * floats[i]), (float)stored.v[i])); + } + } + } + + { + VectorF16 vec(floats); + vec = vec / vec; + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], _Float16(1))) { + return new std::string(std::format("Divide mismatch at Len={} Packing={}, Expected: 1, Got: {}", Len, Packing, (float)stored.v[i])); + } + } + } + + { + VectorF16 vec(floats); + vec = vec + _Float16(2); + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] + _Float16(2))) { + return new std::string(std::format("Scalar add mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] + _Float16(2)), (float)stored.v[i])); + } + } + } + + { + VectorF16 vec(floats); + vec = vec - _Float16(2); + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] - _Float16(2))) { + return new std::string(std::format("Scalar add mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] + _Float16(2)), (float)stored.v[i])); + } + } + } + + { + VectorF16 vec(floats); + vec = vec * _Float16(2); + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] * _Float16(2))) { + return new std::string(std::format("Scalar multiply mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] * _Float16(2)), (float)stored.v[i])); + } + } + } + + { + VectorF16 vec(floats); + vec = vec / _Float16(2); + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] / _Float16(2))) { + return new std::string(std::format("Scalar multiply mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] * _Float16(2)), (float)stored.v[i])); + } + } + } + + { + VectorF16 vec1(floats); + VectorF16 vec2(floats); + + if (!(vec1 == vec2)) { + return new std::string(std::format("Equality 1 test failed at Len={} Packing={}", Len, Packing)); + } + } + + { + VectorF16 vec1(floats); + VectorF16 vec2(floats); + vec2 *= 2; + if (vec1 == vec2) { + return new std::string(std::format("Equality 2 test failed at Len={} Packing={}", Len, Packing)); + } + } + + { + VectorF16 vec1(floats); + VectorF16 vec2(floats); + + if ((vec1 != vec2)) { + return new std::string(std::format("Inequality 1 test failed at Len={} Packing={}", Len, Packing)); + } + } + + { + VectorF16 vec1(floats); + VectorF16 vec2(floats); + vec2 *= 2; + if (!(vec1 != vec2)) { + return new std::string(std::format("Inequality 2 test failed at Len={} Packing={}", Len, Packing)); + } + } + } + + if constexpr(Packing == 1) { + _Float16 expectedLengthSq = _Float16(0); + for (std::uint32_t i = 0; i < VectorF16::Alignment; i++) { + expectedLengthSq += floats[i] * floats[i]; + } + + { + VectorF16 vec(floats); + _Float16 dot = VectorF16::Dot(vec, vec); + if (!FloatEquals(dot, expectedLengthSq)) { + return new std::string(std::format("Dot product mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)expectedLengthSq, (float)dot)); + } + } + + { + VectorF16 vec(floats); + _Float16 lengthSq = vec.LengthSq(); + if (!FloatEquals(lengthSq, expectedLengthSq)) { + return new std::string(std::format("LengthSq mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)expectedLengthSq, (float)lengthSq)); + } + } + + { + VectorF16 vec(floats); + _Float16 length = vec.Length(); + if (!FloatEquals(length, std::sqrtf(static_cast(expectedLengthSq)))) { + return new std::string(std::format("Length mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (std::sqrtf(static_cast(expectedLengthSq))), (float)length)); + } + } + } + + if constexpr(Len == 3) { + { + VectorF16 vec1(floats1); + VectorF16 vec2(floats2); + VectorF16 result = VectorF16::Cross(vec1, vec2); + Vector<_Float16, Len*Packing, VectorF16::Alignment> stored = result.Store(); + if (!FloatEquals(stored.v[0], -3) || !FloatEquals(stored.v[1], 6) || !FloatEquals(stored.v[2], -3)) { + return new std::string(std::format("Cross mismatch at Len={} Packing={}, Expected: -3,6,-3, Got: {},{},{}", Len, Packing, (float)stored.v[0], (float)stored.v[1], (float)stored.v[2])); + } + } + } + return TestAllCombinations(); } } - extern "C" { std::string* RunTest() { std::string* err = TestAllCombinations::MaxSize>();