#include "../tdkpin_real48.h" #include #include #include #include #include #include static jmp_buf g_runtime_error_jump; static uint16_t g_runtime_error_code; _Noreturn void borland_runtime_error(uint16_t code) { g_runtime_error_code = code; longjmp(g_runtime_error_jump, 1); } static BorlandReal48 real48( uint8_t exponent, uint8_t byte_1, uint8_t byte_2, uint8_t byte_3, uint8_t byte_4, uint8_t byte_5) { return (BorlandReal48){{ exponent, byte_1, byte_2, byte_3, byte_4, byte_5}}; } static void assert_encoding( BorlandReal48 actual, BorlandReal48 expected) { assert(memcmp(actual.bytes, expected.bytes, sizeof(actual.bytes)) == 0); } static void test_integer_encoding(void) { assert_encoding( borland_i32_to_real48_registers(0), real48(0, 0, 0, 0, 0, 0)); assert_encoding( borland_i32_to_real48_registers(1), real48(0x81, 0, 0, 0, 0, 0)); assert_encoding( borland_i32_to_real48_registers(-1), real48(0x81, 0, 0, 0, 0, 0x80)); assert_encoding( borland_i32_to_real48_registers(2), real48(0x82, 0, 0, 0, 0, 0)); assert_encoding( borland_i32_to_real48_registers(INT32_MAX), real48(0x9f, 0x00, 0xfe, 0xff, 0xff, 0x7f)); assert_encoding( borland_i32_to_real48_registers(INT32_MIN), real48(0xa0, 0, 0, 0, 0, 0x80)); assert_encoding( borland_i32_to_real48_registers(123456789), real48(0x9b, 0x00, 0xa0, 0xa2, 0x79, 0x6b)); assert_encoding( borland_i32_to_real48_registers(-123456789), real48(0x9b, 0x00, 0xa0, 0xa2, 0x79, 0xeb)); static const int32_t values[] = { INT32_MIN, -123456789, -65536, -32768, -1, 0, 1, 32767, 65535, 123456789, INT32_MAX, }; for (size_t index = 0; index < sizeof(values) / sizeof(values[0]); index++) { BorlandReal48 encoded = borland_i32_to_real48(values[index]); BorlandReal48IntegerResult decoded = borland_real48_to_i32_registers(encoded, false); assert(!decoded.overflow && decoded.value == values[index]); } } static void test_round_and_truncate(void) { BorlandReal48 positive_half = real48(0x80, 0, 0, 0, 0, 0); BorlandReal48 negative_half = real48(0x80, 0, 0, 0, 0, 0x80); BorlandReal48 below_half = real48(0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f); BorlandReal48 positive_one_and_half = real48(0x81, 0, 0, 0, 0, 0x40); BorlandReal48 below_one_and_half = real48(0x81, 0xff, 0xff, 0xff, 0xff, 0x3f); BorlandReal48 positive_one_and_three_quarters = real48(0x81, 0, 0, 0, 0, 0x60); BorlandReal48 negative_one_and_three_quarters = real48(0x81, 0, 0, 0, 0, 0xe0); BorlandReal48IntegerResult converted = borland_real48_to_i32_registers(positive_half, false); assert(!converted.overflow && converted.value == 0); converted = borland_real48_to_i32_registers(positive_half, true); assert(!converted.overflow && converted.value == 1); converted = borland_real48_to_i32_registers(negative_half, true); assert(!converted.overflow && converted.value == -1); converted = borland_real48_to_i32_registers(below_half, true); assert(!converted.overflow && converted.value == 0); converted = borland_real48_to_i32_registers(positive_one_and_half, true); assert(!converted.overflow && converted.value == 2); converted = borland_real48_to_i32_registers(below_one_and_half, true); assert(!converted.overflow && converted.value == 1); converted = borland_real48_to_i32_registers( positive_one_and_three_quarters, false); assert(!converted.overflow && converted.value == 1); converted = borland_real48_to_i32_registers( negative_one_and_three_quarters, false); assert(!converted.overflow && converted.value == -1); assert(borland_real48_truncate_to_i32( positive_one_and_three_quarters) == 1); assert(borland_real48_truncate_to_i32( negative_one_and_three_quarters) == -1); assert(borland_real48_round_to_i32( positive_one_and_three_quarters) == 2); } static void test_integer_overflow(void) { BorlandReal48 positive_two_to_31 = real48(0xa0, 0, 0, 0, 0, 0); BorlandReal48 negative_two_to_31 = real48(0xa0, 0, 0, 0, 0, 0x80); BorlandReal48 below_negative_two_to_31 = real48(0xa0, 0, 1, 0, 0, 0x80); BorlandReal48 huge = real48(0xff, 0, 0, 0, 0, 0); BorlandReal48IntegerResult converted = borland_real48_to_i32_registers(positive_two_to_31, false); assert(converted.overflow && converted.value == INT32_MIN); converted = borland_real48_to_i32_registers(negative_two_to_31, false); assert(!converted.overflow && converted.value == INT32_MIN); converted = borland_real48_to_i32_registers( below_negative_two_to_31, false); assert(converted.overflow && converted.value == INT32_MAX); converted = borland_real48_to_i32_registers(huge, true); assert(converted.overflow); g_runtime_error_code = 0; if (setjmp(g_runtime_error_jump) == 0) { (void)borland_real48_round_to_i32(positive_two_to_31); assert(false); } assert(g_runtime_error_code == 207); if (setjmp(g_runtime_error_jump) == 0) { (void)borland_real48_truncate_to_i32(positive_two_to_31); assert(false); } assert(g_runtime_error_code == 207); } static void test_comparison(void) { BorlandReal48 zero = real48(0, 0, 0, 0, 0, 0); BorlandReal48 noncanonical_zero = real48(0, 1, 2, 3, 4, 5); BorlandReal48 one = real48(0x81, 0, 0, 0, 0, 0); BorlandReal48 one_and_half = real48(0x81, 0, 0, 0, 0, 0x40); BorlandReal48 two = real48(0x82, 0, 0, 0, 0, 0); BorlandReal48 minus_one = real48(0x81, 0, 0, 0, 0, 0x80); BorlandReal48 minus_two = real48(0x82, 0, 0, 0, 0, 0x80); assert(borland_real48_compare_magnitude_registers( zero, noncanonical_zero) == 0); assert(borland_real48_compare_magnitude_registers(one, one) == 0); assert(borland_real48_compare_magnitude_registers(one, one_and_half) < 0); assert(borland_real48_compare_magnitude_registers(two, one_and_half) > 0); assert(borland_real48_compare(zero, one) < 0); assert(borland_real48_compare(one_and_half, one) > 0); assert(borland_real48_compare(minus_one, one) < 0); assert(borland_real48_compare(minus_two, minus_one) < 0); assert(borland_real48_compare(minus_one, minus_two) > 0); } static void test_arithmetic(void) { BorlandReal48 zero = real48(0, 0, 0, 0, 0, 0); BorlandReal48 half = real48(0x80, 0, 0, 0, 0, 0); BorlandReal48 one = real48(0x81, 0, 0, 0, 0, 0); BorlandReal48 minus_one = real48(0x81, 0, 0, 0, 0, 0x80); BorlandReal48 one_and_half = real48(0x81, 0, 0, 0, 0, 0x40); BorlandReal48 one_and_three_quarters = real48(0x81, 0, 0, 0, 0, 0x60); BorlandReal48 three_quarters = real48(0x80, 0, 0, 0, 0, 0x40); BorlandReal48 minus_half = real48(0x80, 0, 0, 0, 0, 0x80); BorlandReal48 two = real48(0x82, 0, 0, 0, 0, 0); BorlandReal48 two_and_quarter = real48(0x82, 0, 0, 0, 0, 0x10); BorlandReal48 three = real48(0x82, 0, 0, 0, 0, 0x40); BorlandReal48 smallest = real48(1, 0, 0, 0, 0, 0); BorlandReal48 largest = real48(0xff, 0xff, 0xff, 0xff, 0xff, 0x7f); assert_encoding(borland_real48_add(one, one), two); assert_encoding(borland_real48_add(one, minus_one), zero); assert_encoding(borland_real48_add(one_and_half, half), two); assert_encoding(borland_real48_subtract(one_and_half, half), one); assert_encoding( borland_real48_multiply(one_and_half, half), three_quarters); assert_encoding(borland_real48_multiply(one_and_half, two), three); assert_encoding(borland_real48_square(one_and_half), two_and_quarter); assert_encoding(borland_real48_divide(one_and_half, half), three); assert_encoding( borland_real48_add_preserving_right(one_and_half, half).value, two); assert_encoding( borland_real48_subtract_preserving_right(one_and_half, half).value, one); assert_encoding( borland_real48_multiply_preserving_right(one_and_half, half).value, three_quarters); assert_encoding( borland_real48_divide_preserving_right(one_and_half, half).value, three); assert_encoding(borland_real48_multiply(smallest, half), zero); assert_encoding(borland_real48_add(smallest, half), half); assert_encoding(borland_real48_subtract(smallest, half), minus_half); assert_encoding( borland_real48_divide(smallest, half), real48(2, 0, 0, 0, 0, 0)); assert_encoding(borland_real48_integer_part(half), zero); assert_encoding(borland_real48_fractional_part(half), half); assert_encoding(borland_real48_integer_part(one_and_three_quarters), one); assert_encoding( borland_real48_fractional_part(one_and_three_quarters), three_quarters); assert_encoding(borland_real48_sqrt(zero), zero); assert_encoding(borland_real48_sqrt(one), one); assert_encoding(borland_real48_sqrt(two), real48(0x81, 0xfa, 0x33, 0xf3, 0x04, 0x35)); assert_encoding( borland_real48_sqrt(real48(0x83, 0, 0, 0, 0, 0)), two); assert_encoding( borland_real48_sqrt(one_and_half), real48(0x81, 0x49, 0xa0, 0x70, 0xc4, 0x1c)); assert_encoding( borland_real48_arctan_series(zero), zero); assert_encoding( borland_real48_arctan_series( real48(0x7f, 0, 0, 0, 0, 0)), real48(0x7e, 0xb6, 0xb6, 0xaf, 0xdb, 0x7a)); assert_encoding( borland_real48_arctan_series(half), real48(0x7f, 0x0b, 0x0c, 0x35, 0x62, 0x6d)); assert_encoding( borland_real48_arctan_series( real48(0x7f, 0xe7, 0xcf, 0xcc, 0x13, 0x54)), real48(0x7f, 0x49, 0xe2, 0xc2, 0x0f, 0x49)); assert_encoding(borland_real48_arctan(zero), zero); assert_encoding( borland_real48_arctan(real48(0x7e, 0, 0, 0, 0, 0)), real48(0x7d, 0x60, 0xd5, 0xd4, 0xad, 0x7e)); assert_encoding( borland_real48_arctan(half), real48(0x7f, 0x0a, 0x2b, 0x38, 0x63, 0x6d)); assert_encoding( borland_real48_arctan(one), real48(0x80, 0x21, 0xa2, 0xda, 0x0f, 0x49)); assert_encoding( borland_real48_arctan(two), real48(0x81, 0x5f, 0x97, 0x0c, 0xb7, 0x0d)); assert_encoding( borland_real48_arctan(minus_one), real48(0x80, 0x21, 0xa2, 0xda, 0x0f, 0xc9)); assert_encoding( borland_real48_ln(half), real48(0x80, 0xd0, 0xf7, 0x17, 0x72, 0xb1)); assert_encoding(borland_real48_ln(one), zero); assert_encoding( borland_real48_ln(two), real48(0x80, 0xd5, 0xf7, 0x17, 0x72, 0x31)); assert_encoding( borland_real48_ln(one_and_half), real48(0x7f, 0xff, 0x65, 0x1f, 0x99, 0x4f)); assert_encoding( borland_real48_ln(real48(0x84, 0, 0, 0, 0, 0x20)), real48(0x82, 0xac, 0xdd, 0x8d, 0x5d, 0x13)); assert_encoding( borland_real48_exp(real48(0x82, 0, 0, 0, 0, 0x80)), real48(0x7e, 0xfc, 0x1d, 0x55, 0x95, 0x0a)); assert_encoding( borland_real48_exp(minus_one), real48(0x7f, 0x67, 0xb1, 0xb1, 0x5a, 0x3c)); assert_encoding( borland_real48_exp(real48(0x80, 0, 0, 0, 0, 0x80)), real48(0x80, 0x7b, 0xe3, 0x97, 0x45, 0x1b)); assert_encoding(borland_real48_exp(zero), one); assert_encoding( borland_real48_exp(half), real48(0x81, 0xf2, 0x70, 0x4c, 0x09, 0x53)); assert_encoding( borland_real48_exp(one), real48(0x82, 0xa3, 0x58, 0x54, 0xf8, 0x2d)); assert_encoding( borland_real48_exp(two), real48(0x83, 0xa7, 0xc6, 0x25, 0x73, 0x6c)); assert_encoding( borland_real48_exp(real48(0x84, 0, 0, 0, 0, 0x20)), real48(0x8f, 0xa8, 0x7c, 0xee, 0x14, 0x2c)); BorlandReal48 pi_over_6 = real48(0x80, 0x6a, 0xc1, 0x91, 0x0a, 0x06); BorlandReal48 pi_over_2 = real48(0x81, 0x21, 0xa2, 0xda, 0x0f, 0x49); BorlandReal48 pi = real48(0x82, 0x21, 0xa2, 0xda, 0x0f, 0x49); BorlandReal48 two_pi = real48(0x83, 0x21, 0xa2, 0xda, 0x0f, 0x49); assert_encoding(borland_real48_sin(zero), zero); assert_encoding( borland_real48_sin(pi_over_6), real48(0x7f, 0xfe, 0xff, 0xff, 0xff, 0x7f)); assert_encoding( borland_real48_sin(pi_over_2), real48(0x80, 0xfa, 0xff, 0xff, 0xff, 0x7f)); assert_encoding(borland_real48_sin(pi), zero); assert_encoding(borland_real48_sin(two_pi), zero); pi_over_2.bytes[5] |= 0x80; assert_encoding( borland_real48_sin(pi_over_2), real48(0x80, 0xf9, 0xff, 0xff, 0xff, 0xff)); assert_encoding( borland_real48_sin(one), real48(0x80, 0x48, 0x78, 0xa4, 0x6a, 0x57)); assert_encoding( borland_real48_cos(zero), real48(0x80, 0xfa, 0xff, 0xff, 0xff, 0x7f)); assert_encoding( borland_real48_cos(pi_over_6), real48(0x80, 0xc2, 0x42, 0xd7, 0xb3, 0x5d)); pi_over_2.bytes[5] &= 0x7f; assert_encoding(borland_real48_cos(pi_over_2), zero); assert_encoding( borland_real48_cos(pi), real48(0x80, 0xf9, 0xff, 0xff, 0xff, 0xff)); assert_encoding( borland_real48_cos(two_pi), real48(0x80, 0xf9, 0xff, 0xff, 0xff, 0x7f)); pi_over_2.bytes[5] |= 0x80; assert_encoding(borland_real48_cos(pi_over_2), zero); assert_encoding( borland_real48_cos(one), real48(0x80, 0xa8, 0x7d, 0x40, 0x51, 0x0a)); one_and_three_quarters.bytes[5] |= 0x80; assert_encoding( borland_real48_integer_part(one_and_three_quarters), minus_one); three_quarters.bytes[5] |= 0x80; assert_encoding( borland_real48_fractional_part(one_and_three_quarters), three_quarters); BorlandReal48Result overflow = borland_real48_add_registers(largest, largest); assert(overflow.overflow && !overflow.divide_by_zero); overflow = borland_real48_multiply_registers(largest, largest); assert(overflow.overflow && !overflow.divide_by_zero); BorlandReal48Result division = borland_real48_divide_registers(one, zero); assert(division.divide_by_zero && !division.overflow); g_runtime_error_code = 0; if (setjmp(g_runtime_error_jump) == 0) { (void)borland_real48_add(largest, largest); assert(false); } assert(g_runtime_error_code == 205); if (setjmp(g_runtime_error_jump) == 0) { (void)borland_real48_divide(one, zero); assert(false); } assert(g_runtime_error_code == 200); if (setjmp(g_runtime_error_jump) == 0) { (void)borland_real48_sqrt(minus_one); assert(false); } assert(g_runtime_error_code == 207); if (setjmp(g_runtime_error_jump) == 0) { (void)borland_real48_ln(minus_one); assert(false); } assert(g_runtime_error_code == 207); } int main(void) { test_integer_encoding(); test_round_and_truncate(); test_integer_overflow(); test_comparison(); test_arithmetic(); return 0; }