summaryrefslogtreecommitdiffstats
path: root/vespalib/src/tests/util/brain_float16/brain_float16_test.cpp
blob: 4b7b0ee78974a140c60f8ed14c09230820fc14e4 (plain) (blame)
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
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/util/brain_float16.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <stdio.h>
#include <cmath>

using namespace vespalib;

using Limits = std::numeric_limits<BrainFloat16>;

TEST(BrainFloat16Test, constants_check) {
	EXPECT_EQ(0x1.0p-7, (1.0/128.0));

	float n_min = Limits::min();
	float d_min = Limits::denorm_min();
	float eps = Limits::epsilon();
	float big = Limits::max();
	float low = Limits::lowest();

	EXPECT_EQ(n_min, 0x1.0p-126);
	EXPECT_EQ(d_min, 0x1.0p-133);
	EXPECT_EQ(eps, 0x1.0p-7);
	EXPECT_EQ(big, 0x1.FEp127);
	EXPECT_EQ(low, -big);

	EXPECT_EQ(n_min, std::numeric_limits<float>::min());
	EXPECT_EQ(d_min, n_min / 128.0);
	EXPECT_GT(eps, std::numeric_limits<float>::epsilon());

	BrainFloat16 try_epsilon = 1.0f + eps;
	EXPECT_GT(try_epsilon.to_float(), 1.0f);
	BrainFloat16 try_half_epsilon = 1.0f + (0.5f * eps);
	EXPECT_EQ(try_half_epsilon.to_float(), 1.0f);

	EXPECT_LT(big, std::numeric_limits<float>::max());
	EXPECT_GT(low, std::numeric_limits<float>::lowest());

	printf("bfloat16 epsilon: %.10g (float has %.20g)\n", eps, std::numeric_limits<float>::epsilon());
	printf("bfloat16 norm_min: %.20g (float has %.20g)\n", n_min, std::numeric_limits<float>::min());
	printf("bfloat16 denorm_min: %.20g (float has %.20g)\n", d_min, std::numeric_limits<float>::denorm_min());
	printf("bfloat16 max: %.20g (float has %.20g)\n", big, std::numeric_limits<float>::max());
	printf("bfloat16 lowest: %.20g (float has %.20g)\n", low, std::numeric_limits<float>::lowest());
}

TEST(BrainFloat16Test, traits_check) {
        EXPECT_TRUE(std::is_trivially_constructible<BrainFloat16>::value);
        EXPECT_TRUE(std::is_trivially_move_constructible<BrainFloat16>::value);
        EXPECT_TRUE(std::is_trivially_default_constructible<BrainFloat16>::value);
        EXPECT_TRUE((std::is_trivially_assignable<BrainFloat16,BrainFloat16>::value));
        EXPECT_TRUE(std::is_trivially_move_assignable<BrainFloat16>::value);
        EXPECT_TRUE(std::is_trivially_copy_assignable<BrainFloat16>::value);
        EXPECT_TRUE(std::is_trivially_copyable<BrainFloat16>::value);
        EXPECT_TRUE(std::is_trivially_destructible<BrainFloat16>::value);
        EXPECT_TRUE(std::is_trivial<BrainFloat16>::value);
        EXPECT_TRUE(std::is_swappable<BrainFloat16>::value);
        EXPECT_TRUE(std::has_unique_object_representations<BrainFloat16>::value);
}

TEST(BrainFloat16Test, check_special_values) {
    float f_inf = std::numeric_limits<float>::infinity();
    float f_neg = -f_inf;
    float f_nan = std::numeric_limits<float>::quiet_NaN();
    BrainFloat16 b_inf = f_inf;
    BrainFloat16 b_neg = f_neg;
    BrainFloat16 b_nan = f_nan;
    double d_inf = b_inf;
    double d_neg = b_neg;
    double d_nan = b_nan;
    EXPECT_EQ(d_inf, std::numeric_limits<double>::infinity());
    EXPECT_EQ(d_neg, -std::numeric_limits<double>::infinity());
    EXPECT_TRUE(std::isnan(d_nan));
    float f_from_b_inf = b_inf;
    float f_from_b_neg = b_neg;
    float f_from_b_nan = b_nan;
    EXPECT_EQ(memcmp(&f_inf, &f_from_b_inf, sizeof(float)), 0);
    EXPECT_EQ(memcmp(&f_neg, &f_from_b_neg, sizeof(float)), 0);
    EXPECT_EQ(memcmp(&f_nan, &f_from_b_nan, sizeof(float)), 0);
}

GTEST_MAIN_RUN_ALL_TESTS()