[amx-netlinx-common] r35 committed - Right... just a few changes. Here we go:...

4 views
Skip to first unread message

amx-netli...@googlecode.com

unread,
May 28, 2010, 3:00:08 AM5/28/10
to netlinx-comm...@googlegroups.com
Revision: 35
Author: kim.john.burgess
Date: Thu May 27 23:58:59 2010
Log: Right... just a few changes. Here we go:
- Increased default math library precision
- Modified math_raw_be_to_long() to increase performance
- Removed unused math_slong_to_bits() function
- Removed unnecessary parenthesis
- Renamed math_is_whole_number() to is_int() and re-wrote to function over
all possible double precision floating point values
- Added is_Nan()
- Added is_infinite()
- Re-wrote ceil() to use functionality provided by floor()
- Re-wrote floor to behave well with NaN's, +/-infinity, +/- 0 and
subnormals (still relies on type cast to long though so breaks above 2^32)
- Added IEEEremainder()
- Modified sqrt() to behave well with NaN's, +/-infinity and 0 and limited
to max 1000 refinements
- Re-wrote fast_inv_sqrt() to function with a double as input
- Modified fast_sqrt() to function with a double as input
- Moved test_error() to test_math.axi
- Wrote math library test suite (still needs a bit more work)
- Misc commenting improvements
- Removed trailing whitespace
- Set svn:ignore properties for /test
http://code.google.com/p/amx-netlinx-common/source/detail?r=35

Modified:
/trunk/math.axi
/trunk/string.axi
/trunk/test
/trunk/test/test_math.axi
/trunk/test_utils.axi

=======================================
--- /trunk/math.axi Mon May 24 22:55:23 2010
+++ /trunk/math.axi Thu May 27 23:58:59 2010
@@ -34,7 +34,7 @@

// Precision required for processor intensive math functions. If accuracy
is
// not integral to their use this may be increased to improve performance.
-double MATH_PRECISION = 1.0e-6
+double MATH_PRECISION = 1.0e-13


define_variable
@@ -43,6 +43,7 @@
volatile double MATH_NaN
volatile double MATH_POSITIVE_INFINITY
volatile double MATH_NEGATIVE_INFINITY
+volatile double MATH_TWO_52


/**
@@ -55,23 +56,7 @@
*/
define_function long math_raw_be_to_long(char x[4])
{
- stack_var char byte
- stack_var long bits
- FOR (byte = 4; byte; byte--) {
- bits = bits + (x[byte] << ((4 - byte) << 3))
- }
- return bits
-}
-
-/**
- * Load a signed long's bit pattern into a long.
- *
- * @param x the slong to load
- * @return a long filled with the bit pattern of the slong
- */
-define_function long math_slong_to_bits(slong x)
-{
- return math_raw_be_to_long(raw_be(x))
+ return x[1] << 24 + x[2] << 16 + x[3] << 8 + x[4]
}

/**
@@ -82,7 +67,7 @@
*/
define_function long math_float_to_bits(float x)
{
- return math_raw_be_to_long(RAW_BE(x))
+ return math_raw_be_to_long(raw_be(x))
}

/**
@@ -156,7 +141,7 @@
stack_var long low
hi = math_double_high_to_bits(x)
low = math_double_low_to_bits(x)
- low = low >> 1 + ((hi & 1) << 15)
+ low = low >> 1 + (hi & 1) << 15
hi = hi >> 1
return math_build_double(hi, low)
}
@@ -174,7 +159,7 @@
stack_var long low
hi = math_double_high_to_bits(x)
low = math_double_low_to_bits(x)
- hi = ((hi & $7FFFFFFF) << 1) + ((low & $80000000) >> 15)
+ hi = (hi & $7FFFFFFF) << 1 + (low & $80000000) >> 15
low = (low & $7FFFFFFF) << 1
return math_build_double(hi, low)
}
@@ -185,44 +170,63 @@
* false.
*
* @param x the double to check
- * @return a boolean representing the number's 'wholeness'
+ * @return a boolean, true if x is a mathematical integer
*/
-define_function char math_is_whole_number(double x)
-{
- stack_var char tmp
+define_function char is_int(double x)
+{
+ stack_var char i
stack_var sinteger exp
stack_var long hi
- stack_var long m_hi
- stack_var long m_low
+ stack_var long m
stack_var long mask
+ if (is_NaN(x)) {
+ return false
+ }
+ if (x >= MATH_TWO_52) {
+ return true
+ }
+ if (abs_value(x) < 1.0) {
+ return (abs_value(x) == 0)
+ }
hi = math_double_high_to_bits(x)
- exp = type_cast(((hi & $7FF00000) >> 20) - 1023)
- m_hi = hi & $FFFFF
- select {
- active (exp == -1023 || exp == 1024): {
- m_low = math_double_low_to_bits(x)
- return (m_hi == 0 && m_low == 0)
- }
- active (exp < 0): {
- return false
- }
- active (exp > 52): {
- return true
- }
- active (exp > 20): {
- for (tmp = type_cast(52 - exp); tmp; tmp--) {
- mask = mask + (1 << (tmp - 1))
- }
- return (m_low & mask == 0)
- }
- active (1): {
- m_low = math_double_low_to_bits(x)
- for (tmp = type_cast(20 - exp); tmp; tmp--) {
- mask = mask + (1 << (tmp - 1))
- }
- return (m_hi & mask == 0)
- }
- }
+ exp = type_cast((hi & $7FF00000) >> 20 - 1023)
+ if (exp > 20) {
+ m = math_double_low_to_bits(x)
+ } else {
+ m = hi & $FFFFF
+ }
+ for (i = type_cast(32 + (exp > 20) * 20 - exp); i; i--) {
+ mask = mask + 1 << (i - 1)
+ }
+ return (m & mask == 0)
+}
+
+/**
+ * Checks if a value is NaN.
+ *
+ * @param x a double to check
+ * @return a boolean, true is x is NaN
+ */
+define_function char is_NaN(double x)
+{
+ stack_var long hi
+ hi = math_double_high_to_bits(x)
+ return (hi & $7FF00000) >> 20 == $7FF &&
+ (hi & $FFFFF || math_double_low_to_bits(x))
+}
+
+/**
+ * Checks if a value is either positive infinity or negative infinity.
+ *
+ * @param x a double to check
+ * @return a boolean, true is x is infinite
+ */
+define_function char is_infinite(double x)
+{
+ stack_var long hi
+ hi = math_double_high_to_bits(x)
+ return (hi & $7FF00000) >> 20 == $7FF &&
+ !(hi & $FFFFF || math_double_low_to_bits(x))
}

/**
@@ -231,7 +235,8 @@
*
* @param x a number to compare
* @param y another number to compare to x
- * @return a boolean specifying if x and y are within MATH_PRECISION of
each other
+ * @return a boolean specifying if x and y are within MATH_PRECISION
+ * of each other
*/
define_function char math_near(double x, double y)
{
@@ -243,43 +248,73 @@
* less than the argument and is equal to a mathematical integer.
*
* @param x the double to round
- * @return a signed long containing the rounded number
+ * @return a double containing the rounded number
*/
-define_function slong ceil(double x)
-{
- if (x > 0 && !math_is_whole_number(x)) {
- return type_cast(x + 1.0)
- } else {
- return type_cast(x)
- }
+define_function double ceil(double x)
+{
+ return -floor(-x)
}

/**
* Returns the largest (closest to positive infinity) long value that is
not
* greater than the argument and is equal to a mathematical integer.
*
+ * @todo remove dependancy on type_cast'ing to a slong to allow for
+ * correct operation over all possible inputs
* @param x a double to round
- * @return a signed long containing the rounded number
+ * @return a double containing the rounded number
*/
-define_function slong floor(double x)
-{
- if (x < 0 && !math_is_whole_number(x)) {
- return type_cast(x - 1.0)
- } else {
- return type_cast(x)
- }
+define_function double floor(double x)
+{
+ stack_var double tmp
+ stack_var slong ret
+ tmp = abs_value(x)
+ if (is_int(tmp)) {
+ return x
+ }
+ if (tmp < 1) {
+ if (x >= 0) {
+ return 0.0 * x
+ } else {
+ return -1.0
+ }
+ }
+ if (x < 0) {
+ ret = type_cast(x - 1.0)
+ } else {
+ ret = type_cast(x)
+ }
+ return ret
}

/**
* Rounds a flouting point number to it's closest whole number.
*
* @param x a double to round
- * @return a signed long containing the rounded number
+ * @return a double containing the rounded number
*/
-define_function slong round(double x)
+define_function double round(double x)
{
return floor(x + 0.5)
}
+
+/**
+ * Computes the remainder operation on two arguments as prescribed by the
+ * IEEE 754 standard.
+ *
+ * @param x a dividend
+ * @param y a divisor
+ * @return a double equal to x - (y Q), where Q is the quotient of
+ * x / y rounded to the nearest integer (if y = 0, NaN is
+ * returned
+ */
+define_function double IEEEremainder(double x, double y)
+{
+ if (y == 0) {
+ return MATH_NaN
+ }
+ return x - y * round(x / y)
+}

/**
* Returns a double value with a positive sign, greater than or equal to
0.0
@@ -294,12 +329,12 @@
stack_var long hi
stack_var long low
for (i = 32; i; i--) {
- low = low + (random_number(2) << (i - 1))
+ low = low + random_number(2) << (i - 1)
}
for (i = 20; i; i--) {
- hi = hi + (random_number(2) << (i - 1))
- }
- hi = hi + (1023 << 20)
+ hi = hi + random_number(2) << (i - 1)
+ }
+ hi = hi + 1023 << 20
return math_build_double(hi, low) - 1
}

@@ -307,8 +342,11 @@
* Calculate the square root of the passed number.
*
* This function takes a log base 2 approximation then iterates a
Babylonian
- * refinement until the answer is within the math libraries defined
precision.
+ * refinement until the answer is within the math libraries defined
precision
+ * or exceeds 1000 steps of refinement.
*
+ * @todo re-write to allow for accurate (and faster) operation on
+ * small (< 1.0e-5) input values
* @param x the double to find the square root of
* @return a double containing the square root
*/
@@ -316,23 +354,24 @@
{
stack_var long hi
stack_var long low
+ stack_var double i
stack_var double tmp
if (x < 0) {
return MATH_NaN
}
- if (x = 0 ||
+ if (x == 0 ||
x == 1 ||
- //x == MATH_NaN ||
- x == MATH_NEGATIVE_INFINITY ||
- x == MATH_POSITIVE_INFINITY) {
+ is_NaN(x) ||
+ is_infinite(x)) {
return x
}
tmp = math_rshift_double(x)
- hi = (1 << 29) + math_double_high_to_bits(tmp) - (1 << 19)
+ hi = 1 << 29 + math_double_high_to_bits(tmp) - 1 << 19
low = math_double_low_to_bits(tmp)
tmp = math_build_double(hi, low)
- while (!math_near(tmp * tmp, x)) {
- tmp = 0.5 * (tmp + (x / tmp))
+ while (!math_near(tmp * tmp, x) && i < 1000) {
+ tmp = 0.5 * (tmp + x / tmp)
+ i++
}
return tmp
}
@@ -343,16 +382,29 @@
* This method uses a integer shift and single Newton refinement aka Quake
3
* method. Original algorithm by Greg Walsh.
*
- * @param x the float to find the inverse square root of
- * @return a float containing an approximation of the inverse square root
+ * @param x the double to find the inverse square root of
+ * @return a double containing an approximation of the inverse square
root
*/
-define_function float fast_inv_sqrt(float x)
-{
- stack_var long bits
- stack_var float tmp
- bits = $5F3759DF - (math_float_to_bits(x) >> 1)
- tmp = math_build_float(bits)
- return tmp * (1.5 - 0.5 * x * tmp * tmp)
+define_function double fast_inv_sqrt(double x)
+{
+ stack_var long hi
+ stack_var long low
+ stack_var long t_hi
+ stack_var long t_low
+ stack_var double res
+ stack_var double tmp
+ tmp = math_rshift_double(x)
+ t_hi = math_double_high_to_bits(tmp)
+ t_low = math_double_low_to_bits(tmp)
+ hi = $5FE6EC85 - t_hi
+ if (t_low > $E7DE30DA) {
+ hi = hi - (t_low - $E7DE30DA)
+ low = 0
+ } else {
+ low = $E7DE30DA - t_low
+ }
+ res = math_build_double(hi, low)
+ return res * (1.5 - 0.5 * x * res * res)
}

/**
@@ -361,10 +413,10 @@
* recommended over sqrt() for use anywhere a precise square root is not
* required. Error is approx +/-0.17%.
*
- * @param x the float to find the square root of
- * @return a float containing an approximation of the square root
+ * @param x the double to find the square root of
+ * @return a double containing an approximation of the square root
*/
-define_function float fast_sqrt(float x)
+define_function double fast_sqrt(double x)
{
return x * fast_inv_sqrt(x)
}
@@ -396,7 +448,7 @@
}
partial = 0.5
tmp = tmp * tmp
- while (partial > MATH_PRECISION) {
+ while (!math_near(partial, 0)) {
if (tmp >= base) {
decimal = decimal + partial
tmp = tmp / base
@@ -469,8 +521,9 @@

DEFINE_START

-MATH_NaN = math_build_double($FFFFFFFF, $FFFFFFFF)
+MATH_NaN = math_build_double($7FFFFFFF, $FFFFFFFF)
MATH_POSITIVE_INFINITY = math_build_double($7FF00000, $00000000)
MATH_NEGATIVE_INFINITY = math_build_double($FFF00000, $00000000)
+MATH_TWO_52 = 1 << 52

#end_if
=======================================
--- /trunk/string.axi Wed May 19 09:21:37 2010
+++ /trunk/string.axi Thu May 27 23:58:59 2010
@@ -150,7 +150,7 @@
if (end) {
ret[i] = mid_string(a, start + 1, (end - start) - 1)
i++
-
+
start = end + 1
continue
}
@@ -297,7 +297,7 @@
tmp == 'yes' ||
tmp == 'y' ||
tmp == '1') {
-
+
return TRUE
} else {
return FALSE
@@ -329,7 +329,7 @@
list = "list, delim, itoa(ints[item])"
}
}
-
+
if (length_string(list) > STRING_RETURN_SIZE_LIMIT) {
return string_size_error()
}
@@ -364,11 +364,11 @@
}

ret = end - start
-
+
if (ret > STRING_RETURN_SIZE_LIMIT) {
return string_size_error()
}
-
+
return mid_string(a, start, ret)
}

@@ -397,7 +397,7 @@
if (retlen > STRING_RETURN_SIZE_LIMIT) {
return string_size_error()
}
-
+
return left_string(a, retlen)
}

@@ -421,7 +421,7 @@
if (retlen > STRING_RETURN_SIZE_LIMIT) {
return string_size_error()
}
-
+
return right_string(a, retlen)
}

@@ -469,7 +469,7 @@
if (retlen > STRING_RETURN_SIZE_LIMIT) {
return string_size_error()
}
-
+
return mid_string(a, start, retlen)
}

@@ -544,7 +544,7 @@

if (len > STRING_RETURN_SIZE_LIMIT ||
length_string(a) > STRING_RETURN_SIZE_LIMIT) {
-
+
return string_size_error()
}

@@ -576,10 +576,10 @@

if (len > STRING_RETURN_SIZE_LIMIT ||
length_string(a) > STRING_RETURN_SIZE_LIMIT) {
-
+
return string_size_error()
}
-
+
if (length_string(a) < len) {
for (i = length_string(a); i < len; i++) {
ret = "value, ret"
@@ -595,7 +595,7 @@
if (length_string(a) - len > STRING_RETURN_SIZE_LIMIT) {
return string_size_error()
}
-
+
return remove_string(a, left_string(a, len), 1)
}

=======================================
--- /trunk/test/test_math.axi Mon May 24 23:08:29 2010
+++ /trunk/test/test_math.axi Thu May 27 23:58:59 2010
@@ -40,44 +40,531 @@


/**
- * Test functionality and execution speed of the math_is_whole_number()
+ * Calculates the percentage error.
+ *
+ * @return the percentage error (0.0 <= x <= 100.0)
+ */
+define_function double test_math_error(double estimate, double actual)
+{
+ if (is_NaN(estimate) ||
+ is_NaN(actual) ||
+ is_infinite(estimate) ||
+ is_infinite(actual)) {
+ return 0.0
+ }
+ return abs_value(estimate - actual) / actual * 100.0
+}
+
+/**
+ * Returns an array of length TEST_MATH_ITERATIONS filled with random
double
+ * precision floating point values.
+ *
+ * @return an array of doubles filled with random data
+ */
+define_function double[TEST_MATH_ITERATIONS] test_math_rand_doubles()
+{
+ stack_var double ret[TEST_MATH_ITERATIONS]
+ stack_var long i
+ stack_var char sign
+ stack_var integer exp
+ stack_var long hi
+ stack_var long low
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ sign = random_number(2)
+ exp = random_number(32) + 1008 // Just so we don't get too crazy
+ // with the massive (or miniscule)
+ // values at this point.
+ hi = sign << 31 + exp << 20 + random_number(1 << 20)
+ low = random_number(1 << 31)
+ ret[i] = math_build_double(hi, low)
+ }
+ return ret
+}
+
+/**
+ * Returns an array of length TEST_MATH_ITERATIONS filled with random
single
+ * precision floating point values.
+ *
+ * @return an array of floats filled with random data
+ */
+define_function float[TEST_MATH_ITERATIONS] test_math_rand_floats()
+{
+ stack_var float ret[TEST_MATH_ITERATIONS]
+ stack_var char sign
+ stack_var char exp
+ stack_var long mantissa
+ stack_var long i
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ sign = random_number(2)
+ exp = random_number(1 << 8)
+ mantissa = random_number(1 << 23)
+ ret[i] = math_build_float(sign << 31 + exp << 23 + mantissa)
+ }
+ return ret
+}
+
+/**
+ * Returns an array of length TEST_MATH_ITERATIONS filled with random long
+ * data.
+ *
+ * @return an array of longs filled with random data
+ */
+define_function long[TEST_MATH_ITERATIONS] test_math_rand_longs()
+{
+ stack_var long ret[TEST_MATH_ITERATIONS]
+ stack_var long i
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ ret[i] = random_number(1 << 32)
+ }
+ return ret
+}
+
+/**
+ * Returns an array of length TEST_MATH_ITERATIONS filled with random char
+ * data.
+ *
+ * @return an array of chars filled with random data
+ */
+define_function char[TEST_MATH_ITERATIONS] test_math_rand_chars()
+{
+ stack_var char ret[TEST_MATH_ITERATIONS]
+ stack_var long i
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ ret[i] = random_number(1 << 8)
+ }
+ return ret
+}
+
+/**
+ * Test functionality and execution speed of the math_raw_be_to_long()
* function.
*
* @return a boolean reflecting success
*/
-define_function char test_math_is_whole_number()
+define_function char test_math_raw_be_to_long()
+{
+ stack_var char test_data[4][TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data[1] = test_math_rand_chars()
+ test_data[2] = test_math_rand_chars()
+ test_data[3] = test_math_rand_chars()
+ test_data[4] = test_math_rand_chars()
+
+ test_start('math_raw_be_to_long()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ math_raw_be_to_long("test_data[1][i], test_data[2][i],
+ test_data[3][i], test_data[4][i]")
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the math_float_to_bits()
+ * function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_math_float_to_bits()
+{
+ stack_var float test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_floats()
+
+ test_start('math_float_to_bits()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ math_float_to_bits(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the math_double_high_to_bits()
+ * function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_math_double_high_to_bits()
{
stack_var double test_data[TEST_MATH_ITERATIONS]
stack_var long i
- stack_var double avg
-
- test_start('math_is_whole_number()')
-
- // Build some random test data
+
+ test_data = test_math_rand_doubles()
+
+ test_start('math_double_high_to_bits()')
+
+ // Check execution speed
+ test_timer_start()
for (i = TEST_MATH_ITERATIONS; i; i--) {
- test_data[i] = random() * 100000.0
- }
+ math_double_high_to_bits(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the math_double_low_to_bits()
+ * function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_math_double_low_to_bits()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('math_double_low_to_bits()')

// Check execution speed
test_timer_start()
for (i = TEST_MATH_ITERATIONS; i; i--) {
- math_is_whole_number(test_data[i])
+ math_double_low_to_bits(test_data[i])
}
test_timer_stop(TEST_MATH_ITERATIONS)

+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the math_build_float()
function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_math_build_float()
+{
+ stack_var long test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_longs()
+
+ test_start('math_build_float()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ math_build_float(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the math_build_double()
function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_math_build_double()
+{
+ stack_var long test_data[2][TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data[1] = test_math_rand_longs()
+ test_data[2] = test_math_rand_longs()
+
+ test_start('math_build_double()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ math_build_double(test_data[1][i], test_data[2][i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the math_rshift_double()
+ * function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_math_rshift_double()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('math_rshift_double()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ math_rshift_double(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the math_lshift_double()
+ * function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_math_lshift_double()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('math_lshift_double()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ math_lshift_double(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the is_int()
+ * function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_is_int()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('is_int()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ is_int(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)

// Check special cases
- test_check(math_is_whole_number(-1) == true, 'breaks on negative input')
- test_check(math_is_whole_number(-1.5) == false, 'breaks on negative
input')
- test_check(math_is_whole_number(0) == true, 'breaks with 0 input')
- test_check(math_is_whole_number(MATH_NaN) == false, 'breaks with NaN')
- test_check(math_is_whole_number(MATH_NEGATIVE_INFINITY) == true,
+ test_check(is_int(-1.0) == true, 'breaks with -1.0 input')
+ test_check(is_int(-1.5) == false, 'breaks iwth -1.5 input')
+ test_check(is_int(0.0) == true, 'breaks with 0 input')
+ test_check(is_int(0.5) == false, 'breaks with 0.5 input')
+ test_check(is_int(MATH_NaN) == false, 'breaks with NaN')
+ test_check(is_int(MATH_NEGATIVE_INFINITY) == true, 'breaks with -inf')
+ test_check(is_int(MATH_POSITIVE_INFINITY) == true, 'breaks with +inf')
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the is_NaN() function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_is_NaN()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('is_NaN()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ is_NaN(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+
+ // Check special cases
+ test_check(is_NaN(MATH_NaN) == true, 'breaks with NaN')
+ test_check(is_NaN(-1) == false, 'breaks on negative input')
+ test_check(is_NaN(-1.5) == false, 'breaks on negative input')
+ test_check(is_NaN(0) == false, 'breaks with 0 input')
+ test_check(is_NaN(MATH_NEGATIVE_INFINITY) == false,
'breaks with -inf')
- test_check(math_is_whole_number(MATH_POSITIVE_INFINITY) == true,
+ test_check(is_NaN(MATH_POSITIVE_INFINITY) == false,
'breaks with +inf')

return test_end()
}
+
+/**
+ * Test functionality and execution speed of the is_infinite() function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_is_infinite()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('is_infinite()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ is_infinite(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+
+ // Check special cases
+ test_check(is_infinite(MATH_NEGATIVE_INFINITY) == true, 'breaks with
-inf')
+ test_check(is_infinite(MATH_POSITIVE_INFINITY) == true, 'breaks with
+inf')
+ test_check(is_infinite(MATH_NaN) == false, 'breaks with NaN')
+ test_check(is_infinite(-1) == false, 'breaks on negative input')
+ test_check(is_infinite(-1.5) == false, 'breaks on negative input')
+ test_check(is_infinite(0) == false, 'breaks with 0 input')
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the math_near() function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_math_near()
+{
+ stack_var double test_data[2][TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data[1] = test_math_rand_doubles()
+ test_data[2] = test_math_rand_doubles()
+
+ test_start('math_near()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ math_near(test_data[1][i], test_data[2][i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ // Check some random cases
+ test_check(math_near(0, MATH_PRECISION) == true, 'breaks at bound')
+ test_check(math_near(MATH_PRECISION, 0) == true, 'breaks at bound')
+ test_check(math_near(0, MATH_PRECISION * 2) == true, 'does not function')
+ test_check(math_near(MATH_PRECISION * 2, 0) == true, 'does not function')
+ test_check(math_near(0, 0) == true, 'does not function')
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the ceil() function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_ceil()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('ceil()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ ceil(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ // Check some random cases
+ test_check(ceil(0.0) == 0.0, 'breaks with 0')
+ test_check(ceil(0.1) == 1.0, 'breaks with 0.1')
+ test_check(ceil(-0.1) == -0.0, 'breaks with -0.1')
+ test_check(ceil(1.0) == 1.0, 'breaks with 1.0')
+ test_check(ceil(1.7) == 2.0, 'breaks with 1.7')
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the floor() function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_floor()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('floor()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ floor(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ // Check some random cases
+ test_check(floor(0.0) == 0.0, 'breaks with 0')
+ test_check(floor(0.1) == 0.0, 'breaks with 0.1')
+ test_check(floor(-0.1) == -1.0, 'breaks with -0.1')
+ test_check(floor(1.0) == 1.0, 'breaks with 1.0')
+ test_check(floor(1.7) == 1.0, 'breaks with 1.7')
+
+ return test_end()
+}
+
+/**
+ * Test functionality and execution speed of the round() function.
+ *
+ * @return a boolean reflecting success
+ */
+define_function char test_round()
+{
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var long i
+
+ test_data = test_math_rand_doubles()
+
+ test_start('round()')
+
+ // Check execution speed
+ test_timer_start()
+ for (i = TEST_MATH_ITERATIONS; i; i--) {
+ round(test_data[i])
+ }
+ test_timer_stop(TEST_MATH_ITERATIONS)
+
+ // Check some random cases
+ test_check(round(0.0) == 0.0, 'breaks with 0')
+ test_check(round(0.1) == 0.0, 'breaks with 0.1')
+ test_check(round(-0.1) == -0.0, 'breaks with -0.1')
+ test_check(round(1.0) == 1.0, 'breaks with 1.0')
+ test_check(round(1.7) == 2.0, 'breaks with 1.7')
+ test_check(round(1.5) == 2.0, 'breaks with 1.5')
+
+ return test_end()
+}

/**
* Test functionality and execution speed of the random() function.
@@ -126,12 +613,12 @@
stack_var double avg_err
stack_var double max_err

- test_start('sqrt()')
-
- // Build some random test data
+ test_data = test_math_rand_doubles()
for (i = TEST_MATH_ITERATIONS; i; i--) {
- test_data[i] = random() * 100000.0
- }
+ test_data[i] = abs_value(test_data[i])
+ }
+
+ test_start('sqrt()')

// Test for execution speed
test_timer_start()
@@ -142,8 +629,10 @@

// Check for correct functionality
for (i = TEST_MATH_ITERATIONS; i; i--) {
- error = test_error(res[i] * res[i], test_data[i])
- test_check(error <= 0.00001, 'exceeds maximum error')
+ error = test_math_error(res[i] * res[i], test_data[i])
+ test_check(error <= 0.0001,
+ "'exceeds maximum error (x = ', ftoa(test_data[i]),
+ ', error = ', ftoa(error), '%)'")
if (error > max_err) {
max_err = error
}
@@ -154,7 +643,7 @@
test_add_stat('avg. error', format('%1.3f', avg_err), '%')

// Check special cases
- test_check(sqrt(-1) == -1, 'breaks with negative input')
+ test_check(sqrt(-1) == MATH_NaN, 'breaks with negative input')
test_check(sqrt(0) == 0, 'breaks with 0 input')
test_check(sqrt(MATH_NaN) == MATH_NaN, 'breaks with NaN')
test_check(sqrt(MATH_NEGATIVE_INFINITY) == MATH_NEGATIVE_INFINITY,
@@ -172,19 +661,19 @@
*/
define_function char test_fast_inv_sqrt()
{
- stack_var float test_data[TEST_MATH_ITERATIONS]
- stack_var float res[TEST_MATH_ITERATIONS]
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var double res[TEST_MATH_ITERATIONS]
stack_var long i
stack_var double error
stack_var double avg_err
stack_var double max_err

- test_start('fast_inv_sqrt()')
-
- // Build some random test data
+ test_data = test_math_rand_doubles()
for (i = TEST_MATH_ITERATIONS; i; i--) {
- test_data[i] = type_cast(random() * 100000.0)
- }
+ test_data[i] = abs_value(test_data[i])
+ }
+
+ test_start('fast_inv_sqrt()')

// Test for execution speed
test_timer_start()
@@ -196,9 +685,11 @@

// Check for correct functionality
for (i = TEST_MATH_ITERATIONS; i; i--) {
- error = test_error(test_data[i] * test_data[i] * res[i] * res[i],
+ error = test_math_error(test_data[i] * test_data[i] * res[i] * res[i],
test_data[i])
- test_check(error <= 0.35, 'exceeds maximum error')
+ test_check(error <= 0.35,
+ "'exceeds maximum error (x = ', ftoa(test_data[i]),
+ ', error = ', ftoa(error), '%)'")
if (error > max_err) {
max_err = error
}
@@ -218,19 +709,19 @@
*/
define_function char test_fast_sqrt()
{
- stack_var float test_data[TEST_MATH_ITERATIONS]
- stack_var float res[TEST_MATH_ITERATIONS]
+ stack_var double test_data[TEST_MATH_ITERATIONS]
+ stack_var double res[TEST_MATH_ITERATIONS]
stack_var long i
stack_var double error
stack_var double avg_err
stack_var double max_err

- test_start('fast_sqrt()')
-
- // Build some random test data
+ test_data = test_math_rand_doubles()
for (i = TEST_MATH_ITERATIONS; i; i--) {
- test_data[i] = type_cast(random() * 100000.0)
- }
+ test_data[i] = abs_value(test_data[i])
+ }
+
+ test_start('fast_sqrt()')

// Test for execution speed
test_timer_start()
@@ -242,8 +733,10 @@

// Check for correct functionality
for (i = TEST_MATH_ITERATIONS; i; i--) {
- error = test_error(res[i] * res[i], test_data[i])
- test_check(error <= 0.35, 'exceeds maximum error')
+ error = test_math_error(res[i] * res[i], test_data[i])
+ test_check(error <= 0.35,
+ "'exceeds maximum error (x = ', ftoa(test_data[i]),
+ ', error = ', ftoa(error), '%)'")
if (error > max_err) {
max_err = error
}
@@ -264,7 +757,21 @@
println("':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::'")
println("'Running math library test suite. This may take a while...'")
println("' '")
- test_math_is_whole_number()
+ test_math_raw_be_to_long()
+ test_math_float_to_bits()
+ test_math_double_high_to_bits()
+ test_math_double_low_to_bits()
+ test_math_build_float()
+ test_math_build_double()
+ test_math_rshift_double()
+ test_math_lshift_double()
+ test_is_int()
+ test_is_NaN()
+ test_is_infinite()
+ test_math_near()
+ test_ceil()
+ test_floor()
+ test_round()
test_random()
test_sqrt()
test_fast_inv_sqrt()
=======================================
--- /trunk/test_utils.axi Mon May 24 23:08:29 2010
+++ /trunk/test_utils.axi Thu May 27 23:58:59 2010
@@ -177,15 +177,5 @@
println("' ', msg")
}
}
-
-/**
- * Calculates the percentage error.
- *
- * @return the percentage error (0.0 <= x <= 100.0)
- */
-define_function double test_error(double estimate, double actual)
-{
- return abs_value(estimate - actual) / actual * 100.0
-}

#end_if

Reply all
Reply to author
Forward
0 new messages