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;
}
|