From b582e168e3dc5fd011e6e347d796737e277c27ae Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Wed, 25 Mar 2026 00:42:04 +0100 Subject: [PATCH] more tests --- interfaces/Crafter.Math-Basic.cppm | 9 +- interfaces/Crafter.Math-Vector.cppm | 14 +- interfaces/Crafter.Math-VectorF16.cppm | 65 ++-- project.json | 2 +- tests/Vector.cpp | 412 +++++++++++++++++++++++++ tests/VectorF16.cpp | 246 --------------- 6 files changed, 460 insertions(+), 288 deletions(-) create mode 100644 tests/Vector.cpp delete mode 100644 tests/VectorF16.cpp diff --git a/interfaces/Crafter.Math-Basic.cppm b/interfaces/Crafter.Math-Basic.cppm index 8757ee2..135d7ba 100755 --- a/interfaces/Crafter.Math-Basic.cppm +++ b/interfaces/Crafter.Math-Basic.cppm @@ -29,11 +29,10 @@ namespace Crafter { return degrees * (std::numbers::pi / 180); } - #ifdef __AVX512FP16__ + #ifdef __x86_64 + #ifndef __AVX512FP16__ export template - using VectorF16L = VectorF16; - #else - export template - using VectorF16L = VectorF32; + using VectorF16 = VectorF32; + #endif #endif } \ No newline at end of file diff --git a/interfaces/Crafter.Math-Vector.cppm b/interfaces/Crafter.Math-Vector.cppm index 87703b6..e42b5ec 100755 --- a/interfaces/Crafter.Math-Vector.cppm +++ b/interfaces/Crafter.Math-Vector.cppm @@ -439,13 +439,13 @@ namespace Crafter { return q; } - constexpr static Vector QuanternionFromEuler(T roll, T pitch, T yaw) { - T cr = std::cos(roll * 0.5); - T sr = std::sin(roll * 0.5); - T cp = std::cos(pitch * 0.5); - T sp = std::sin(pitch * 0.5); - T cy = std::cos(yaw * 0.5); - T sy = std::sin(yaw * 0.5); + constexpr static Vector QuanternionFromEuler(T rollHalf, T pitchHalf, T yawHalf) { + T cr = std::cos(rollHalf); + T sr = std::sin(rollHalf); + T cp = std::cos(pitchHalf); + T sp = std::sin(pitchHalf); + T cy = std::cos(yawHalf); + T sy = std::sin(yawHalf); return Vector( sr * cp * cy - cr * sp * sy, diff --git a/interfaces/Crafter.Math-VectorF16.cppm b/interfaces/Crafter.Math-VectorF16.cppm index 57c944c..1443e68 100755 --- a/interfaces/Crafter.Math-VectorF16.cppm +++ b/interfaces/Crafter.Math-VectorF16.cppm @@ -92,20 +92,24 @@ namespace Crafter { template constexpr operator VectorF16() const { - if constexpr(std::is_same_v && std::is_same_v::VectorType, __m128h>) { - return VectorF16(_mm256_castph256_ph128(v)); - } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m128h>) { - return VectorF16(_mm512_castph512_ph128(v)); - } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m256h>) { - return VectorF16(_mm512_castph512_ph256(v)); - } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m256h>) { - return VectorF16(_mm256_castph128_ph256(v)); - } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m512h>) { - return VectorF16(_mm512_castph128_ph512(v)); - } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m512h>) { - return VectorF16(_mm512_castph256_ph512(v)); + if(constexpr Len == Blen) { + if constexpr(std::is_same_v && std::is_same_v::VectorType, __m128h>) { + return VectorF16(_mm256_castph256_ph128(v)); + } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m128h>) { + return VectorF16(_mm512_castph512_ph128(v)); + } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m256h>) { + return VectorF16(_mm512_castph512_ph256(v)); + } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m256h>) { + return VectorF16(_mm256_castph128_ph256(v)); + } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m512h>) { + return VectorF16(_mm512_castph128_ph512(v)); + } else if constexpr(std::is_same_v && std::is_same_v::VectorType, __m512h>) { + return VectorF16(_mm512_castph256_ph512(v)); + } else { + return VectorF16(v); + } } else { - return VectorF16(v); + return ExtractLo(); } } @@ -364,13 +368,14 @@ namespace Crafter { template values> constexpr VectorF16 Negate() { - std::array mask = GetNegateMask(); + std::array mask = GetNegateMask(); + std::println("{}", mask); if constexpr(std::is_same_v) { return VectorF16(_mm_castsi128_ph(_mm_xor_si128(_mm_castph_si128(v), _mm_loadu_epi16(mask.data())))); } else if constexpr(std::is_same_v) { - return VectorF16(_mm256_castsi2568_ph(_mm256_xor_si256(_mm256_castph_si256(v), _mm_loadu_epi16(mask.data())))); + return VectorF16(_mm256_castsi256_ph(_mm256_xor_si256(_mm256_castph_si256(v), _mm256_loadu_epi16(mask.data())))); } else { - return VectorF16(_mm512_castsi512_ph(_mm512_xor_si256(_mm512_castph_si512(v), _mm_loadu_epi16(mask.data())))); + return VectorF16(_mm512_castsi512_ph(_mm512_xor_si512(_mm512_castph_si512(v), _mm512_loadu_epi16(mask.data())))); } } @@ -1170,14 +1175,14 @@ namespace Crafter { static_assert(false, "No __AVX512BW__ and __AVX512VL__ support"); #endif #endif - return _mm256_castsi256_ph(_mm256_mask_blend_epi16(_mm256_castph_si256(a.v), _mm256_castph_si256(b.v), GetBlendMaskEpi16())); + return _mm256_castsi256_ph(_mm256_mask_blend_epi16(GetBlendMaskEpi16(), _mm256_castph_si256(a.v), _mm256_castph_si256(b.v))); } else { - return _mm512_castsi512_ph(_mm512_blend_epi16(GetBlendMaskEpi16(), _mm512_castph_si512(a.v), _mm512_castph_si512(b.v))); + return _mm512_castsi512_ph(_mm512_mask_blend_epi16(GetBlendMaskEpi16(), _mm512_castph_si512(a.v), _mm512_castph_si512(b.v))); } } constexpr static VectorF16 Rotate(VectorF16<3, Packing> v, VectorF16<4, Packing> q) requires(Len == 3) { - VectorF16<3, Packing> qv(q.v); + VectorF16<3, Packing> qv(q); VectorF16 t = Cross(qv, v) * _Float16(2); return v + t * q.template Shuffle<{{3,3,3,3}}>() + Cross(qv, t); } @@ -1226,21 +1231,23 @@ namespace Crafter { } private: template values> - static consteval std::array GetNegateMask() { - std::array mask; - for(std::uint8_t i = 0; i < Len; i++) { - if(values[i]) { - mask[i] = 0b1000000000000000; - } else { - mask[i] = 0; + static consteval std::array GetNegateMask() { + std::array mask{0}; + for(std::uint8_t i2 = 0; i2 < Packing; i2++) { + for(std::uint8_t i = 0; i < Len; i++) { + if(values[i]) { + mask[i2*Len+i] = 0b1000000000000000; + } else { + mask[i2*Len+i] = 0; + } } } return mask; } - static consteval std::array GetNegateMaskAll() { - std::array mask; - for(std::uint8_t i = 0; i < Len; i++) { + static consteval std::array GetNegateMaskAll() { + std::array mask{0}; + for(std::uint8_t i = 0; i < Packing*Len; i++) { mask[i] = 0b1000000000000000; } return mask; diff --git a/project.json b/project.json index 4c07ec8..63c7728 100644 --- a/project.json +++ b/project.json @@ -35,7 +35,7 @@ "tests":[ { "name": "F16-x86-64-sapphirerapids", - "implementations": ["tests/VectorF16"], + "implementations": ["tests/Vector"], "march": "sapphirerapids", "extends": ["lib-shared"] } diff --git a/tests/Vector.cpp b/tests/Vector.cpp new file mode 100644 index 0000000..4e2cb91 --- /dev/null +++ b/tests/Vector.cpp @@ -0,0 +1,412 @@ +/* +Crafter® Build +Copyright (C) 2026 Catcrafts® +Catcrafts.net + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 3.0 as published by the Free Software Foundation; + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +import Crafter.Math; +import std; +using namespace Crafter; + +// Helper function to compare floating point values with tolerance +template +constexpr bool FloatEquals(T a, T b, T epsilon = 0.001f) { + return std::abs(static_cast(a) - static_cast(b)) < static_cast(epsilon); +} + +template +consteval std::array AlternateTrueFalse() { + std::array result = {}; + for (std::uint8_t i = 0; i < Len; ++i) { + result[i] = (i % 2 == 0); // Set true for even indices, false for odd indices + } + return result; +} + +template class VectorType, std::uint32_t MaxSize, std::uint32_t Len = 1, std::uint32_t Packing = 1> +std::string* TestAllCombinations() { + if constexpr (Len > MaxSize) { + return nullptr; + } else if constexpr (Len * Packing > MaxSize) { + return TestAllCombinations(); + } else { + T floats[VectorType::Alignment]; + T floats1[VectorType::Alignment]; + T floats2[VectorType::Alignment]; + for (std::uint32_t i = 0; i < VectorType::Alignment; i++) { + floats[i] = static_cast(i+1); + } + for (std::uint32_t i = 0; i < Packing*Len; i++) { + floats1[i] = static_cast(i+1); + } + for (std::uint32_t i = 0; i < Packing*Len; i++) { + floats2[i] = static_cast(i+1+Len); + } + for (std::uint32_t i = Len*Packing; i < VectorType::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) { + { + VectorType vec(floats); + Vector::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])); + } + } + } + + { + VectorType vec(floats); + vec = vec + vec; + Vector::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])); + } + } + } + + { + VectorType vec(floats); + vec = vec - vec; + Vector::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], T(0))) { + return new std::string(std::format("Subtract mismatch at Len={} Packing={}, Expected: 0, Got: {}", Len, Packing, (float)stored.v[i])); + } + } + } + + { + VectorType vec(floats); + vec = vec * vec; + Vector::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])); + } + } + } + + { + VectorType vec(floats); + vec = vec / vec; + Vector::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], T(1))) { + return new std::string(std::format("Divide mismatch at Len={} Packing={}, Expected: 1, Got: {}", Len, Packing, (float)stored.v[i])); + } + } + } + + { + VectorType vec(floats); + vec = vec + T(2); + Vector::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] + T(2))) { + return new std::string(std::format("Scalar add mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] + T(2)), (float)stored.v[i])); + } + } + } + + { + VectorType vec(floats); + vec = vec - T(2); + Vector::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] - T(2))) { + return new std::string(std::format("Scalar add mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] + T(2)), (float)stored.v[i])); + } + } + } + + { + VectorType vec(floats); + vec = vec * T(2); + Vector::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] * T(2))) { + return new std::string(std::format("Scalar multiply mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] * T(2)), (float)stored.v[i])); + } + } + } + + { + VectorType vec(floats); + vec = vec / T(2); + Vector::Alignment> stored = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(stored.v[i], floats[i] / T(2))) { + return new std::string(std::format("Scalar multiply mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(floats[i] * T(2)), (float)stored.v[i])); + } + } + } + + { + VectorType vec1(floats); + VectorType vec2(floats); + + if (!(vec1 == vec2)) { + return new std::string(std::format("Equality 1 test failed at Len={} Packing={}", Len, Packing)); + } + } + + { + VectorType vec1(floats); + VectorType vec2(floats); + vec2 *= 2; + if (vec1 == vec2) { + return new std::string(std::format("Equality 2 test failed at Len={} Packing={}", Len, Packing)); + } + } + + { + VectorType vec1(floats); + VectorType vec2(floats); + + if ((vec1 != vec2)) { + return new std::string(std::format("Inequality 1 test failed at Len={} Packing={}", Len, Packing)); + } + } + + { + VectorType vec1(floats); + VectorType vec2(floats); + vec2 *= 2; + if (!(vec1 != vec2)) { + return new std::string(std::format("Inequality 2 test failed at Len={} Packing={}", Len, Packing)); + } + } + + { + VectorType vec(floats); + vec = -vec; + Vector::Alignment> result = vec.Store(); + for (std::uint32_t i = 0; i < Len * Packing; i++) { + if (!FloatEquals(result.v[i], -floats[i])) { + return new std::string(std::format("Negate mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, (float)(-floats[i]), (float)result.v[i])); + } + } + } + + { + VectorType vecA(floats1); + VectorType vecB(floats2); + VectorType result = VectorType::template Blend()>(vecA, vecB); + Vector::Alignment> stored = result.Store(); + for (std::uint32_t i = 0; i < Len; i++) { + bool useB = (i % 2 == 0); + T expected = useB ? floats2[i]: floats1[i]; + if (!FloatEquals(stored.v[i], expected)) { + return new std::string(std::format("Blend mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {}", Len, Packing, i, (float)expected, (float)stored.v[i])); + } + } + } + + { + VectorType vecA(floats); + VectorType vecB(floats); + VectorType vecAdd(floats); + VectorType result = VectorType::MulitplyAdd(vecA, vecB, vecAdd); + Vector::Alignment> stored = result.Store(); + for (std::uint32_t i = 0; i < Len; i++) { + T expected = floats[i] * floats[i] + floats[i]; + if (!FloatEquals(stored.v[i], expected)) { + return new std::string(std::format("MulitplyAdd mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {}", Len, Packing, i, (float)expected, (float)stored.v[i])); + } + } + } + + { + VectorType vecA(floats); + VectorType vecB(floats); + VectorType vecSub(floats); + VectorType result = VectorType::MulitplySub(vecA, vecB, vecSub); + Vector::Alignment> stored = result.Store(); + for (std::uint32_t i = 0; i < Len; i++) { + T expected = floats[i] * floats[i] - floats[i]; + if (!FloatEquals(stored.v[i], expected)) { + return new std::string(std::format("MulitplySub mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {}", Len, Packing, i, (float)expected, (float)stored.v[i])); + } + } + } + } + + if constexpr(Packing == 1) { + T expectedLengthSq = T(0); + for (std::uint32_t i = 0; i < VectorType::Alignment; i++) { + expectedLengthSq += floats[i] * floats[i]; + } + + { + VectorType vec(floats); + T dot = VectorType::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)); + } + } + + { + VectorType vec(floats); + T 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)); + } + } + + { + VectorType vec(floats); + T length = vec.Length(); + if (!FloatEquals(length, static_cast(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)); + } + } + + { + VectorType vec(floats); + vec.Normalize(); + T length = vec.Length(); + if (!FloatEquals(length, static_cast(1))) { + return new std::string(std::format("Normalize mismatch at Len={} Packing={}, Expected: {}, Got: {}", Len, Packing, 1, (float)length)); + } + } + } + + if constexpr(Len == 3) { + { + VectorType vec1(floats1); + VectorType vec2(floats2); + VectorType result = VectorType::Cross(vec1, vec2); + Vector::Alignment> stored = result.Store(); + if (!FloatEquals(stored.v[0], T(-3)) || !FloatEquals(stored.v[1], T(6)) || !FloatEquals(stored.v[2], T(-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])); + } + } + if constexpr(4 * Packing < VectorType<1, 1>::MaxSize) { + T qData[4]; + qData[0] = T(1); + qData[1] = T(0); + qData[2] = T(0); + qData[3] = T(0); + + VectorType<3, Packing> vecV(floats); + VectorType<4, Packing> vecQ(qData); + VectorType<3, Packing> result = VectorType<3, Packing>::Rotate(vecV, vecQ); + Vector::Alignment> stored = result.Store(); + + for (std::uint32_t i = 0; i < 3; i++) { + if (!FloatEquals(stored.v[i], floats[i])) { + return new std::string(std::format("Rotate mismatch at Len={} Packing={}, Index={}, Expected: {}, Got: {}", Len, Packing, i, (float)floats[i], (float)stored.v[i])); + } + } + } + } + + + // // Test QuanternionFromEuler() static method (Len == 4 only) + // if constexpr(Len == 4) { + // T eulerData[3] = {T(0), T(0), T(0)}; // Zero rotation + // VectorType<3, 1> eulerVec(eulerData); + // VectorType<4, 1> result = VectorType<4, 1>::QuanternionFromEuler(eulerVec); + // Vector stored = result.Store(); + + // // Identity quaternion should be (1, 0, 0, 0) + // if (!FloatEquals(stored.v[0], T(1)) || !FloatEquals(stored.v[1], T(0)) || + // !FloatEquals(stored.v[2], T(0)) || !FloatEquals(stored.v[3], T(0))) { + // return new std::string(std::format("QuanternionFromEuler mismatch at Len={} Packing={}, Expected: 1,0,0,0, Got: {},{},{},{}", Len, Packing, (float)stored.v[0], (float)stored.v[1], (float)stored.v[2], (float)stored.v[3])); + // } + // } + + // // Test batch Normalize() for 2 vectors (Len == 2) + // if constexpr(Len == 2) { + // T aData[2] = {T(3), T(4)}; + // T eData[2] = {T(6), T(8)}; + // VectorType<2, 1> vecA(aData); + // VectorType<2, 1> vecE(eData); + // auto result = VectorType<2, 1>::Normalize(vecA, vecE); + // Vector storedA = std::get<0>(result).Store(); + // Vector storedE = std::get<1>(result).Store(); + + // // Normalize (3,4) -> (0.6, 0.8) + // for (std::uint32_t i = 0; i < 2; i++) { + // if (!FloatEquals(storedA.v[i], static_cast(0.6f + i * 0.2f))) { + // return new std::string(std::format("Normalize 2 vec test failed (A) at index {}, Expected: {}, Got: {}", i, (float)(0.6f + i * 0.2f), (float)storedA.v[i])); + // } + // } + + // // Normalize (6,8) -> (0.6, 0.8) + // for (std::uint32_t i = 0; i < 2; i++) { + // if (!FloatEquals(storedE.v[i], static_cast(0.6f + i * 0.2f))) { + // return new std::string(std::format("Normalize 2 vec test failed (E) at index {}, Expected: {}, Got: {}", i, (float)(0.6f + i * 0.2f), (float)storedE.v[i])); + // } + // } + // } + + // // Test batch LengthSq() for 2 vectors (Len == 2) + // if constexpr(Len == 2) { + // T aData[2] = {T(3), T(4)}; + // T eData[2] = {T(5), T(12)}; + // VectorType<2, 1> vecA(aData); + // VectorType<2, 1> vecE(eData); + // VectorType<2, 1> result = VectorType<2, 1>::LengthSq(vecA, vecE); + // Vector stored = result.Store(); + + // // LengthSq of (3,4) = 9+16 = 25 + // // LengthSq of (5,12) = 25+144 = 169 + // if (!FloatEquals(stored.v[0], T(25)) || !FloatEquals(stored.v[1], T(169))) { + // return new std::string(std::format("LengthSq 2 vec test failed at Len={} Packing={}, Expected: 25,169, Got: {},{}", Len, Packing, (float)stored.v[0], (float)stored.v[1])); + // } + // } + + // // Test batch Dot() for 2 vectors (Len == 2) + // if constexpr(Len == 2) { + // T a0Data[2] = {T(1), T(2)}; + // T a1Data[2] = {T(3), T(4)}; + // T e0Data[2] = {T(5), T(6)}; + // T e1Data[2] = {T(7), T(8)}; + // VectorType<2, 1> vecA0(a0Data); + // VectorType<2, 1> vecA1(a1Data); + // VectorType<2, 1> vecE0(e0Data); + // VectorType<2, 1> vecE1(e1Data); + // VectorType<2, 1> result = VectorType<2, 1>::Dot(vecA0, vecA1, vecE0, vecE1); + // Vector stored = result.Store(); + + // // Dot (1,2) with (3,4) = 3+8=11 + // // Dot (5,6) with (7,8) = 35+48=83 + // if (!FloatEquals(stored.v[0], T(11)) || !FloatEquals(stored.v[1], T(83))) { + // return new std::string(std::format("Dot 2 vec test failed at Len={} Packing={}, Expected: 11,83, Got: {},{}", Len, Packing, (float)stored.v[0], (float)stored.v[1])); + // } + // } + + return TestAllCombinations(); + } +} + +extern "C" { + std::string* RunTest() { + std::string* err = TestAllCombinations<_Float16, VectorF16, VectorF16<1, 1>::MaxSize>(); + if (err) { + return err; + } + return nullptr; + } +} \ No newline at end of file diff --git a/tests/VectorF16.cpp b/tests/VectorF16.cpp deleted file mode 100644 index 37c16f7..0000000 --- a/tests/VectorF16.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* -Crafter® Build -Copyright (C) 2026 Catcrafts® -Catcrafts.net - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License version 3.0 as published by the Free Software Foundation; - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include -import Crafter.Math; -import std; -using namespace Crafter; - -// 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* TestAllCombinations() { - if constexpr (Len > MaxSize) { - return nullptr; - } else if constexpr (Len * Packing > MaxSize) { - return TestAllCombinations(); - } else { - _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>(); - if (err) { - return err; - } - return nullptr; - } -} \ No newline at end of file