FxLibcTest/src/stdlib/fpconv.c

157 lines
4.1 KiB
C

#include <stdlib.h>
#include <float.h>
#include <errno.h>
#include <math.h>
#include <ft/test.h>
#include <ft/all-tests.h>
/* All these macros have free variables "func" and "format". */
/* Assert that converting (string) gives (result) with (errno == 0). This check
will skip the test if there is a relative error of 1e-12 or less. */
#define assert_conv(string, expected) { \
errno = 0; \
__auto_type _result = func(string, NULL); \
ft_assert(t, errno == 0); \
if(_result == expected) { \
ft_assert(t, 1); \
ft_log(t, string " = " #expected "\n"); \
} \
else if(fabs(1e12 * (_result - expected)) < expected) { \
ft_skip(t, 1); \
ft_log(t, string " = %" format "f [skipped from " #expected \
", difference is %" format "e]\n", \
_result, expected - _result); \
} \
else { \
ft_assert(t, 0); \
ft_log(t, string " = %" format "f [wanted " #expected \
", difference is %" format "e]\n", \
_result, expected - _result); \
} \
}
/* Assert that converting (string) gives (errno == error). */
#define assert_errno(string, error) { \
errno = 0; \
ft_log(t, string " should be errno " #error "\n"); \
func(string, NULL); \
ft_assert(t, errno == error); \
}
/* Assert that converting (string) sets (endptr == string + distance). */
#define assert_end(string, distance) { \
char const *_str = string; \
char *_end; \
ft_log(t, string " should read " #distance "\n"); \
func(_str, &_end); \
ft_assert(t, _end - _str == distance); \
}
static void _ft_stdlib_fpconv(ft_test *t)
{
#define func strtold
#define format "L"
ft_log(t, "--- strtold ---\n");
ft_log(t, "\nSimple test cases:\n");
assert_conv("73", 73.0);
assert_conv("-12", -12.0);
assert_conv("12.125", 12.125);
ft_log(t, "\nOmitting digits:\n");
assert_conv("73.", 73.0);
assert_conv("+0.375", 0.375);
assert_conv(".625", 0.625);
ft_log(t, "\nBasic exponents:\n");
assert_conv("0.3e2", 30.0);
assert_conv("-0.777e+3", -777.0);
assert_conv("6250E-5", 0.0625);
ft_log(t, "\nEnd pointer for valid cases:\n");
assert_end("73b", 2);
assert_end("-73.f", 4);
assert_end("-73.5.2", 5);
assert_end("73.e2f", 5);
assert_end(" 73E+2+1", 7);
assert_end(" -1e5", 6);
assert_end("nan(120)+3", 8);
assert_end("", 0);
ft_log(t, "\nInfinity and NaN:\n");
assert_conv("inf", HUGE_VALL);
assert_conv("-inFiNiTY", -HUGE_VALL);
ft_assert(t, isnan(strtold("+NAN", NULL)));
ft_assert(t, isnan(strtold("-nan", NULL)));
ft_assert(t, isnan(strtold("NaN(57)", NULL)));
ft_log(t, "\nOverflows (with denormalization):\n");
assert_errno("-1e309", ERANGE);
assert_errno("-1e308", 0);
assert_errno("-1e-308", 0);
assert_errno("-1e-324", 0);
/* Implementation is not required to detect underflows */
assert_errno("-1e-325", 0);
assert_errno("0", 0);
assert_errno("1e-325", 0);
assert_errno("1e-324", 0);
assert_errno("1e-308", 0);
assert_errno("1e308", 0);
assert_errno("1e309", ERANGE);
assert_errno("+inf", 0);
assert_errno("-infinity", 0);
ft_log(t, "\nEnd pointer for invalid cases:\n");
assert_end(" b", 0);
assert_end("73e++", 2);
assert_end(" -E5", 0);
assert_end(" +1ex", 3);
ft_log(t, "\nLarge numbers of decimal digits:\n");
assert_conv("18446744073709551616", 1.8446744073709552e+19);
assert_conv("1844674407370955.2e4", 1.8446744073709552e+19);
ft_log(t, "\nHexadecimal notation:\n");
assert_conv("0xa47b.3f85p12", 0xa47b.3f85p12);
#undef func
#undef format
#define func strtod
#define format "l"
ft_log(t, "\n--- strtod ---\n");
ft_log(t, "\nConversion to double:\n");
assert_conv(" -0.73e2", -73.0);
assert_conv("-inf", -HUGE_VAL);
ft_assert(t, atof("+37.5") == 37.5);
assert_errno("1e308", 0);
assert_errno("1e309", ERANGE);
ft_assert(t, isnan(strtod("nan", NULL)));
#undef func
#undef format
#define func strtof
#define format ""
ft_log(t, "\n--- strtof ---\n");
ft_log(t, "\nConversion to float:\n");
assert_conv(" -0.73e2", -73.0f);
assert_conv("+inf", HUGE_VALF);
assert_errno("1e38", 0);
assert_errno("1e39", ERANGE);
ft_assert(t, isnan(strtof("nan", NULL)));
}
ft_test ft_stdlib_fpconv = {
.name = "Floating-point conversion",
.function = _ft_stdlib_fpconv,
};