Added constant time ULP distance between float #121

This commit is contained in:
Christophe Riccio 2018-09-26 12:09:06 +02:00
parent 0f4a597f10
commit 59cae7b5cb
3 changed files with 66 additions and 56 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;
}