1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Tests for Emboss floating-point support.
16
17 #include <stdint.h>
18
19 #include <cmath>
20 #include <vector>
21
22 #include "gtest/gtest.h"
23 #include "testdata/float.emb.h"
24
25 namespace emboss {
26 namespace test {
27 namespace {
28
MakeFloats(::std::uint32_t bits)29 ::std::array<char, 8> MakeFloats(::std::uint32_t bits) {
30 return ::std::array<char, 8>({{
31 // Little endian version
32 static_cast<char>(bits & 0xff), //
33 static_cast<char>((bits >> 8) & 0xff), //
34 static_cast<char>((bits >> 16) & 0xff), //
35 static_cast<char>((bits >> 24) & 0xff), //
36
37 // Big endian version
38 static_cast<char>((bits >> 24) & 0xff), //
39 static_cast<char>((bits >> 16) & 0xff), //
40 static_cast<char>((bits >> 8) & 0xff), //
41 static_cast<char>(bits & 0xff), //
42 }});
43 }
44
MakeDoubles(::std::uint64_t bits)45 ::std::array<char, 16> MakeDoubles(::std::uint64_t bits) {
46 return ::std::array<char, 16>({{
47 // Little endian version
48 static_cast<char>(bits & 0xff), //
49 static_cast<char>((bits >> 8) & 0xff), //
50 static_cast<char>((bits >> 16) & 0xff), //
51 static_cast<char>((bits >> 24) & 0xff), //
52 static_cast<char>((bits >> 32) & 0xff), //
53 static_cast<char>((bits >> 40) & 0xff), //
54 static_cast<char>((bits >> 48) & 0xff), //
55 static_cast<char>((bits >> 56) & 0xff), //
56
57 // Big endian version
58 static_cast<char>((bits >> 56) & 0xff), //
59 static_cast<char>((bits >> 48) & 0xff), //
60 static_cast<char>((bits >> 40) & 0xff), //
61 static_cast<char>((bits >> 32) & 0xff), //
62 static_cast<char>((bits >> 24) & 0xff), //
63 static_cast<char>((bits >> 16) & 0xff), //
64 static_cast<char>((bits >> 8) & 0xff), //
65 static_cast<char>(bits & 0xff), //
66 }});
67 }
68
69 // This is used separately for tests where !(a == a).
TestFloatWrite(float value,::std::uint32_t bits)70 void TestFloatWrite(float value, ::std::uint32_t bits) {
71 const auto floats = MakeFloats(bits);
72
73 ::std::array<char, 8> buffer = {};
74 auto writer = MakeFloatsView(&buffer);
75 EXPECT_TRUE(writer.float_little_endian().CouldWriteValue(value));
76 EXPECT_TRUE(writer.float_big_endian().CouldWriteValue(value));
77 writer.float_little_endian().Write(value);
78 writer.float_big_endian().Write(value);
79 EXPECT_EQ(floats, buffer);
80 }
81
TestFloatValue(float value,::std::uint32_t bits)82 ::std::array<char, 8> TestFloatValue(float value, ::std::uint32_t bits) {
83 const auto floats = MakeFloats(bits);
84
85 auto view = MakeFloatsView(&floats);
86 EXPECT_EQ(value, view.float_little_endian().Read());
87 EXPECT_EQ(value, view.float_big_endian().Read());
88
89 TestFloatWrite(value, bits);
90
91 return floats;
92 }
93
94 // This is used separately for tests where !(a == a).
TestDoubleWrite(double value,::std::uint64_t bits)95 void TestDoubleWrite(double value, ::std::uint64_t bits) {
96 const auto doubles = MakeDoubles(bits);
97
98 ::std::array<char, 16> buffer = {};
99 auto writer = MakeDoublesView(&buffer);
100 EXPECT_TRUE(writer.double_little_endian().CouldWriteValue(value));
101 EXPECT_TRUE(writer.double_big_endian().CouldWriteValue(value));
102 writer.double_little_endian().Write(value);
103 writer.double_big_endian().Write(value);
104 EXPECT_EQ(doubles, buffer);
105 }
106
TestDoubleValue(double value,::std::uint64_t bits)107 ::std::array<char, 16> TestDoubleValue(double value, ::std::uint64_t bits) {
108 const auto doubles = MakeDoubles(bits);
109
110 auto view = MakeDoublesView(&doubles);
111 EXPECT_EQ(value, view.double_little_endian().Read());
112 EXPECT_EQ(value, view.double_big_endian().Read());
113
114 TestDoubleWrite(value, bits);
115
116 return doubles;
117 }
118
TEST(Floats,One)119 TEST(Floats, One) { TestFloatValue(+1.0f, 0x3f800000); }
TEST(Floats,Fraction)120 TEST(Floats, Fraction) { TestFloatValue(-0.375f, 0xbec00000); }
TEST(Floats,MinimumDenorm)121 TEST(Floats, MinimumDenorm) {
122 TestFloatValue(::std::exp2(-149.0f), 0x00000001);
123 }
124
TEST(Floats,PlusZero)125 TEST(Floats, PlusZero) {
126 auto floats = TestFloatValue(+0.0f, 0x00000000);
127 auto view = MakeFloatsView(&floats);
128 EXPECT_FALSE(::std::signbit(view.float_little_endian().Read()));
129 EXPECT_FALSE(::std::signbit(view.float_big_endian().Read()));
130 }
131
TEST(Floats,MinusZero)132 TEST(Floats, MinusZero) {
133 auto floats = TestFloatValue(-0.0f, 0x80000000);
134 auto view = MakeFloatsView(&floats);
135 EXPECT_TRUE(::std::signbit(view.float_little_endian().Read()));
136 EXPECT_TRUE(::std::signbit(view.float_big_endian().Read()));
137 }
138
TEST(Floats,PlusInfinity)139 TEST(Floats, PlusInfinity) {
140 auto floats = MakeFloats(0x7f800000);
141 auto view = MakeFloatsView(&floats);
142 EXPECT_TRUE(::std::isinf(view.float_little_endian().Read()));
143 EXPECT_TRUE(::std::isinf(view.float_big_endian().Read()));
144 EXPECT_FALSE(::std::signbit(view.float_little_endian().Read()));
145 EXPECT_FALSE(::std::signbit(view.float_big_endian().Read()));
146 TestFloatWrite(view.float_little_endian().Read(), 0x7f800000);
147 }
148
TEST(Floats,MinusInfinity)149 TEST(Floats, MinusInfinity) {
150 auto floats = MakeFloats(0xff800000);
151 auto view = MakeFloatsView(&floats);
152 EXPECT_TRUE(::std::isinf(view.float_little_endian().Read()));
153 EXPECT_TRUE(::std::isinf(view.float_big_endian().Read()));
154 EXPECT_TRUE(::std::signbit(view.float_little_endian().Read()));
155 EXPECT_TRUE(::std::signbit(view.float_big_endian().Read()));
156 TestFloatWrite(view.float_little_endian().Read(), 0xff800000);
157 }
158
TEST(Floats,Nan)159 TEST(Floats, Nan) {
160 // TODO(bolms): IEEE 754 does not specify the difference between quiet and
161 // signalling NaN, and there are two completely incompatible definitions in
162 // use by modern processors. Ideally, Emboss should provide some way to
163 // specify which convention is in use, but in practice it probably doesn't
164 // matter when dealing with hardware devices.
165 //
166 // Note that the above bit patterns are signalling NaNs on some processors,
167 // and thus any operation on them other than 'std::isnan' should be avoided.
168
169 auto floats = MakeFloats(0x7f800001);
170 auto view = MakeFloatsView(&floats);
171 EXPECT_TRUE(::std::isnan(view.float_little_endian().Read()));
172 EXPECT_TRUE(::std::isnan(view.float_big_endian().Read()));
173 TestFloatWrite(view.float_little_endian().Read(), 0x7f800001);
174 }
175
TEST(FloatView,Equals)176 TEST(FloatView, Equals) {
177 auto buf_x = MakeFloats(64);
178 auto buf_y = MakeFloats(64);
179 EXPECT_EQ(buf_x, buf_y);
180
181 auto x = MakeFloatsView(&buf_x);
182 auto x_const =
183 MakeFloatsView(static_cast</**/ ::std::array<char, 8>*>(&buf_x));
184 auto y = MakeFloatsView(&buf_y);
185
186 EXPECT_TRUE(x.Equals(x));
187 EXPECT_TRUE(x.UncheckedEquals(x));
188 EXPECT_TRUE(y.Equals(y));
189 EXPECT_TRUE(y.UncheckedEquals(y));
190
191 EXPECT_TRUE(x.Equals(y));
192 EXPECT_TRUE(x.UncheckedEquals(y));
193 EXPECT_TRUE(y.Equals(x));
194 EXPECT_TRUE(y.UncheckedEquals(x));
195
196 EXPECT_TRUE(x_const.Equals(y));
197 EXPECT_TRUE(x_const.UncheckedEquals(y));
198 EXPECT_TRUE(y.Equals(x_const));
199 EXPECT_TRUE(y.UncheckedEquals(x_const));
200
201 ++buf_y[1];
202 EXPECT_FALSE(x.Equals(y));
203 EXPECT_FALSE(x.UncheckedEquals(y));
204 EXPECT_FALSE(y.Equals(x));
205 EXPECT_FALSE(y.UncheckedEquals(x));
206 }
207
TEST(FloatView,EqualsNaN)208 TEST(FloatView, EqualsNaN) {
209 auto buf_x = MakeFloats(0x7f800001);
210 auto buf_y = MakeFloats(0x7f800001);
211 EXPECT_EQ(buf_x, buf_y);
212
213 auto x = MakeFloatsView(&buf_x);
214 auto y = MakeFloatsView(&buf_y);
215
216 EXPECT_TRUE(::std::isnan(x.float_little_endian().Read()));
217 EXPECT_TRUE(::std::isnan(x.float_big_endian().Read()));
218 EXPECT_TRUE(::std::isnan(y.float_little_endian().Read()));
219 EXPECT_TRUE(::std::isnan(y.float_big_endian().Read()));
220
221 EXPECT_FALSE(x.Equals(x));
222 EXPECT_FALSE(y.Equals(y));
223 EXPECT_FALSE(x.Equals(y));
224 EXPECT_FALSE(y.Equals(x));
225 }
226
TEST(Doubles,One)227 TEST(Doubles, One) { TestDoubleValue(+1.0, 0x3ff0000000000000UL); }
TEST(Doubles,Fraction)228 TEST(Doubles, Fraction) { TestDoubleValue(-0.375, 0xbfd8000000000000UL); }
TEST(Doubles,MinimumDenorm)229 TEST(Doubles, MinimumDenorm) {
230 TestDoubleValue(::std::exp2(-1074.0), 0x0000000000000001UL);
231 }
232
TEST(Doubles,PlusZero)233 TEST(Doubles, PlusZero) {
234 auto doubles = TestDoubleValue(+0.0, 0x0000000000000000UL);
235 auto view = MakeDoublesView(&doubles);
236 EXPECT_FALSE(::std::signbit(view.double_little_endian().Read()));
237 EXPECT_FALSE(::std::signbit(view.double_big_endian().Read()));
238 }
239
TEST(Doubles,MinusZero)240 TEST(Doubles, MinusZero) {
241 auto doubles = TestDoubleValue(-0.0, 0x8000000000000000UL);
242 auto view = MakeDoublesView(&doubles);
243 EXPECT_TRUE(::std::signbit(view.double_little_endian().Read()));
244 EXPECT_TRUE(::std::signbit(view.double_big_endian().Read()));
245 }
246
TEST(Doubles,PlusInfinity)247 TEST(Doubles, PlusInfinity) {
248 auto doubles = MakeDoubles(0x7ff0000000000000UL);
249 auto view = MakeDoublesView(&doubles);
250 EXPECT_TRUE(::std::isinf(view.double_little_endian().Read()));
251 EXPECT_TRUE(::std::isinf(view.double_big_endian().Read()));
252 EXPECT_FALSE(::std::signbit(view.double_little_endian().Read()));
253 EXPECT_FALSE(::std::signbit(view.double_big_endian().Read()));
254 TestDoubleWrite(view.double_little_endian().Read(), 0x7ff0000000000000UL);
255 }
256
TEST(Doubles,MinusInfinity)257 TEST(Doubles, MinusInfinity) {
258 auto doubles = MakeDoubles(0xfff0000000000000UL);
259 auto view = MakeDoublesView(&doubles);
260 EXPECT_TRUE(::std::isinf(view.double_little_endian().Read()));
261 EXPECT_TRUE(::std::isinf(view.double_big_endian().Read()));
262 EXPECT_TRUE(::std::signbit(view.double_little_endian().Read()));
263 EXPECT_TRUE(::std::signbit(view.double_big_endian().Read()));
264 TestDoubleWrite(view.double_little_endian().Read(), 0xfff0000000000000UL);
265 }
266
TEST(Doubles,Nan)267 TEST(Doubles, Nan) {
268 auto doubles = MakeDoubles(0x7ff0000000000001UL);
269 auto view = MakeDoublesView(&doubles);
270 EXPECT_TRUE(::std::isnan(view.double_little_endian().Read()));
271 EXPECT_TRUE(::std::isnan(view.double_big_endian().Read()));
272 TestDoubleWrite(view.double_little_endian().Read(), 0x7ff0000000000001UL);
273 }
274
TEST(Doubles,CopyFrom)275 TEST(Doubles, CopyFrom) {
276 auto doubles_x = MakeDoubles(0x7ff0000000000001UL);
277 auto doubles_y = MakeDoubles(0x0000000000000000UL);
278
279 auto x = MakeDoublesView(&doubles_x);
280 auto y = MakeDoublesView(&doubles_y);
281
282 EXPECT_NE(x.double_little_endian().Read(), y.double_little_endian().Read());
283 EXPECT_NE(x.double_big_endian().Read(), y.double_big_endian().Read());
284 x.double_little_endian().CopyFrom(y.double_little_endian());
285 x.double_big_endian().CopyFrom(y.double_big_endian());
286 EXPECT_EQ(x.double_little_endian().Read(), y.double_little_endian().Read());
287 EXPECT_EQ(x.double_big_endian().Read(), y.double_big_endian().Read());
288 }
289
TEST(Doubles,TryToCopyFrom)290 TEST(Doubles, TryToCopyFrom) {
291 auto doubles_x = MakeDoubles(0x7ff0000000000001UL);
292 auto doubles_y = MakeDoubles(0x0000000000000000UL);
293
294 auto x = MakeDoublesView(&doubles_x);
295 auto y = MakeDoublesView(&doubles_y);
296
297 EXPECT_NE(x.double_little_endian().Read(), y.double_little_endian().Read());
298 EXPECT_NE(x.double_big_endian().Read(), y.double_big_endian().Read());
299 EXPECT_TRUE(x.double_little_endian().TryToCopyFrom(y.double_little_endian()));
300 EXPECT_TRUE(x.double_big_endian().TryToCopyFrom(y.double_big_endian()));
301 EXPECT_EQ(x.double_little_endian().Read(), y.double_little_endian().Read());
302 EXPECT_EQ(x.double_big_endian().Read(), y.double_big_endian().Read());
303 }
304
TEST(DoubleView,Equals)305 TEST(DoubleView, Equals) {
306 auto buf_x = MakeDoubles(64);
307 auto buf_y = MakeDoubles(64);
308 EXPECT_EQ(buf_x, buf_y);
309
310 auto x = MakeDoublesView(&buf_x);
311 auto y = MakeDoublesView(&buf_y);
312
313 EXPECT_TRUE(x.Equals(x));
314 EXPECT_TRUE(y.Equals(y));
315
316 EXPECT_TRUE(x.Equals(y));
317 EXPECT_TRUE(y.Equals(x));
318
319 ++buf_y[1];
320 EXPECT_FALSE(x.Equals(y));
321 EXPECT_FALSE(y.Equals(x));
322 }
323
TEST(DoubleView,EqualsNaN)324 TEST(DoubleView, EqualsNaN) {
325 auto buf_x = MakeDoubles(0x7ff0000000000001UL);
326 auto buf_y = MakeDoubles(0x7ff0000000000001UL);
327 EXPECT_EQ(buf_x, buf_y);
328
329 auto x = MakeDoublesView(&buf_x);
330 auto y = MakeDoublesView(&buf_y);
331
332 EXPECT_TRUE(::std::isnan(x.double_little_endian().Read()));
333 EXPECT_TRUE(::std::isnan(x.double_big_endian().Read()));
334 EXPECT_TRUE(::std::isnan(y.double_little_endian().Read()));
335 EXPECT_TRUE(::std::isnan(y.double_big_endian().Read()));
336
337 EXPECT_FALSE(x.Equals(x));
338 EXPECT_FALSE(y.Equals(y));
339
340 EXPECT_FALSE(x.Equals(y));
341 EXPECT_FALSE(y.Equals(x));
342 }
343
TEST(DoubleView,WriteTextFormat)344 TEST(DoubleView, WriteTextFormat) {
345 auto buf_x = MakeDoubles(0x4050000000000000UL);
346 auto x = MakeDoublesView(&buf_x);
347 EXPECT_EQ("{ double_little_endian: 64, double_big_endian: 64 }",
348 ::emboss::WriteToString(x));
349 EXPECT_EQ(
350 "{\n"
351 " double_little_endian: 64\n"
352 " double_big_endian: 64\n"
353 "}",
354 ::emboss::WriteToString(x, ::emboss::MultilineText()));
355 }
356
TEST(DoubleView,ReadTextFormat)357 TEST(DoubleView, ReadTextFormat) {
358 auto buf_x = MakeDoubles(0UL);
359 auto x = MakeDoublesView(&buf_x);
360 EXPECT_TRUE(::emboss::UpdateFromText(x,
361 "{\n"
362 " double_little_endian: 64\n"
363 " double_big_endian: 64\n"
364 "}"));
365 EXPECT_EQ(64, x.double_little_endian().Read());
366 EXPECT_EQ(64, x.double_big_endian().Read());
367 }
368
369 } // namespace
370 } // namespace test
371 } // namespace emboss
372