Revision 16ddff55efc02d37b713eed569d435bdc4f5dfb7 authored by Andrew Adams on 31 August 2023, 22:21:03 UTC, committed by Andrew Adams on 31 August 2023, 22:21:03 UTC
1 parent ef9a7d8
float16_t_constants.cpp
#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;
}
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...