From 3e214678c3a7de23f530a838d6b06f8c5760cb3b Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 16 Mar 2015 13:53:48 +0100 Subject: [PATCH] (Math) Added IntegralLog2(Pot) functions Former-commit-id: 2def88ebf1e0ec2c908b2da4df60ff9e8075f8f1 --- include/Nazara/Math/Algorithm.hpp | 2 + include/Nazara/Math/Algorithm.inl | 85 +++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/include/Nazara/Math/Algorithm.hpp b/include/Nazara/Math/Algorithm.hpp index a842c1df8..92ea232bd 100644 --- a/include/Nazara/Math/Algorithm.hpp +++ b/include/Nazara/Math/Algorithm.hpp @@ -35,6 +35,8 @@ unsigned int NzGetNumberLength(unsigned long long number); unsigned int NzGetNumberLength(float number, nzUInt8 precision = NAZARA_CORE_DECIMAL_DIGITS); unsigned int NzGetNumberLength(double number, nzUInt8 precision = NAZARA_CORE_DECIMAL_DIGITS); unsigned int NzGetNumberLength(long double number, nzUInt8 precision = NAZARA_CORE_DECIMAL_DIGITS); +template unsigned int NzIntegralLog2(T number); +template unsigned int NzIntegralLog2Pot(T pot); unsigned int NzIntegralPow(unsigned int base, unsigned int exponent); template T NzLerp(T from, T to, T2 interpolation); template T NzMultiplyAdd(T x, T y, T z); diff --git a/include/Nazara/Math/Algorithm.inl b/include/Nazara/Math/Algorithm.inl index dc95dbba8..18b93c9cc 100644 --- a/include/Nazara/Math/Algorithm.inl +++ b/include/Nazara/Math/Algorithm.inl @@ -7,11 +7,83 @@ #include #include #include +#include #include #define F(a) static_cast(a) #define F2(a) static_cast(a) +namespace +{ + // https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn + static const unsigned int MultiplyDeBruijnBitPosition[32] = + { + 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 + }; + + static const unsigned int MultiplyDeBruijnBitPosition2[32] = + { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + + + template + typename std::enable_if::type NzImplIntegralLog2(T number) + { + // https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn + number |= number >> 1; // first round down to one less than a power of 2 + number |= number >> 2; + number |= number >> 4; + number |= number >> 8; + number |= number >> 16; + + return MultiplyDeBruijnBitPosition[static_cast(number * 0x07C4ACDDU) >> 27]; + } + + template + // Les parenthèses autour de la condition sont nécesaires pour que GCC compile ça + typename std::enable_if<(sizeof(T) > sizeof(nzUInt32)), unsigned int>::type NzImplIntegralLog2(T number) + { + static_assert(sizeof(T) % sizeof(nzUInt32) == 0, "Assertion failed"); + + for (int i = sizeof(T)-sizeof(nzUInt32); i >= 0; i -= sizeof(nzUInt32)) + { + T mask = T(std::numeric_limits::max()) << i*8; + unsigned int log2 = NzImplIntegralLog2((number & mask) >> i*8); + if (log2) + return log2 + i*8; + } + + return 0; + } + + template + typename std::enable_if::type NzImplIntegralLog2Pot(T number) + { + // https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn + return MultiplyDeBruijnBitPosition2[static_cast(number * 0x077CB531U) >> 27]; + } + + template + // Les parenthèses autour de la condition sont nécesaires pour que GCC compile ça + typename std::enable_if<(sizeof(T) > sizeof(nzUInt32)), unsigned int>::type NzImplIntegralLog2Pot(T number) + { + static_assert(sizeof(T) % sizeof(nzUInt32) == 0, "Assertion failed"); + + for (int i = sizeof(T)-sizeof(nzUInt32); i >= 0; i -= sizeof(nzUInt32)) + { + T mask = T(std::numeric_limits::max()) << i*8; + unsigned int log2 = NzImplIntegralLog2Pot((number & mask) >> i*8); + if (log2) + return log2 + i*8; + } + + return 0; + } +} + template T NzApproach(T value, T objective, T increment) { @@ -151,6 +223,19 @@ inline unsigned int NzGetNumberLength(long double number, nzUInt8 precision) return NzGetNumberLength(static_cast(number)) + precision + 1; // Plus un pour le point } +template +unsigned int NzIntegralLog2(T number) +{ + // Proxy nécessaire pour éviter un problème de surcharge + return NzImplIntegralLog2(number); +} + +template +unsigned int NzIntegralLog2Pot(T pot) +{ + return NzImplIntegralLog2Pot(pot); +} + inline unsigned int NzIntegralPow(unsigned int base, unsigned int exponent) { ///TODO: Marquer comme constexpr en C++14