|
| 1 | +/// Checks a numeric_limits specialization of bfloat16. |
| 2 | + |
| 3 | +// RUN: %{build} -o %t.out |
| 4 | +// RUN: %{run} %t.out |
| 5 | + |
| 6 | +#include <sycl/detail/core.hpp> |
| 7 | +#include <sycl/ext/oneapi/bfloat16.hpp> |
| 8 | +#include <sycl/ext/oneapi/experimental/bfloat16_math.hpp> |
| 9 | + |
| 10 | +namespace sycl_ext = sycl::ext::oneapi; |
| 11 | + |
| 12 | +using Limit = std::numeric_limits<sycl_ext::bfloat16>; |
| 13 | + |
| 14 | +// Result of std::log10(2). |
| 15 | +constexpr float Log10_2 = 0.30103f; |
| 16 | + |
| 17 | +// Helper constexpr ceil function. |
| 18 | +constexpr int ceil(float Val) { |
| 19 | + return Val + (float(int(Val)) == Val ? 0.f : 1.f); |
| 20 | +} |
| 21 | + |
| 22 | +int Check(bool Condition, sycl_ext::bfloat16 Value, std::string CheckName) { |
| 23 | + if (!Condition) |
| 24 | + std::cout << "Failed " << CheckName << " for " << Value << std::endl; |
| 25 | + return !Condition; |
| 26 | +} |
| 27 | + |
| 28 | +int CheckBfloat16(uint16_t Sign, uint16_t Exponent, uint16_t Significand) { |
| 29 | + const auto Value = sycl::bit_cast<sycl_ext::bfloat16>( |
| 30 | + uint16_t((Sign << 15) | (Exponent << 7) | Significand)); |
| 31 | + |
| 32 | + int Failed = 0; |
| 33 | + |
| 34 | + Failed += Check(Limit::lowest() <= Value, Value, "lowest()"); |
| 35 | + Failed += Check(Limit::max() >= Value, Value, "max()"); |
| 36 | + |
| 37 | + // min() is the lowest normal number, so if Value is negative, 0 or a |
| 38 | + // subnormal - the latter two being represented by a 0-exponent - min() must |
| 39 | + // be strictly greater. |
| 40 | + if (Sign || Exponent == 0x0) |
| 41 | + Failed += Check(Limit::min() > Value, Value, "min() (1)"); |
| 42 | + else |
| 43 | + Failed += Check(Limit::min() <= Value, Value, "min() (2)"); |
| 44 | + |
| 45 | + // denorm_min() is the lowest subnormal number, so if Value is negative or 0 |
| 46 | + // denorm_min() must be strictly greater. |
| 47 | + if (Sign || (Exponent == 0x0 && Significand == 0x0)) |
| 48 | + Failed += Check(Limit::denorm_min() > Value, Value, "denorm_min() (1)"); |
| 49 | + else |
| 50 | + Failed += Check(Limit::denorm_min() <= Value, Value, "denorm_min() (2)"); |
| 51 | + |
| 52 | + return Failed; |
| 53 | +} |
| 54 | + |
| 55 | +int main() { |
| 56 | + static_assert(Limit::is_specialized); |
| 57 | + static_assert(Limit::is_signed); |
| 58 | + static_assert(!Limit::is_integer); |
| 59 | + static_assert(!Limit::is_exact); |
| 60 | + static_assert(Limit::has_infinity); |
| 61 | + static_assert(Limit::has_quiet_NaN); |
| 62 | + static_assert(Limit::has_signaling_NaN); |
| 63 | + static_assert(Limit::has_denorm == std::float_denorm_style::denorm_present); |
| 64 | + static_assert(!Limit::has_denorm_loss); |
| 65 | + static_assert(!Limit::tinyness_before); |
| 66 | + static_assert(!Limit::traps); |
| 67 | + static_assert(Limit::max_exponent10 == 35); |
| 68 | + static_assert(Limit::max_exponent == 127); |
| 69 | + static_assert(Limit::min_exponent10 == -37); |
| 70 | + static_assert(Limit::min_exponent == -126); |
| 71 | + static_assert(Limit::radix == 2); |
| 72 | + static_assert(Limit::digits == 8); |
| 73 | + static_assert(Limit::max_digits10 == |
| 74 | + ceil(float(Limit::digits) * Log10_2 + 1.0f)); |
| 75 | + static_assert(Limit::is_bounded); |
| 76 | + static_assert(Limit::digits10 == int(Limit::digits * Log10_2)); |
| 77 | + static_assert(!Limit::is_modulo); |
| 78 | + static_assert(Limit::is_iec559); |
| 79 | + static_assert(Limit::round_style == std::float_round_style::round_to_nearest); |
| 80 | + |
| 81 | + int Failed = 0; |
| 82 | + |
| 83 | + Failed += Check(sycl_ext::experimental::isnan(Limit::quiet_NaN()), |
| 84 | + Limit::quiet_NaN(), "quiet_NaN()"); |
| 85 | + Failed += Check(sycl_ext::experimental::isnan(Limit::signaling_NaN()), |
| 86 | + Limit::signaling_NaN(), "signaling_NaN()"); |
| 87 | + // isinf does not exist for bfloat16 currently. |
| 88 | + Failed += Check(Limit::infinity() == |
| 89 | + sycl::bit_cast<sycl_ext::bfloat16>(uint16_t(0xff << 7)), |
| 90 | + Limit::infinity(), "infinity()"); |
| 91 | + Failed += Check(Limit::round_error() == sycl_ext::bfloat16(0.5f), |
| 92 | + Limit::round_error(), "round_error()"); |
| 93 | + Failed += Check(sycl_ext::bfloat16{1.0f} + Limit::epsilon() > |
| 94 | + sycl_ext::bfloat16{1.0f}, |
| 95 | + Limit::epsilon(), "epsilon()"); |
| 96 | + |
| 97 | + for (uint16_t Sign : {0, 1}) |
| 98 | + for (uint16_t Exponent = 0; Exponent < 0xff; ++Exponent) |
| 99 | + for (uint16_t Significand = 0; Significand < 0x7f; ++Significand) |
| 100 | + Failed += CheckBfloat16(Sign, Exponent, Significand); |
| 101 | + |
| 102 | + return Failed; |
| 103 | +} |
0 commit comments