OILS / mycpp / float_test.cc View on Github | oilshell.org

131 lines, 69 significant
1// float_test.cc - Printing floats
2
3#include <inttypes.h>
4// #include <limits.h> // HOST_NAME_MAX
5// #include <unistd.h> // gethostname()
6
7//#include <new> // placement new
8
9// #include "mycpp/runtime.h"
10// #include "mycpp/common.h"
11// #include "mycpp/gc_obj.h" // ObjHeader
12#include "vendor/greatest.h"
13
14// https://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format/
15
16union Float_t {
17 Float_t(float num = 0.0f) : f(num) {
18 }
19 // Portable extraction of components.
20 bool Negative() const {
21 return (i >> 31) != 0;
22 }
23 int32_t RawMantissa() const {
24 return i & ((1 << 23) - 1);
25 }
26 int32_t RawExponent() const {
27 return (i >> 23) & 0xFF;
28 }
29
30 int32_t i;
31 float f;
32#if 1
33 struct { // Bitfields for exploration. Do not use in production code.
34 uint32_t mantissa : 23;
35 uint32_t exponent : 8;
36 uint32_t sign : 1;
37 } parts;
38#endif
39};
40
41void PrintFloat(Float_t num) {
42 // printf("Float value, representation, sign, exponent, mantissa\n");
43 printf("%1.8e 0x%08X sign %d, exponent %d, mantissa 0x%06X\n", num.f,
44 num.i, num.parts.sign, num.parts.exponent, num.parts.mantissa);
45}
46
47TEST print_float_test() {
48 Float_t num(1.0f);
49 for (int i = 0; i < 10; ++i) {
50 PrintFloat(num);
51 num.i -= 1;
52 }
53
54 PASS();
55}
56
57typedef float (*Transform)(float);
58
59// https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/
60
61// Pass in a uint32_t range of float representations to test.
62// start and stop are inclusive. Pass in 0, 0xFFFFFFFF to scan all
63// floats. The floats are iterated through by incrementing
64// their integer representation.
65bool ExhaustiveTest(uint32_t start, uint32_t stop, Transform TestFunc,
66 Transform RefFunc, const char* desc) {
67 printf("Testing %s from %u to %u (inclusive).\n", desc, start, stop);
68 // Use long long to let us loop over all positive integers.
69 long long i = start;
70 bool passed = true;
71 while (i <= stop) {
72 Float_t input;
73 input.i = (int32_t)i;
74 Float_t testValue = TestFunc(input.f);
75 Float_t refValue = RefFunc(input.f);
76 // If the results don’t match then report an error.
77 if (testValue.f != refValue.f &&
78 // If both results are NaNs then we treat that as a match.
79 (testValue.f == testValue.f || refValue.f == refValue.f)) {
80 printf("Input %.9g, expected %.9g, got %1.9g \n", input.f,
81 refValue.f, testValue.f);
82 passed = false;
83 }
84
85 ++i;
86 }
87 return passed;
88}
89
90float half(float f) {
91 return f / 2;
92}
93
94float half2(float f) {
95#if 0
96 if (f == 4242.00) {
97 return f + 1; // see if exhasutive test finds this number
98 }
99#endif
100 return f / 2;
101}
102
103TEST round_trip_test() {
104 // This is the biggest number that can be represented in
105 // both float and int32_t. It’s 2^31-128.
106 Float_t maxfloatasint(2147483520.0f);
107
108 // const uint32_t signBit = 0x80000000;
109
110 // Takes 3.5 seconds in opt
111 ASSERT(ExhaustiveTest(0, (uint32_t)maxfloatasint.i, half, half2,
112 "exhaustive half"));
113
114 PASS();
115}
116
117GREATEST_MAIN_DEFS();
118
119int main(int argc, char** argv) {
120 // gHeap.Init();
121
122 GREATEST_MAIN_BEGIN();
123
124 RUN_TEST(print_float_test);
125 RUN_TEST(round_trip_test);
126
127 // gHeap.CleanProcessExit();
128
129 GREATEST_MAIN_END();
130 return 0;
131}