(Math) Added IntegralLog2(Pot) functions

Former-commit-id: 2def88ebf1e0ec2c908b2da4df60ff9e8075f8f1
This commit is contained in:
Lynix 2015-03-16 13:53:48 +01:00
parent 7bac245a0f
commit 3e214678c3
2 changed files with 87 additions and 0 deletions

View File

@ -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<typename T> unsigned int NzIntegralLog2(T number);
template<typename T> unsigned int NzIntegralLog2Pot(T pot);
unsigned int NzIntegralPow(unsigned int base, unsigned int exponent);
template<typename T, typename T2> T NzLerp(T from, T to, T2 interpolation);
template<typename T> T NzMultiplyAdd(T x, T y, T z);

View File

@ -7,11 +7,83 @@
#include <Nazara/Math/Config.hpp>
#include <algorithm>
#include <cstring>
#include <type_traits>
#include <Nazara/Core/Debug.hpp>
#define F(a) static_cast<T>(a)
#define F2(a) static_cast<T2>(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 T>
typename std::enable_if<sizeof(T) <= sizeof(nzUInt32), unsigned int>::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<nzUInt32>(number * 0x07C4ACDDU) >> 27];
}
template<typename T>
// 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<nzUInt32>::max()) << i*8;
unsigned int log2 = NzImplIntegralLog2<nzUInt32>((number & mask) >> i*8);
if (log2)
return log2 + i*8;
}
return 0;
}
template<typename T>
typename std::enable_if<sizeof(T) <= sizeof(nzUInt32), unsigned int>::type NzImplIntegralLog2Pot(T number)
{
// https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
return MultiplyDeBruijnBitPosition2[static_cast<nzUInt32>(number * 0x077CB531U) >> 27];
}
template<typename T>
// 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<nzUInt32>::max()) << i*8;
unsigned int log2 = NzImplIntegralLog2Pot<nzUInt32>((number & mask) >> i*8);
if (log2)
return log2 + i*8;
}
return 0;
}
}
template<typename T>
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<long long>(number)) + precision + 1; // Plus un pour le point
}
template<typename T>
unsigned int NzIntegralLog2(T number)
{
// Proxy nécessaire pour éviter un problème de surcharge
return NzImplIntegralLog2<T>(number);
}
template<typename T>
unsigned int NzIntegralLog2Pot(T pot)
{
return NzImplIntegralLog2Pot<T>(pot);
}
inline unsigned int NzIntegralPow(unsigned int base, unsigned int exponent)
{
///TODO: Marquer comme constexpr en C++14