mirror of
https://github.com/g-truc/glm.git
synced 2024-11-26 02:04:35 +00:00
Added constant time ULP distance between float #121
This commit is contained in:
parent
0f4a597f10
commit
59cae7b5cb
@ -17,6 +17,7 @@
|
||||
// Dependencies
|
||||
#include "../gtc/constants.hpp"
|
||||
#include "../ext/vector_relational.hpp"
|
||||
#include "../ext/scalar_int_sized.hpp"
|
||||
|
||||
#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)
|
||||
# pragma message("GLM: GLM_GTC_ulp extension included")
|
||||
@ -40,22 +41,32 @@ namespace glm
|
||||
/// Return the value(s) ULP distance after the input value(s).
|
||||
/// @see gtc_ulp
|
||||
template<typename genType>
|
||||
GLM_FUNC_DECL genType next_float(genType const& x, uint const& Distance);
|
||||
GLM_FUNC_DECL genType next_float(genType const& x, int DistanceULPs);
|
||||
|
||||
/// Return the value(s) ULP distance before the input value(s).
|
||||
/// @see gtc_ulp
|
||||
template<typename genType>
|
||||
GLM_FUNC_DECL genType prev_float(genType const& x, uint const& Distance);
|
||||
GLM_FUNC_DECL genType prev_float(genType const& x, int DistanceULPs);
|
||||
|
||||
/// Return the distance in the number of ULP between 2 scalars.
|
||||
/// Return the distance in the number of ULP between 2 single-precision floating-point scalars.
|
||||
/// @see gtc_ulp
|
||||
template<typename T>
|
||||
GLM_FUNC_DECL uint float_distance(T const& x, T const& y);
|
||||
GLM_FUNC_DECL int float_distance(float x, float y);
|
||||
|
||||
/// Return the distance in the number of ULP between 2 vectors.
|
||||
/// Return the distance in the number of ULP between 2 double-precision floating-point scalars.
|
||||
/// @see gtc_ulp
|
||||
template<typename T, qualifier Q>
|
||||
GLM_FUNC_DECL vec<2, uint, Q> float_distance(vec<2, T, Q> const& x, vec<2, T, Q> const& y);
|
||||
template<typename T>
|
||||
GLM_FUNC_DECL int64 float_distance(double x, double y);
|
||||
|
||||
/// Return the distance in the number of ULP between single-precision floating-point 2 vectors.
|
||||
/// @see gtc_ulp
|
||||
template<length_t L, qualifier Q>
|
||||
GLM_FUNC_DECL vec<L, int, Q> float_distance(vec<L, float, Q> const& x, vec<L, float, Q> const& y);
|
||||
|
||||
/// Return the distance in the number of ULP between double-precision floating-point 2 vectors.
|
||||
/// @see gtc_ulp
|
||||
template<length_t L, qualifier Q>
|
||||
GLM_FUNC_DECL vec<L, int64, Q> float_distance(vec<L, double, Q> const& x, vec<L, double, Q> const& y);
|
||||
|
||||
/// @}
|
||||
}// namespace glm
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <limits>
|
||||
#include "../detail/type_float.hpp"
|
||||
|
||||
#if(GLM_COMPILER & GLM_COMPILER_VC)
|
||||
# pragma warning(push)
|
||||
@ -260,16 +261,16 @@ namespace glm
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GLM_FUNC_QUALIFIER T next_float(T const& x, uint const& ulps)
|
||||
GLM_FUNC_QUALIFIER T next_float(T const& x, int ulps)
|
||||
{
|
||||
T temp = x;
|
||||
for(uint i = 0; i < ulps; ++i)
|
||||
for(int i = 0; i < ulps; ++i)
|
||||
temp = next_float(temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
template<length_t L, typename T, qualifier Q>
|
||||
GLM_FUNC_QUALIFIER vec<L, T, Q> next_float(vec<L, T, Q> const& x, vec<L, uint, Q> const& ulps)
|
||||
GLM_FUNC_QUALIFIER vec<L, T, Q> next_float(vec<L, T, Q> const& x, vec<L, int, Q> const& ulps)
|
||||
{
|
||||
vec<L, T, Q> Result;
|
||||
for(length_t i = 0, n = Result.length(); i < n; ++i)
|
||||
@ -278,16 +279,18 @@ namespace glm
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GLM_FUNC_QUALIFIER T prev_float(T const& x, uint const& ulps)
|
||||
GLM_FUNC_QUALIFIER T prev_float(T const& x, int ulps)
|
||||
{
|
||||
assert(ulps >= 0);
|
||||
|
||||
T temp = x;
|
||||
for(uint i = 0; i < ulps; ++i)
|
||||
for(int i = 0; i < ulps; ++i)
|
||||
temp = prev_float(temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
template<length_t L, typename T, qualifier Q>
|
||||
GLM_FUNC_QUALIFIER vec<L, T, Q> prev_float(vec<L, T, Q> const& x, vec<L, uint, Q> const& ulps)
|
||||
GLM_FUNC_QUALIFIER vec<L, T, Q> prev_float(vec<L, T, Q> const& x, vec<L, int, Q> const& ulps)
|
||||
{
|
||||
vec<L, T, Q> Result;
|
||||
for(length_t i = 0, n = Result.length(); i < n; ++i)
|
||||
@ -295,41 +298,35 @@ namespace glm
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
GLM_FUNC_QUALIFIER uint float_distance(T const& x, T const& y)
|
||||
{
|
||||
uint ulp = 0;
|
||||
|
||||
if(x < y)
|
||||
{
|
||||
T temp = x;
|
||||
while(glm::epsilonNotEqual(temp, y, glm::epsilon<T>()))// && ulp < std::numeric_limits<std::size_t>::max())
|
||||
{
|
||||
++ulp;
|
||||
temp = next_float(temp);
|
||||
}
|
||||
}
|
||||
else if(y < x)
|
||||
{
|
||||
T temp = y;
|
||||
while(glm::epsilonNotEqual(temp, x, glm::epsilon<T>()))// && ulp < std::numeric_limits<std::size_t>::max())
|
||||
{
|
||||
++ulp;
|
||||
temp = next_float(temp);
|
||||
}
|
||||
}
|
||||
else // ==
|
||||
GLM_FUNC_QUALIFIER int float_distance(float x, float y)
|
||||
{
|
||||
detail::float_t<float> const a(x);
|
||||
detail::float_t<float> const b(y);
|
||||
|
||||
return abs(a.i - b.i);
|
||||
}
|
||||
|
||||
return ulp;
|
||||
GLM_FUNC_QUALIFIER int64 float_distance(double x, double y)
|
||||
{
|
||||
detail::float_t<double> const a(x);
|
||||
detail::float_t<double> const b(y);
|
||||
|
||||
return abs(a.i - b.i);
|
||||
}
|
||||
|
||||
template<length_t L, typename T, qualifier Q>
|
||||
GLM_FUNC_QUALIFIER vec<L, uint, Q> float_distance(vec<L, T, Q> const& x, vec<L, T, Q> const& y)
|
||||
template<length_t L, qualifier Q>
|
||||
GLM_FUNC_QUALIFIER vec<L, int, Q> float_distance(vec<L, float, Q> const& x, vec<L, float, Q> const& y)
|
||||
{
|
||||
vec<L, uint, Q> Result;
|
||||
vec<L, int, Q> Result;
|
||||
for(length_t i = 0, n = Result.length(); i < n; ++i)
|
||||
Result[i] = float_distance(x[i], y[i]);
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<length_t L, qualifier Q>
|
||||
GLM_FUNC_QUALIFIER vec<L, int64, Q> float_distance(vec<L, double, Q> const& x, vec<L, double, Q> const& y)
|
||||
{
|
||||
vec<L, int64, Q> Result;
|
||||
for(length_t i = 0, n = Result.length(); i < n; ++i)
|
||||
Result[i] = float_distance(x[i], y[i]);
|
||||
return Result;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <glm/gtc/ulp.hpp>
|
||||
#include <glm/gtc/epsilon.hpp>
|
||||
#include <glm/ext/scalar_relational.hpp>
|
||||
#include <limits>
|
||||
|
||||
int test_ulp_float_dist()
|
||||
@ -9,9 +9,9 @@ int test_ulp_float_dist()
|
||||
float A = 1.0f;
|
||||
|
||||
float B = glm::next_float(A);
|
||||
Error += !glm::epsilonEqual(A, B, glm::epsilon<float>()) ? 0 : 1;
|
||||
Error += glm::notEqual(A, B, 0) ? 0 : 1;
|
||||
float C = glm::prev_float(B);
|
||||
Error += glm::epsilonEqual(A, C, glm::epsilon<float>()) ? 0 : 1;
|
||||
Error += glm::equal(A, C, 0) ? 0 : 1;
|
||||
|
||||
int D = glm::float_distance(A, B);
|
||||
Error += D == 1 ? 0 : 1;
|
||||
@ -30,9 +30,9 @@ int test_ulp_float_step()
|
||||
for(int i = 10; i < 1000; i *= 10)
|
||||
{
|
||||
float B = glm::next_float(A, i);
|
||||
Error += !glm::epsilonEqual(A, B, glm::epsilon<float>()) ? 0 : 1;
|
||||
Error += glm::notEqual(A, B, 0) ? 0 : 1;
|
||||
float C = glm::prev_float(B, i);
|
||||
Error += glm::epsilonEqual(A, C, glm::epsilon<float>()) ? 0 : 1;
|
||||
Error += glm::equal(A, C, 0) ? 0 : 1;
|
||||
|
||||
int D = glm::float_distance(A, B);
|
||||
Error += D == i ? 0 : 1;
|
||||
@ -50,13 +50,13 @@ int test_ulp_double_dist()
|
||||
double A = 1.0;
|
||||
|
||||
double B = glm::next_float(A);
|
||||
Error += !glm::epsilonEqual(A, B, glm::epsilon<double>()) ? 0 : 1;
|
||||
Error += glm::notEqual(A, B, 0) ? 0 : 1;
|
||||
double C = glm::prev_float(B);
|
||||
Error += glm::epsilonEqual(A, C, glm::epsilon<double>()) ? 0 : 1;
|
||||
Error += glm::equal(A, C, 0) ? 0 : 1;
|
||||
|
||||
int D = glm::float_distance(A, B);
|
||||
glm::int64 const D = glm::float_distance(A, B);
|
||||
Error += D == 1 ? 0 : 1;
|
||||
int E = glm::float_distance(A, C);
|
||||
glm::int64 const E = glm::float_distance(A, C);
|
||||
Error += E == 0 ? 0 : 1;
|
||||
|
||||
return Error;
|
||||
@ -71,13 +71,13 @@ int test_ulp_double_step()
|
||||
for(int i = 10; i < 1000; i *= 10)
|
||||
{
|
||||
double B = glm::next_float(A, i);
|
||||
Error += !glm::epsilonEqual(A, B, glm::epsilon<double>()) ? 0 : 1;
|
||||
Error += glm::notEqual(A, B, 0) ? 0 : 1;
|
||||
double C = glm::prev_float(B, i);
|
||||
Error += glm::epsilonEqual(A, C, glm::epsilon<double>()) ? 0 : 1;
|
||||
Error += glm::equal(A, C, 0) ? 0 : 1;
|
||||
|
||||
int D = glm::float_distance(A, B);
|
||||
glm::int64 const D = glm::float_distance(A, B);
|
||||
Error += D == i ? 0 : 1;
|
||||
int E = glm::float_distance(A, C);
|
||||
glm::int64 const E = glm::float_distance(A, C);
|
||||
Error += E == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
@ -87,10 +87,12 @@ int test_ulp_double_step()
|
||||
int main()
|
||||
{
|
||||
int Error = 0;
|
||||
|
||||
Error += test_ulp_float_dist();
|
||||
Error += test_ulp_float_step();
|
||||
Error += test_ulp_double_dist();
|
||||
Error += test_ulp_double_step();
|
||||
|
||||
return Error;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user