File: fp16_test.cpp

package info (click to toggle)
movit 1.7.2-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 3,248 kB
  • sloc: cpp: 16,677; sh: 3,940; makefile: 167
file content (95 lines) | stat: -rw-r--r-- 2,800 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include "fp16.h"

#include <cmath>
#include <gtest/gtest.h>

namespace movit {
namespace {

fp16_int_t make_fp16(unsigned short x)
{
	fp16_int_t ret;
	ret.val = x;
	return ret;
}

}  // namespace

TEST(FP16Test, Simple) {
	EXPECT_EQ(0x0000, fp32_to_fp16(0.0).val);
	EXPECT_DOUBLE_EQ(0.0, fp16_to_fp32(make_fp16(0x0000)));

	EXPECT_EQ(0x3c00, fp32_to_fp16(1.0).val);
	EXPECT_DOUBLE_EQ(1.0, fp16_to_fp32(make_fp16(0x3c00)));

	EXPECT_EQ(0x3555, fp32_to_fp16(1.0 / 3.0).val);
	EXPECT_DOUBLE_EQ(0.333251953125, fp16_to_fp32(make_fp16(0x3555)));
}

TEST(FP16Test, RoundToNearestEven) {
	ASSERT_DOUBLE_EQ(1.0, fp16_to_fp32(make_fp16(0x3c00)));

	double x0 = fp16_to_fp32(make_fp16(0x3c00));
	double x1 = fp16_to_fp32(make_fp16(0x3c01));
	double x2 = fp16_to_fp32(make_fp16(0x3c02));
	double x3 = fp16_to_fp32(make_fp16(0x3c03));
	double x4 = fp16_to_fp32(make_fp16(0x3c04));

	EXPECT_EQ(0x3c00, fp32_to_fp16(0.5 * (x0 + x1)).val);
	EXPECT_EQ(0x3c02, fp32_to_fp16(0.5 * (x1 + x2)).val);
	EXPECT_EQ(0x3c02, fp32_to_fp16(0.5 * (x2 + x3)).val);
	EXPECT_EQ(0x3c04, fp32_to_fp16(0.5 * (x3 + x4)).val);
}

union fp64 {
	double f;
	unsigned long long ll;
};

#ifdef __F16C__
union fp32 {
	float f;
	unsigned int u;
};
#endif

TEST(FP16Test, NaN) {
	// Ignore the sign bit.
	EXPECT_EQ(0x7e00, fp32_to_fp16(0.0 / 0.0).val & 0x7fff);
	EXPECT_TRUE(std::isnan(fp16_to_fp32(make_fp16(0xfe00))));

	fp32 borderline_inf;
	borderline_inf.u = 0x7f800000ull;
	fp32 borderline_nan;
	borderline_nan.u = 0x7f800001ull;

	ASSERT_FALSE(std::isfinite(borderline_inf.f));
	ASSERT_FALSE(std::isnan(borderline_inf.f));

	ASSERT_FALSE(std::isfinite(borderline_nan.f));
	ASSERT_TRUE(std::isnan(borderline_nan.f));

	double borderline_inf_roundtrip = fp16_to_fp32(fp32_to_fp16(borderline_inf.f));
	double borderline_nan_roundtrip = fp16_to_fp32(fp32_to_fp16(borderline_nan.f));

	EXPECT_FALSE(std::isfinite(borderline_inf_roundtrip));
	EXPECT_FALSE(std::isnan(borderline_inf_roundtrip));

	EXPECT_FALSE(std::isfinite(borderline_nan_roundtrip));
	EXPECT_TRUE(std::isnan(borderline_nan_roundtrip));
}

TEST(FP16Test, Denormals) {
	const double smallest_fp16_denormal = 5.9604644775390625e-08;
	EXPECT_EQ(0x0001, fp32_to_fp16(smallest_fp16_denormal).val);
	EXPECT_EQ(0x0000, fp32_to_fp16(0.5 * smallest_fp16_denormal).val);  // Round-to-even.
	EXPECT_EQ(0x0001, fp32_to_fp16(0.51 * smallest_fp16_denormal).val);
	EXPECT_EQ(0x0002, fp32_to_fp16(1.5 * smallest_fp16_denormal).val);

	const double smallest_fp16_non_denormal = 6.103515625e-05;
	EXPECT_EQ(0x0400, fp32_to_fp16(smallest_fp16_non_denormal).val);
	EXPECT_EQ(0x0400, fp32_to_fp16(smallest_fp16_non_denormal - 0.5 * smallest_fp16_denormal).val);  // Round-to-even.
	EXPECT_EQ(0x03ff, fp32_to_fp16(smallest_fp16_non_denormal - smallest_fp16_denormal).val);
}

}  // namespace movit