322 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /// @ref gtc_ulp
 | |
| /// @file glm/gtc/ulp.inl
 | |
| ///
 | |
| /// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 | |
| ///
 | |
| /// Developed at SunPro, a Sun Microsystems, Inc. business.
 | |
| /// Permission to use, copy, modify, and distribute this
 | |
| /// software is freely granted, provided that this notice
 | |
| /// is preserved.
 | |
| 
 | |
| #include "../detail/type_int.hpp"
 | |
| #include <cmath>
 | |
| #include <cfloat>
 | |
| #include <limits>
 | |
| 
 | |
| #if(GLM_COMPILER & GLM_COMPILER_VC)
 | |
| #	pragma warning(push)
 | |
| #	pragma warning(disable : 4127)
 | |
| #endif
 | |
| 
 | |
| typedef union
 | |
| {
 | |
| 	float value;
 | |
| 	/* FIXME: Assumes 32 bit int.  */
 | |
| 	unsigned int word;
 | |
| } ieee_float_shape_type;
 | |
| 
 | |
| typedef union
 | |
| {
 | |
| 	double value;
 | |
| 	struct
 | |
| 	{
 | |
| 		glm::detail::int32 lsw;
 | |
| 		glm::detail::int32 msw;
 | |
| 	} parts;
 | |
| } ieee_double_shape_type;
 | |
| 
 | |
| #define GLM_EXTRACT_WORDS(ix0,ix1,d)		\
 | |
| 	do {									\
 | |
| 		ieee_double_shape_type ew_u;		\
 | |
| 		ew_u.value = (d);					\
 | |
| 		(ix0) = ew_u.parts.msw;				\
 | |
| 		(ix1) = ew_u.parts.lsw;				\
 | |
| 	} while (0)
 | |
| 
 | |
| #define GLM_GET_FLOAT_WORD(i,d)				\
 | |
| 	do {									\
 | |
| 		ieee_float_shape_type gf_u;			\
 | |
| 		gf_u.value = (d);					\
 | |
| 		(i) = gf_u.word;					\
 | |
| 	} while (0)
 | |
| 
 | |
| #define GLM_SET_FLOAT_WORD(d,i)				\
 | |
| 	do {									\
 | |
| 		ieee_float_shape_type sf_u;			\
 | |
| 		sf_u.word = (i);					\
 | |
| 		(d) = sf_u.value;					\
 | |
| 	} while (0)
 | |
| 
 | |
| #define GLM_INSERT_WORDS(d,ix0,ix1)			\
 | |
| 	do {									\
 | |
| 		ieee_double_shape_type iw_u;		\
 | |
| 		iw_u.parts.msw = (ix0);				\
 | |
| 		iw_u.parts.lsw = (ix1);				\
 | |
| 		(d) = iw_u.value;					\
 | |
| 	} while (0)
 | |
| 
 | |
| namespace glm{
 | |
| namespace detail
 | |
| {
 | |
| 	GLM_FUNC_QUALIFIER float nextafterf(float x, float y)
 | |
| 	{
 | |
| 		volatile float t;
 | |
| 		glm::detail::int32 hx, hy, ix, iy;
 | |
| 
 | |
| 		GLM_GET_FLOAT_WORD(hx, x);
 | |
| 		GLM_GET_FLOAT_WORD(hy, y);
 | |
| 		ix = hx&0x7fffffff;		// |x|
 | |
| 		iy = hy&0x7fffffff;		// |y|
 | |
| 
 | |
| 		if((ix>0x7f800000) ||	// x is nan 
 | |
| 			(iy>0x7f800000))	// y is nan 
 | |
| 			return x+y;
 | |
| 		if(x==y) return y;		// x=y, return y
 | |
| 		if(ix==0) {				// x == 0
 | |
| 			GLM_SET_FLOAT_WORD(x,(hy&0x80000000)|1);// return +-minsubnormal
 | |
| 			t = x*x;
 | |
| 			if(t==x) return t; else return x;	// raise underflow flag
 | |
| 		}
 | |
| 		if(hx>=0) {				// x > 0 
 | |
| 			if(hx>hy) {			// x > y, x -= ulp
 | |
| 				hx -= 1;
 | |
| 			} else {			// x < y, x += ulp
 | |
| 				hx += 1;
 | |
| 			}
 | |
| 		} else {				// x < 0
 | |
| 			if(hy>=0||hx>hy){	// x < y, x -= ulp
 | |
| 				hx -= 1;
 | |
| 			} else {			// x > y, x += ulp
 | |
| 				hx += 1;
 | |
| 			}
 | |
| 		}
 | |
| 		hy = hx&0x7f800000;
 | |
| 		if(hy>=0x7f800000) return x+x;  // overflow
 | |
| 		if(hy<0x00800000) {             // underflow
 | |
| 			t = x*x;
 | |
| 			if(t!=x) {          // raise underflow flag
 | |
| 				GLM_SET_FLOAT_WORD(y,hx);
 | |
| 				return y;
 | |
| 			}
 | |
| 		}
 | |
| 		GLM_SET_FLOAT_WORD(x,hx);
 | |
| 		return x;
 | |
| 	}
 | |
| 
 | |
| 	GLM_FUNC_QUALIFIER double nextafter(double x, double y)
 | |
| 	{
 | |
| 		volatile double t;
 | |
| 		glm::detail::int32 hx, hy, ix, iy;
 | |
| 		glm::detail::uint32 lx, ly;
 | |
| 
 | |
| 		GLM_EXTRACT_WORDS(hx, lx, x);
 | |
| 		GLM_EXTRACT_WORDS(hy, ly, y);
 | |
| 		ix = hx & 0x7fffffff;             // |x| 
 | |
| 		iy = hy & 0x7fffffff;             // |y| 
 | |
| 
 | |
| 		if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   // x is nan
 | |
| 			((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))     // y is nan
 | |
| 			return x+y;
 | |
| 		if(x==y) return y;              // x=y, return y
 | |
| 		if((ix|lx)==0) {                        // x == 0 
 | |
| 			GLM_INSERT_WORDS(x, hy & 0x80000000, 1);    // return +-minsubnormal
 | |
| 			t = x*x;
 | |
| 			if(t==x) return t; else return x;   // raise underflow flag 
 | |
| 		}
 | |
| 		if(hx>=0) {                             // x > 0 
 | |
| 			if(hx>hy||((hx==hy)&&(lx>ly))) {    // x > y, x -= ulp 
 | |
| 				if(lx==0) hx -= 1;
 | |
| 				lx -= 1;
 | |
| 			} else {                            // x < y, x += ulp
 | |
| 				lx += 1;
 | |
| 				if(lx==0) hx += 1;
 | |
| 			}
 | |
| 		} else {                                // x < 0 
 | |
| 			if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){// x < y, x -= ulp
 | |
| 				if(lx==0) hx -= 1;
 | |
| 				lx -= 1;
 | |
| 			} else {                            // x > y, x += ulp
 | |
| 				lx += 1;
 | |
| 				if(lx==0) hx += 1;
 | |
| 			}
 | |
| 		}
 | |
| 		hy = hx&0x7ff00000;
 | |
| 		if(hy>=0x7ff00000) return x+x;  // overflow
 | |
| 		if(hy<0x00100000) {             // underflow
 | |
| 			t = x*x;
 | |
| 			if(t!=x) {          // raise underflow flag
 | |
| 				GLM_INSERT_WORDS(y,hx,lx);
 | |
| 				return y;
 | |
| 			}
 | |
| 		}
 | |
| 		GLM_INSERT_WORDS(x,hx,lx);
 | |
| 		return x;
 | |
| 	}
 | |
| }//namespace detail
 | |
| }//namespace glm
 | |
| 
 | |
| #if(GLM_COMPILER & GLM_COMPILER_VC)
 | |
| #	pragma warning(pop)
 | |
| #endif
 | |
| 
 | |
| namespace glm
 | |
| {
 | |
| 	template <>
 | |
| 	GLM_FUNC_QUALIFIER float next_float(float const & x)
 | |
| 	{
 | |
| #		if GLM_HAS_CXX11_STL
 | |
| 			return std::nextafter(x, std::numeric_limits<float>::max());
 | |
| #		elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))
 | |
| 			return detail::nextafterf(x, FLT_MAX);
 | |
| #		elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
 | |
| 			return __builtin_nextafterf(x, FLT_MAX);
 | |
| #		else
 | |
| 			return nextafterf(x, FLT_MAX);
 | |
| #		endif
 | |
| 	}
 | |
| 
 | |
| 	template <>
 | |
| 	GLM_FUNC_QUALIFIER double next_float(double const & x)
 | |
| 	{
 | |
| #		if GLM_HAS_CXX11_STL
 | |
| 			return std::nextafter(x, std::numeric_limits<double>::max());
 | |
| #		elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))
 | |
| 			return detail::nextafter(x, std::numeric_limits<double>::max());
 | |
| #		elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
 | |
| 			return __builtin_nextafter(x, FLT_MAX);
 | |
| #		else
 | |
| 			return nextafter(x, DBL_MAX);
 | |
| #		endif
 | |
| 	}
 | |
| 
 | |
| 	template<typename T, precision P, template<typename, precision> class vecType>
 | |
| 	GLM_FUNC_QUALIFIER vecType<T, P> next_float(vecType<T, P> const & x)
 | |
| 	{
 | |
| 		vecType<T, P> Result(uninitialize);
 | |
| 		for(length_t i = 0, n = Result.length(); i < n; ++i)
 | |
| 			Result[i] = next_float(x[i]);
 | |
| 		return Result;
 | |
| 	}
 | |
| 
 | |
| 	GLM_FUNC_QUALIFIER float prev_float(float const & x)
 | |
| 	{
 | |
| #		if GLM_HAS_CXX11_STL
 | |
| 			return std::nextafter(x, std::numeric_limits<float>::min());
 | |
| #		elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))
 | |
| 			return detail::nextafterf(x, FLT_MIN);
 | |
| #		elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
 | |
| 			return __builtin_nextafterf(x, FLT_MIN);
 | |
| #		else
 | |
| 			return nextafterf(x, FLT_MIN);
 | |
| #		endif
 | |
| 	}
 | |
| 
 | |
| 	GLM_FUNC_QUALIFIER double prev_float(double const & x)
 | |
| 	{
 | |
| #		if GLM_HAS_CXX11_STL
 | |
| 			return std::nextafter(x, std::numeric_limits<double>::min());
 | |
| #		elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))
 | |
| 			return _nextafter(x, DBL_MIN);
 | |
| #		elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
 | |
| 			return __builtin_nextafter(x, DBL_MIN);
 | |
| #		else
 | |
| 			return nextafter(x, DBL_MIN);
 | |
| #		endif
 | |
| 	}
 | |
| 
 | |
| 	template<typename T, precision P, template<typename, precision> class vecType>
 | |
| 	GLM_FUNC_QUALIFIER vecType<T, P> prev_float(vecType<T, P> const & x)
 | |
| 	{
 | |
| 		vecType<T, P> Result(uninitialize);
 | |
| 		for(length_t i = 0, n = Result.length(); i < n; ++i)
 | |
| 			Result[i] = prev_float(x[i]);
 | |
| 		return Result;
 | |
| 	}
 | |
| 
 | |
| 	template <typename T>
 | |
| 	GLM_FUNC_QUALIFIER T next_float(T const & x, uint const & ulps)
 | |
| 	{
 | |
| 		T temp = x;
 | |
| 		for(uint i = 0; i < ulps; ++i)
 | |
| 			temp = next_float(temp);
 | |
| 		return temp;
 | |
| 	}
 | |
| 
 | |
| 	template<typename T, precision P, template<typename, precision> class vecType>
 | |
| 	GLM_FUNC_QUALIFIER vecType<T, P> next_float(vecType<T, P> const & x, vecType<uint, P> const & ulps)
 | |
| 	{
 | |
| 		vecType<T, P> Result(uninitialize);
 | |
| 		for(length_t i = 0, n = Result.length(); i < n; ++i)
 | |
| 			Result[i] = next_float(x[i], ulps[i]);
 | |
| 		return Result;
 | |
| 	}
 | |
| 
 | |
| 	template <typename T>
 | |
| 	GLM_FUNC_QUALIFIER T prev_float(T const & x, uint const & ulps)
 | |
| 	{
 | |
| 		T temp = x;
 | |
| 		for(uint i = 0; i < ulps; ++i)
 | |
| 			temp = prev_float(temp);
 | |
| 		return temp;
 | |
| 	}
 | |
| 
 | |
| 	template<typename T, precision P, template<typename, precision> class vecType>
 | |
| 	GLM_FUNC_QUALIFIER vecType<T, P> prev_float(vecType<T, P> const & x, vecType<uint, P> const & ulps)
 | |
| 	{
 | |
| 		vecType<T, P> Result(uninitialize);
 | |
| 		for(length_t i = 0, n = Result.length(); i < n; ++i)
 | |
| 			Result[i] = prev_float(x[i], ulps[i]);
 | |
| 		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(temp != y)// && ulp < std::numeric_limits<std::size_t>::max())
 | |
| 			{
 | |
| 				++ulp;
 | |
| 				temp = next_float(temp);
 | |
| 			}
 | |
| 		}
 | |
| 		else if(y < x)
 | |
| 		{
 | |
| 			T temp = y;
 | |
| 			while(temp != x)// && ulp < std::numeric_limits<std::size_t>::max())
 | |
| 			{
 | |
| 				++ulp;
 | |
| 				temp = next_float(temp);
 | |
| 			}
 | |
| 		}
 | |
| 		else // ==
 | |
| 		{
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 		return ulp;
 | |
| 	}
 | |
| 
 | |
| 	template<typename T, precision P, template<typename, precision> class vecType>
 | |
| 	GLM_FUNC_QUALIFIER vecType<uint, P> float_distance(vecType<T, P> const & x, vecType<T, P> const & y)
 | |
| 	{
 | |
| 		vecType<uint, P> Result(uninitialize);
 | |
| 		for(length_t i = 0, n = Result.length(); i < n; ++i)
 | |
| 			Result[i] = float_distance(x[i], y[i]);
 | |
| 		return Result;
 | |
| 	}
 | |
| }//namespace glm
 | 
