File: float16_t_constants.cpp

package info (click to toggle)
halide 21.0.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 55,752 kB
  • sloc: cpp: 289,334; ansic: 22,751; python: 7,486; makefile: 4,299; sh: 2,508; java: 1,549; javascript: 282; pascal: 207; xml: 127; asm: 9
file content (164 lines) | stat: -rw-r--r-- 7,240 bytes parent folder | download | duplicates (3)
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "Halide.h"
#include <cmath>
#include <stdio.h>

using namespace Halide;

void h_assert(bool condition, const char *msg) {
    if (!condition) {
        printf("FAIL: %s\n", msg);
        abort();
    }
}

int main() {
    // Special constants

    // positive Zero
    {
        printf("Checking positive zero...\n");
        // Try constructing positive zero in different ways and check they all represent
        // the same float16_t
        const float16_t zeroDefaultConstructor;
        const float16_t zeroP = float16_t::make_zero();
        const float16_t zeroPFromFloat(0.0f);
        const float16_t zeroPFromDouble(0.0);
        const float16_t zeroPFromInt(0);
        h_assert(zeroDefaultConstructor.to_bits() == zeroP.to_bits(), "Mismatch between constructors");
        h_assert(zeroPFromFloat.to_bits() == zeroP.to_bits(), "Mistmatch between constructors");
        h_assert(zeroPFromDouble.to_bits() == zeroP.to_bits(), "Mistmatch between constructors");
        h_assert(zeroPFromInt.to_bits() == zeroP.to_bits(), "make_from_signed_int gave wrong value");

        // Check the representation
        h_assert(zeroP.is_zero() && !zeroP.is_negative(), "positive zero invalid");
        h_assert(zeroP.to_bits() == 0x0000, "positive zero invalid bits");

        // Try converting to native float types
        h_assert(((float)zeroP) == 0.0f, "positive zero conversion to float invalid");
        h_assert(((double)zeroP) == 0.0, "positive zero conversion to double invalid");
    }

    // negative Zero
    {
        printf("Checking negative zero...\n");
        // Try constructing negative zero in different ways and check they all represent
        // the same float16_t
        const float16_t zeroN = float16_t::make_negative_zero();
        const float16_t zeroNFromFloat(-0.0f);
        const float16_t zeroNFromDouble(-0.0);
        h_assert(zeroNFromFloat.to_bits() == zeroN.to_bits(), "Mismatch between constructors");
        h_assert(zeroNFromDouble.to_bits() == zeroN.to_bits(), "Mismatch between constructors");

        // Check the representation
        h_assert(zeroN.to_bits() == 0x8000, "negative zero invalid bits");
        h_assert(zeroN.is_zero(), "negative zero is not zero");
        h_assert(zeroN.is_negative(), "negative zero is not negative");

        // Try converting to native float types
        h_assert(((float)zeroN) == -0.0f, "negative zero conversion to float invalid");
        h_assert(((double)zeroN) == -0.0, "negative zero conversion to double invalid");
    }

    // positive infinity
    {
        printf("Checking positive infinity...\n");
        // Try constructing positive infinity in different ways and check they all
        // represent the same float16_t
        const float16_t infinityP = float16_t::make_infinity();
        const float16_t infinityPFromFloat(std::numeric_limits<float>::infinity());
        const float16_t infinityPFromDouble(std::numeric_limits<double>::infinity());
        h_assert(infinityPFromFloat.to_bits() == infinityP.to_bits(), "Mismatch between constructors");
        h_assert(infinityPFromDouble.to_bits() == infinityP.to_bits(), "Mismatch between constructors");

        // Check the representation
        h_assert(infinityP.is_infinity() && !infinityP.is_negative(), "positive infinity invalid");
        h_assert(infinityP.to_bits() == 0x7c00, "positive infinity invalid bits");

        // Try converting to native float types
        float infinityPf = (float)infinityP;
        double infinityPd = (double)infinityP;
        h_assert(std::isinf(infinityPf) && !std::signbit(infinityPf),
                 "positive infinity conversion to float invalid");
        h_assert(std::isinf(infinityPd) && !std::signbit(infinityPd),
                 "positive infinity conversion to double invalid");
    }

    // negative infinity
    {
        printf("Checking negative infinity...\n");
        // Try constructing negative infinity in different ways and check they all
        // represent the same float16_t
        const float16_t infinityN = float16_t::make_negative_infinity();
        const float16_t infinityNFromFloat(-std::numeric_limits<float>::infinity());
        const float16_t infinityNFromDouble(-std::numeric_limits<double>::infinity());
        h_assert(infinityNFromFloat.to_bits() == infinityN.to_bits(), "Mismatch between constructors");
        h_assert(infinityNFromDouble.to_bits() == infinityN.to_bits(), "Mismatch between constructors");

        // Check the representation
        h_assert(infinityN.is_infinity() && infinityN.is_negative(), "negative infinity invalid");
        h_assert(infinityN.to_bits() == 0xfc00, "negative infinity invalid bits");

        // Try converting to native float types
        float infinityNf = (float)infinityN;
        double infinityNd = (double)infinityN;
        h_assert(std::isinf(infinityNf) && std::signbit(infinityNf),
                 "negative infinity conversion to float invalid");
        h_assert(std::isinf(infinityNd) && std::signbit(infinityNd),
                 "negative infinity conversion to double invalid");
    }

    // NaN
    {
        printf("Checking NaN...\n");
        // Try constructing NaN in different ways and check they all
        // represent the same float16_t
        const float16_t nanValue = float16_t::make_nan();
        const float16_t nanValueFromFloat(std::numeric_limits<float>::quiet_NaN());
        const float16_t nanValueFromDouble(std::numeric_limits<double>::quiet_NaN());
        h_assert(nanValueFromFloat.to_bits() == nanValue.to_bits(), "Mismatch between constructors");
        h_assert(nanValueFromDouble.to_bits() == nanValue.to_bits(), "Mismatch between constructors");

        // Check the representation
        h_assert(nanValue.is_nan(), "NaN invalid");
        // Check exponent is all ones
        h_assert((nanValue.to_bits() & 0x7c00) == 0x7c00, "NaN exponent invalid");
        // Check significand is non zero
        h_assert((nanValue.to_bits() & 0x03ff) > 0, "NaN significant invalid");

        // Try converting to native float types
        float nanValuef = (float)nanValue;
        double nanValued = (double)nanValue;
        h_assert(std::isnan(nanValuef), "NaN conversion to float invalid");
        h_assert(std::isnan(nanValued), "NaN conversion to double invalid");
    }

    // Test the rounding of a few constants
    struct test_case {
        double val;
        uint16_t bits;
    };

    test_case tests[] = {
        {1.0 / (1 << 24), 0x001},    // smallest positive
        {-1.0 / (1 << 24), 0x8001},  // smallest negative
        {65504, 0x7bff},             // largest positive
        {-65504, 0xfbff},            // largest negative
        {0.1, 0x2e66},
        {0.3, 0x34cd},
        {4091, 0x6bfe},
        {-4091, 0xebfe},
        {1000000, 0x7c00},   // Out of range maps to +infinity
        {-1000000, 0xfc00},  // Out of range maps to -infinity
    };

    for (auto test : tests) {
        const float16_t v(test.val);
        if (v.to_bits() != test.bits) {
            printf("Rounding error: %f -> %u instead of %u\n", test.val, v.to_bits(), test.bits);
            return 1;
        }
    }

    printf("Success!\n");
    return 0;
}