1 | /******************************************************************************* |
2 | * Copyright 2020 Intel Corporation |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | *******************************************************************************/ |
16 | |
17 | #include "dnnl_test_common.hpp" |
18 | #include "gtest/gtest.h" |
19 | |
20 | #include "src/common/bfloat16.hpp" |
21 | |
22 | namespace { |
23 | |
24 | template <typename IntegerType> |
25 | void assert_same_bits_converted_from_integer_as_from_float( |
26 | const IntegerType value) { |
27 | const bfloat16_t constructed_from_float {static_cast<float>(value)}; |
28 | const bfloat16_t constructed_from_integer {value}; |
29 | ASSERT_EQ(constructed_from_integer.raw_bits_, |
30 | constructed_from_float.raw_bits_); |
31 | } |
32 | |
33 | template <typename IntegerType> |
34 | void assert_same_bits_assigned_from_integer_as_from_float( |
35 | const IntegerType value) { |
36 | bfloat16_t assigned_from_float; |
37 | assigned_from_float = static_cast<float>(value); |
38 | bfloat16_t assigned_from_integer; |
39 | assigned_from_integer = value; |
40 | ASSERT_EQ(assigned_from_integer.raw_bits_, assigned_from_float.raw_bits_); |
41 | } |
42 | |
43 | template <typename IntegerType> |
44 | void assert_same_bits_from_integer_as_from_float(const IntegerType value) { |
45 | assert_same_bits_converted_from_integer_as_from_float(value); |
46 | assert_same_bits_assigned_from_integer_as_from_float(value); |
47 | } |
48 | |
49 | template <typename IntegerType> |
50 | void assert_same_bits_from_nonnegative_integer_as_from_float() { |
51 | assert_same_bits_from_integer_as_from_float<IntegerType>(0); |
52 | assert_same_bits_from_integer_as_from_float<IntegerType>(1); |
53 | constexpr auto max_value = std::numeric_limits<IntegerType>::max(); |
54 | assert_same_bits_from_integer_as_from_float(max_value - 1); |
55 | assert_same_bits_from_integer_as_from_float(max_value); |
56 | } |
57 | |
58 | template <typename SignedType> |
59 | void assert_same_bits_from_integer_as_from_float() { |
60 | constexpr auto min_value = std::numeric_limits<SignedType>::min(); |
61 | assert_same_bits_from_integer_as_from_float(min_value); |
62 | assert_same_bits_from_integer_as_from_float(min_value + 1); |
63 | assert_same_bits_from_integer_as_from_float<SignedType>(-1); |
64 | |
65 | assert_same_bits_from_nonnegative_integer_as_from_float<SignedType>(); |
66 | using UnsignedType = typename std::make_unsigned<SignedType>::type; |
67 | assert_same_bits_from_nonnegative_integer_as_from_float<UnsignedType>(); |
68 | } |
69 | |
70 | } // namespace |
71 | |
72 | namespace dnnl { |
73 | |
74 | TEST(test_bfloat16_plus_float, TestDenormF32) { |
75 | const float denorm_f32 {FLT_MIN / 2.0f}; |
76 | const bfloat16_t initial_value_bf16 {FLT_MIN}; |
77 | |
78 | bfloat16_t expect_bf16 {float {initial_value_bf16} + denorm_f32}; |
79 | ASSERT_GT(float {expect_bf16}, float {initial_value_bf16}); |
80 | |
81 | bfloat16_t bf16_plus_equal_f32 = initial_value_bf16; |
82 | bf16_plus_equal_f32 += denorm_f32; |
83 | ASSERT_EQ(float {bf16_plus_equal_f32}, float {expect_bf16}); |
84 | |
85 | bfloat16_t bf16_plus_f32 = initial_value_bf16 + denorm_f32; |
86 | ASSERT_EQ(float {bf16_plus_f32}, float {expect_bf16}); |
87 | } |
88 | |
89 | TEST(test_bfloat16_denorm_f32, BitsFromDoubleSameAsFromFloat) { |
90 | // Test that the bits of a bfloat16 produced by passing 'denorm_f32' as a |
91 | // 'double' are the same as when passing 'denorm_f32' as 'float'. |
92 | // |
93 | // This test aims to check that when converting a 'double' value to |
94 | // 'bfloat16_t', or when assigning a 'double' to a bfloat16, this value is |
95 | // _not_ treated as an integer value! ('bfloat16_t' has optimized member |
96 | // function templates for conversion and assignment, specifically from |
97 | // integer types.) |
98 | constexpr float denorm_f32 {FLT_MIN / 2.0f}; |
99 | const auto expected_bits = bfloat16_t {denorm_f32}.raw_bits_; |
100 | |
101 | // Test converting 'double' to bfloat16: |
102 | EXPECT_EQ(bfloat16_t {double {denorm_f32}}.raw_bits_, expected_bits); |
103 | |
104 | bfloat16_t bf16; |
105 | // Test assignment of 'double' to bfloat16: |
106 | bf16 = double {denorm_f32}; |
107 | |
108 | EXPECT_EQ(bf16.raw_bits_, expected_bits); |
109 | } |
110 | |
111 | TEST(test_bfloat16_converting_constructor_and_assignment, |
112 | BitsFromIntegerSameAsFromFloat) { |
113 | assert_same_bits_from_integer_as_from_float<signed char>(); |
114 | assert_same_bits_from_integer_as_from_float<short>(); |
115 | assert_same_bits_from_integer_as_from_float<int>(); |
116 | assert_same_bits_from_integer_as_from_float<long>(); |
117 | assert_same_bits_from_integer_as_from_float<long long>(); |
118 | } |
119 | |
120 | } // namespace dnnl |
121 | |