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