Add more unit tests for fp16.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 12 Mar 2014 00:24:39 +0000 (01:24 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 12 Mar 2014 00:24:39 +0000 (01:24 +0100)
This tests a few edge cases that are not adequately covered by the
random fp32 tests; in particular, the round-to-even logic had
no test coverage, which is bad.

fp16_test.cpp

index d5d7fc0..3deb74b 100644 (file)
@@ -16,9 +16,19 @@ TEST(FP16Test, Simple) {
        EXPECT_DOUBLE_EQ(0.333251953125, fp16_to_fp64(0x3555));
 }
 
-TEST(FP16Test, NaN) {
-       EXPECT_EQ(0xfe00, fp64_to_fp16(0.0 / 0.0));
-       EXPECT_TRUE(isnan(fp16_to_fp64(0xfe00)));
+TEST(FP16Test, RoundToNearestEven) {
+       ASSERT_DOUBLE_EQ(1.0, fp16_to_fp64(0x3c00));
+
+       double x0 = fp16_to_fp64(0x3c00);
+       double x1 = fp16_to_fp64(0x3c01);
+       double x2 = fp16_to_fp64(0x3c02);
+       double x3 = fp16_to_fp64(0x3c03);
+       double x4 = fp16_to_fp64(0x3c04);
+
+       EXPECT_EQ(0x3c00, fp64_to_fp16(0.5 * (x0 + x1)));
+       EXPECT_EQ(0x3c02, fp64_to_fp16(0.5 * (x1 + x2)));
+       EXPECT_EQ(0x3c02, fp64_to_fp16(0.5 * (x2 + x3)));
+       EXPECT_EQ(0x3c04, fp64_to_fp16(0.5 * (x3 + x4)));
 }
 
 union fp64 {
@@ -30,6 +40,44 @@ union fp32 {
        unsigned int u;
 };
 
+TEST(FP16Test, NaN) {
+       EXPECT_EQ(0xfe00, fp64_to_fp16(0.0 / 0.0));
+       EXPECT_TRUE(isnan(fp16_to_fp64(0xfe00)));
+
+       fp64 borderline_inf;
+       borderline_inf.ll = 0x7ff0000000000000ull;
+       fp64 borderline_nan;
+       borderline_nan.ll = 0x7ff0000000000001ull;
+
+       ASSERT_FALSE(isfinite(borderline_inf.f));
+       ASSERT_FALSE(isnan(borderline_inf.f));
+
+       ASSERT_FALSE(isfinite(borderline_nan.f));
+       ASSERT_TRUE(isnan(borderline_nan.f));
+
+       double borderline_inf_roundtrip = fp16_to_fp64(fp64_to_fp16(borderline_inf.f));
+       double borderline_nan_roundtrip = fp16_to_fp64(fp64_to_fp16(borderline_nan.f));
+
+       EXPECT_FALSE(isfinite(borderline_inf_roundtrip));
+       EXPECT_FALSE(isnan(borderline_inf_roundtrip));
+
+       EXPECT_FALSE(isfinite(borderline_nan_roundtrip));
+       EXPECT_TRUE(isnan(borderline_nan_roundtrip));
+}
+
+TEST(FP16Test, Denormals) {
+       const double smallest_fp16_denormal = 5.9604644775390625e-08;
+       EXPECT_EQ(0x0001, fp64_to_fp16(smallest_fp16_denormal));
+       EXPECT_EQ(0x0000, fp64_to_fp16(0.5 * smallest_fp16_denormal));  // Round-to-even.
+       EXPECT_EQ(0x0001, fp64_to_fp16(0.51 * smallest_fp16_denormal));
+       EXPECT_EQ(0x0002, fp64_to_fp16(1.5 * smallest_fp16_denormal));
+
+       const double smallest_fp16_non_denormal = 6.103515625e-05;
+       EXPECT_EQ(0x0400, fp64_to_fp16(smallest_fp16_non_denormal));
+       EXPECT_EQ(0x0400, fp64_to_fp16(smallest_fp16_non_denormal - 0.5 * smallest_fp16_denormal));  // Round-to-even.
+       EXPECT_EQ(0x03ff, fp64_to_fp16(smallest_fp16_non_denormal - smallest_fp16_denormal));
+}
+
 // Randomly test a large number of fp64 -> fp32 conversions, comparing
 // against the FPU.
 TEST(FP16Test, FP32ReferenceDownconvert) {