Get rid of gmio_floatXX_t typedefs

This commit is contained in:
Hugues Delorme 2016-01-26 16:00:36 +01:00
parent 8a5f626663
commit 0c15f9f325
11 changed files with 262 additions and 45 deletions

View File

@ -152,13 +152,6 @@ enum gmio_bool_value
typedef int_or_bool gmio_bool_t;
#endif /* GMIO_HAVE_STDBOOL_H */
/* Float types */
/*! Typedef for 32bit real type (float) */
typedef float gmio_float32_t;
/*! Typedef for 64bit real type (double) */
typedef double gmio_float64_t;
/* GMIO_UNUSED */
/*! Tells the compiler that a parameter is not used in the body of a function */
#define GMIO_UNUSED(x) (void)x;

View File

@ -20,38 +20,38 @@
union gmio_uint_float_32
{
uint32_t as_uint32;
gmio_float32_t as_float32;
uint32_t as_uint32;
float as_float32;
};
union gmio_int_float_32
{
int32_t as_int32;
gmio_float32_t as_float32;
int32_t as_int32;
float as_float32;
};
GMIO_INLINE gmio_float32_t gmio_convert_ufloat32(uint32_t val)
GMIO_INLINE float gmio_convert_ufloat32(uint32_t val)
{
union gmio_uint_float_32 conv;
conv.as_uint32 = val;
return conv.as_float32;
}
GMIO_INLINE uint32_t gmio_convert_uint32(gmio_float32_t val)
GMIO_INLINE uint32_t gmio_convert_uint32(float val)
{
union gmio_uint_float_32 conv;
conv.as_float32 = val;
return conv.as_uint32;
}
GMIO_INLINE gmio_float32_t gmio_convert_sfloat32(int32_t val)
GMIO_INLINE float gmio_convert_sfloat32(int32_t val)
{
union gmio_int_float_32 conv;
conv.as_int32 = val;
return conv.as_float32;
}
GMIO_INLINE int32_t gmio_convert_int32(gmio_float32_t val)
GMIO_INLINE int32_t gmio_convert_int32(float val)
{
union gmio_int_float_32 conv;
conv.as_float32 = val;

View File

@ -25,6 +25,231 @@ GMIO_INLINE gmio_bool_t is_local_decimal_point(char in)
return in == '.';
}
/* #define ASSIMP_FAST_ATOF */
#define IRRLICH_FAST_ATOF
#if defined(ASSIMP_FAST_ATOF)
static const double fast_atof_table[16] = { // we write [16] here instead of [] to work around a swig bug
0.0,
0.1,
0.01,
0.001,
0.0001,
0.00001,
0.000001,
0.0000001,
0.00000001,
0.000000001,
0.0000000001,
0.00000000001,
0.000000000001,
0.0000000000001,
0.00000000000001,
0.000000000000001
};
/* ------------------------------------------------------------------------------------
* Special version of the function, providing higher accuracy and safety
* It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
* ------------------------------------------------------------------------------------ */
GMIO_INLINE uint64_t strtoul10_64( const char* in, const char** out, unsigned int* max_inout)
{
unsigned int cur = 0;
uint64_t value = 0;
const gmio_bool_t running = GMIO_TRUE;
if ( !gmio_ascii_isdigit(*in) )
return value;
/* throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value."); */
while ( running )
{
const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
if ( !gmio_ascii_isdigit(*in) )
break;
if (new_value < value) /* numeric overflow, we rely on you */
return value;
/* throw std::overflow_error(std::string("Converting the string \"") + in + "\" into a value resulted in overflow."); */
value = new_value;
++in;
++cur;
if (max_inout && *max_inout == cur) {
if (out) { /* skip to end */
while (gmio_ascii_isdigit(*in))
++in;
*out = in;
}
return value;
}
}
if (out)
*out = in;
if (max_inout)
*max_inout = cur;
return value;
}
/* ------------------------------------------------------------------------------------
* signed variant of strtoul10_64
* ------------------------------------------------------------------------------------*/
GMIO_INLINE int64_t strtol10_64(const char* in, const char** out, unsigned int* max_inout)
{
const gmio_bool_t inv = (*in == '-');
int64_t value;
if (inv || *in == '+')
++in;
value = strtoul10_64(in, out, max_inout);
if (inv) {
value = -value;
}
return value;
}
/* Number of relevant decimals for floating-point parsing. */
#define AI_FAST_ATOF_RELAVANT_DECIMALS 15
/* ------------------------------------------------------------------------------------
* Provides a fast function for converting a string into a float,
* about 6 times faster than atof in win32.
* If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
* ------------------------------------------------------------------------------------*/
GMIO_INLINE const char* fast_atoreal_move(const char* c, double* out, gmio_bool_t check_comma)
{
double f = 0;
const gmio_bool_t inv = (*c == '-');
if (inv || *c == '+') {
++c;
}
if ((c[0] == 'N' || c[0] == 'n') && gmio_ascii_strincmp(c, "nan", 3) == 0)
{
/* TODO: write NAN */
/* out = std::numeric_limits<Real>::quiet_NaN(); */
c += 3;
return c;
}
if ((c[0] == 'I' || c[0] == 'i') && gmio_ascii_strincmp(c, "inf", 3) == 0)
{
/* TODO: write INF */
/* out = std::numeric_limits<Real>::infinity(); */
if (inv) {
*out = -(*out);
}
c += 3;
if ((c[0] == 'I' || c[0] == 'i') && gmio_ascii_strincmp(c, "inity", 5) == 0)
{
c += 5;
}
return c;
}
if (!gmio_ascii_isdigit(c[0]) &&
!((c[0] == '.' || (check_comma && c[0] == ',')) && gmio_ascii_isdigit(c[1])))
{
return c;
/*throw std::invalid_argument("Cannot parse string "
"as real number: does not start with digit "
"or decimal point followed by digit.");*/
}
if (*c != '.' && (!check_comma || c[0] != ','))
{
f = (double)strtoul10_64(c, &c, NULL);
}
if ((*c == '.' || (check_comma && c[0] == ',')) && gmio_ascii_isdigit(c[1]))
{
unsigned int diff = AI_FAST_ATOF_RELAVANT_DECIMALS;
double pl;
++c;
/* NOTE: The original implementation is highly inaccurate here. The precision of a single
* IEEE 754 float is not high enough, everything behind the 6th digit tends to be more
* inaccurate than it would need to be. Casting to double seems to solve the problem.
* strtol_64 is used to prevent integer overflow.
*
* Another fix: this tends to become 0 for long numbers if we don't limit the maximum
* number of digits to be read. AI_FAST_ATOF_RELAVANT_DECIMALS can be a value between
* 1 and 15. */
pl = (double)strtoul10_64(c, &c, &diff);
pl *= fast_atof_table[diff];
f += pl;
}
/* For backwards compatibility: eat trailing dots, but not trailing commas. */
else if (*c == '.') {
++c;
}
/* A major 'E' must be allowed. Necessary for proper reading of some DXF files.
* Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..) */
if (*c == 'e' || *c == 'E') {
const gmio_bool_t einv = (*(c+1)=='-');
double exp;
++c;
if (einv || *c=='+') {
++c;
}
/* The reason float constants are used here is that we've seen cases where compilers
* would perform such casts on compile-time constants at runtime, which would be
* bad considering how frequently fast_atoreal_move<float> is called in Assimp. */
exp = (double)strtoul10_64(c, &c, NULL);
if (einv) {
exp = -exp;
}
f *= pow(10.0, exp);
}
if (inv) {
f = -f;
}
*out = f;
return c;
}
GMIO_INLINE float fast_atof(const char* c)
{
double ret;
fast_atoreal_move(c, &ret, GMIO_TRUE);
return (float)ret;
}
GMIO_INLINE double fast_atod(const char* c)
{
double ret;
fast_atoreal_move(c, &ret, GMIO_TRUE);
return ret;
}
GMIO_INLINE float fast_strtof(const char* str, const char** out)
{
double ret;
if (out)
*out = fast_atoreal_move(str, &ret, GMIO_TRUE);
else
fast_atoreal_move(str, &ret, GMIO_TRUE);
return (float)ret;
}
#elif defined(IRRLICH_FAST_ATOF)
/* we write [17] here instead of [] to work around a swig bug */
static const float fast_atof_table[17] = {
0.f,
@ -184,5 +409,6 @@ GMIO_INLINE float fast_atof(const char* str)
fast_atof_move(str, &ret);
return ret;
}
#endif
#endif /* GMIO_INTERNAL_FAST_ATOF_H */

View File

@ -15,8 +15,7 @@
#include "numeric_utils.h"
gmio_bool_t gmio_float32_ulp_equals(
gmio_float32_t a, gmio_float32_t b, uint32_t max_ulp_diff)
gmio_bool_t gmio_float32_ulp_equals(float a, float b, uint32_t max_ulp_diff)
{
const int32_t ia = gmio_convert_int32(a);
const int32_t ib = gmio_convert_int32(b);

View File

@ -28,17 +28,16 @@
* See:
* http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
*/
gmio_bool_t gmio_float32_ulp_equals(
gmio_float32_t a, gmio_float32_t b, uint32_t max_ulp_diff);
gmio_bool_t gmio_float32_ulp_equals(float a, float b, uint32_t max_ulp_diff);
/*! Count of ULP between \p a and \p b */
GMIO_INLINE uint32_t gmio_float32_ulp_diff(gmio_float32_t a, gmio_float32_t b);
GMIO_INLINE uint32_t gmio_float32_ulp_diff(float a, float b);
/*! Portable sign-extraction for int32 */
GMIO_INLINE int gmio_int32_sign(int32_t v);
/*! Portable sign-extraction for float32 */
GMIO_INLINE int gmio_float32_sign(gmio_float32_t v);
GMIO_INLINE int gmio_float32_sign(float v);
@ -46,7 +45,7 @@ GMIO_INLINE int gmio_float32_sign(gmio_float32_t v);
* Implementation
*/
uint32_t gmio_float32_ulp_diff(gmio_float32_t a, gmio_float32_t b)
uint32_t gmio_float32_ulp_diff(float a, float b)
{
const uint32_t ua = gmio_convert_uint32(a);
const uint32_t ub = gmio_convert_uint32(b);
@ -58,7 +57,7 @@ int gmio_int32_sign(int32_t v)
return (v & 0x80000000) != 0 ? -1 : 1;
}
int gmio_float32_sign(gmio_float32_t v)
int gmio_float32_sign(float v)
{
return gmio_int32_sign(gmio_convert_int32(v));
}

View File

@ -100,7 +100,7 @@ gmio_bool_t gmio_stringstream_checked_next_chars(
#endif
/*! Parses float from stringstream \p sstream */
GMIO_INLINE gmio_float32_t gmio_stringstream_parse_float32(
GMIO_INLINE float gmio_stringstream_parse_float32(
struct gmio_stringstream* sstream);
/*! Converts C string \p str to float
@ -110,13 +110,13 @@ GMIO_INLINE gmio_float32_t gmio_stringstream_parse_float32(
*
* TODO: move to another header
*/
GMIO_INLINE int gmio_get_float32(const char* str, gmio_float32_t* value_ptr);
GMIO_INLINE int gmio_get_float32(const char* str, float* value_ptr);
/*! Converts C string \p str to float
*
* TODO: move to another header
*/
GMIO_INLINE gmio_float32_t gmio_to_float32(const char* str);
GMIO_INLINE float gmio_to_float32(const char* str);
@ -191,7 +191,7 @@ void gmio_stringstream_copy_ascii_spaces(
}
}
int gmio_get_float32(const char* str, gmio_float32_t* value_ptr)
int gmio_get_float32(const char* str, float* value_ptr)
{
#if defined(GMIO_STRINGSTREAM_USE_FAST_ATOF)
const char* end_ptr = NULL;
@ -201,23 +201,23 @@ int gmio_get_float32(const char* str, gmio_float32_t* value_ptr)
*value_ptr = strtof(str, &end_ptr);
#else
char* end_ptr = NULL;
*value_ptr = (gmio_float32_t)strtod(str, &end_ptr);
*value_ptr = (float)strtod(str, &end_ptr);
#endif
return (end_ptr == str || errno == ERANGE) ? -1 : 0;
}
gmio_float32_t gmio_to_float32(const char* str)
float gmio_to_float32(const char* str)
{
#if defined(GMIO_STRINGSTREAM_USE_FAST_ATOF)
return fast_atof(str);
#elif defined(GMIO_HAVE_STRTOF_FUNC) /* Requires C99 */
return strtof(str, NULL);
#else
return (gmio_float32_t)strtod(str, NULL);
return (float)strtod(str, NULL);
#endif
}
gmio_float32_t gmio_stringstream_parse_float32(struct gmio_stringstream* sstream)
float gmio_stringstream_parse_float32(struct gmio_stringstream* sstream)
{
#if defined(GMIO_STRINGSTREAM_USE_FAST_ATOF)
return gmio_stringstream_fast_atof(sstream);
@ -225,7 +225,7 @@ gmio_float32_t gmio_stringstream_parse_float32(struct gmio_stringstream* sstream
char strbuff_ptr[64];
struct gmio_string strbuff = { &strbuff_ptr[0], 0, sizeof(strbuff_ptr) };
gmio_stringstream_eat_word(sstream, &strbuff);
return (gmio_float32_t)atof(strbuff_ptr);
return (float)atof(strbuff_ptr);
#endif
}

View File

@ -28,7 +28,7 @@
enum gmio_stl_constants
{
/*! Compact size of a gmio_stl_coords object */
GMIO_STL_COORDS_RAWSIZE = (3 * sizeof(gmio_float32_t)),
GMIO_STL_COORDS_RAWSIZE = (3 * sizeof(float)),
/*! Compact size of a gmio_stl_triangle object, STL ascii format */
GMIO_STLA_TRIANGLE_RAWSIZE = (4 * GMIO_STL_COORDS_RAWSIZE),

View File

@ -31,11 +31,11 @@
enum { GMIO_FIXED_BUFFER_SIZE = 1024 };
GMIO_INLINE gmio_float32_t gmio_sqrlen(const struct gmio_stl_coords* c)
GMIO_INLINE float gmio_sqrlen(const struct gmio_stl_coords* c)
{
const gmio_float32_t cx = c->x;
const gmio_float32_t cy = c->y;
const gmio_float32_t cz = c->z;
const float cx = c->x;
const float cy = c->y;
const float cz = c->z;
return cx*cx + cy*cy + cz*cz;
}

View File

@ -29,9 +29,9 @@
* STL needs (single-float) */
struct gmio_stl_coords
{
gmio_float32_t x;
gmio_float32_t y;
gmio_float32_t z;
float x;
float y;
float z;
};
/*! STL mesh triangle defined three geometric vertices and an

View File

@ -86,11 +86,11 @@ static void gmio_test_atof_fprintf_err(
static gmio_bool_t gmio_test_calculation_atof(const char* val_str)
{
const gmio_float32_t std_val = (gmio_float32_t)strtod(val_str, NULL);
const float std_val = (float)strtod(val_str, NULL);
int accurate_count = 0;
{ /* Test fast_atof() */
const gmio_float32_t fast_val = fast_atof(val_str);
const float fast_val = fast_atof(val_str);
if (gmio_float32_ulp_equals(fast_val, std_val, 1))
++accurate_count;
else
@ -105,7 +105,7 @@ static gmio_bool_t gmio_test_calculation_atof(const char* val_str)
gmio_stringstream(
gmio_istream_buffer(&ibuff),
gmio_string(iobuff, 0, sizeof(iobuff)));
const gmio_float32_t fast_val = gmio_stringstream_fast_atof(&sstream);
const float fast_val = gmio_stringstream_fast_atof(&sstream);
if (gmio_float32_ulp_equals(fast_val, std_val, 1)) {
++accurate_count;
}

View File

@ -59,8 +59,8 @@ const char* test_platform__global_h()
UTEST_ASSERT(sizeof(uint64_t) == 8);
#endif
UTEST_ASSERT(sizeof(gmio_float32_t) == 4);
UTEST_ASSERT(sizeof(gmio_float64_t) == 8);
UTEST_ASSERT(sizeof(float) == 4);
UTEST_ASSERT(sizeof(double) == 8);
return NULL;
}