half.h revision 1d77b719d51a01cbd6954a048fb64e79d50a950e
100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar/* 200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * Copyright (C) 2016 The Android Open Source Project 300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * 400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * Licensed under the Apache License, Version 2.0 (the "License"); 500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * you may not use this file except in compliance with the License. 600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * You may obtain a copy of the License at 700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * 800eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * http://www.apache.org/licenses/LICENSE-2.0 900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * 1000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * Unless required by applicable law or agreed to in writing, software 1100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * distributed under the License is distributed on an "AS IS" BASIS, 1200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * See the License for the specific language governing permissions and 1400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * limitations under the License. 1500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar */ 1600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 1700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#pragma once 1800eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 1900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#include <stdint.h> 20d91dc5a0602f54fc0d4d2187f37b5b8169bb62c3Dongwon Kang#include <iosfwd> 2100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#include <limits> 2200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#include <type_traits> 2300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 2400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#ifdef __cplusplus 2500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar# define LIKELY( exp ) (__builtin_expect( !!(exp), true )) 2600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar# define UNLIKELY( exp ) (__builtin_expect( !!(exp), false )) 27defb1b0b7e082621a10763d1bd7a4a01e280fdf0Mathias Agopian#else 28defb1b0b7e082621a10763d1bd7a4a01e280fdf0Mathias Agopian# define LIKELY( exp ) (__builtin_expect( !!(exp), 1 )) 2900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar# define UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 )) 3000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#endif 3100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 3200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#if __cplusplus >= 201402L 3300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#define CONSTEXPR constexpr 3400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#else 3500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#define CONSTEXPR 3600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar#endif 3700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 3800eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnarnamespace android { 3900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 4000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar/* 4100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * half-float 4200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * 4300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * 1 5 10 4400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * +-+------+------------+ 4500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * |s|eee.ee|mm.mmmm.mmmm| 46963f181c57a26dd23bd9dff263614bbb38960888Lajos Molnar * +-+------+------------+ 4700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * 48ba8128f9db82da66f28c6e6740d4721d80da954eDongwon Kang * minimum (denormal) value: 2^-24 = 5.96e-8 49defb1b0b7e082621a10763d1bd7a4a01e280fdf0Mathias Agopian * minimum (normal) value: 2^-14 = 6.10e-5 504f87426e12f5f12e0724519e77f8237a6b2d5dacWonsik Kim * maximum value: 2-2^-10 = 65504 514f87426e12f5f12e0724519e77f8237a6b2d5dacWonsik Kim * 5200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar * Integers between 0 and 2048 can be represented exactly 53defb1b0b7e082621a10763d1bd7a4a01e280fdf0Mathias Agopian */ 54ba8128f9db82da66f28c6e6740d4721d80da954eDongwon Kangclass half { 55defb1b0b7e082621a10763d1bd7a4a01e280fdf0Mathias Agopian struct fp16 { 5600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar uint16_t bits = 0; 5700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar fp16() noexcept = default; 5800eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar explicit constexpr fp16(uint16_t b) noexcept : bits(b) { } 5900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar void setS(unsigned int s) noexcept { bits = uint16_t((bits & 0x7FFF) | (s<<15)); } 6000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar void setE(unsigned int s) noexcept { bits = uint16_t((bits & 0xE3FF) | (s<<10)); } 6100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar void setM(unsigned int s) noexcept { bits = uint16_t((bits & 0xFC00) | (s<< 0)); } 6200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar constexpr unsigned int getS() const noexcept { return bits >> 15u; } 6300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar constexpr unsigned int getE() const noexcept { return (bits >> 10u) & 0x1Fu; } 6400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar constexpr unsigned int getM() const noexcept { return bits & 0x3FFu; } 6500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar }; 6600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar struct fp32 { 6700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar union { 6800eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar uint32_t bits = 0; 6900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar float fp; 7000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar }; 7100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar fp32() noexcept = default; 7200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar explicit constexpr fp32(float f) : fp(f) { } 7300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar void setS(unsigned int s) noexcept { bits = uint32_t((bits & 0x7FFFFFFF) | (s<<31)); } 7400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar void setE(unsigned int s) noexcept { bits = uint32_t((bits & 0x807FFFFF) | (s<<23)); } 7500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar void setM(unsigned int s) noexcept { bits = uint32_t((bits & 0xFF800000) | (s<< 0)); } 7600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar constexpr unsigned int getS() const noexcept { return bits >> 31u; } 77ba8128f9db82da66f28c6e6740d4721d80da954eDongwon Kang constexpr unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; } 784278ba02628d915b52d59dcf5477880cf99f39cdMarco Nelissen constexpr unsigned int getM() const noexcept { return bits & 0x7FFFFFu; } 7900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar }; 8000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 81ba8128f9db82da66f28c6e6740d4721d80da954eDongwon Kangpublic: 8200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar CONSTEXPR half(float v) noexcept : mBits(ftoh(v)) { } 8300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar CONSTEXPR operator float() const noexcept { return htof(mBits); } 844278ba02628d915b52d59dcf5477880cf99f39cdMarco Nelissen 8500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar uint16_t getBits() const noexcept { return mBits.bits; } 8600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar unsigned int getExponent() const noexcept { return mBits.getE(); } 8700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar unsigned int getMantissa() const noexcept { return mBits.getM(); } 8800eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 8900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnarprivate: 9000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar friend class std::numeric_limits<half>; 9100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar friend CONSTEXPR half operator"" _hf(long double v); 9200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 9300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar enum Binary { binary }; 9400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar explicit constexpr half(Binary, uint16_t bits) noexcept : mBits(bits) { } 9500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar static CONSTEXPR fp16 ftoh(float v) noexcept; 9600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar static CONSTEXPR float htof(fp16 v) noexcept; 9700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar fp16 mBits; 9800eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar}; 9900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar 10000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnarinline CONSTEXPR half::fp16 half::ftoh(float v) noexcept { 10100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar fp16 out; 10200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar fp32 in(v); 10300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar if (UNLIKELY(in.getE() == 0xFF)) { // inf or nan 10400eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar out.setE(0x1F); 10500eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar out.setM(in.getM() ? 0x200 : 0); 10600eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar } else { 10700eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar int e = static_cast<int>(in.getE()) - 127 + 15; 10800eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar if (e >= 0x1F) { 10900eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar // overflow 11000eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar out.setE(0x31); // +/- inf 11100eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar } else if (e <= 0) { 11200eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar // underflow 11300eb2fdb2b8f108e74c32e03b2a0e5bab3f107b6Lajos Molnar // flush to +/- 0 114 } else { 115 unsigned int m = in.getM(); 116 out.setE(uint16_t(e)); 117 out.setM(m >> 13); 118 if (m & 0x1000) { 119 // rounding 120 out.bits++; 121 } 122 } 123 } 124 out.setS(in.getS()); 125 return out; 126} 127 128inline CONSTEXPR float half::htof(half::fp16 in) noexcept { 129 fp32 out; 130 if (UNLIKELY(in.getE() == 0x1F)) { // inf or nan 131 out.setE(0xFF); 132 out.setM(in.getM() ? 0x400000 : 0); 133 } else { 134 if (in.getE() == 0) { 135 if (in.getM()) { 136 // TODO: denormal half float, treat as zero for now 137 // (it's stupid because they can be represented as regular float) 138 } 139 } else { 140 int e = static_cast<int>(in.getE()) - 15 + 127; 141 unsigned int m = in.getM(); 142 out.setE(uint32_t(e)); 143 out.setM(m << 13); 144 } 145 } 146 out.setS(in.getS()); 147 return out.fp; 148} 149 150inline CONSTEXPR android::half operator"" _hf(long double v) { 151 return android::half(android::half::binary, android::half::ftoh(static_cast<float>(v)).bits); 152} 153 154} // namespace android 155 156namespace std { 157 158template<> struct is_floating_point<android::half> : public std::true_type {}; 159 160template<> 161class numeric_limits<android::half> { 162public: 163 typedef android::half type; 164 165 static constexpr const bool is_specialized = true; 166 static constexpr const bool is_signed = true; 167 static constexpr const bool is_integer = false; 168 static constexpr const bool is_exact = false; 169 static constexpr const bool has_infinity = true; 170 static constexpr const bool has_quiet_NaN = true; 171 static constexpr const bool has_signaling_NaN = false; 172 static constexpr const float_denorm_style has_denorm = denorm_absent; 173 static constexpr const bool has_denorm_loss = true; 174 static constexpr const bool is_iec559 = false; 175 static constexpr const bool is_bounded = true; 176 static constexpr const bool is_modulo = false; 177 static constexpr const bool traps = false; 178 static constexpr const bool tinyness_before = false; 179 static constexpr const float_round_style round_style = round_indeterminate; 180 181 static constexpr const int digits = 11; 182 static constexpr const int digits10 = 3; 183 static constexpr const int max_digits10 = 5; 184 static constexpr const int radix = 2; 185 static constexpr const int min_exponent = -13; 186 static constexpr const int min_exponent10 = -4; 187 static constexpr const int max_exponent = 16; 188 static constexpr const int max_exponent10 = 4; 189 190 inline static constexpr type round_error() noexcept { return android::half(android::half::binary, 0x3800); } 191 inline static constexpr type min() noexcept { return android::half(android::half::binary, 0x0400); } 192 inline static constexpr type max() noexcept { return android::half(android::half::binary, 0x7bff); } 193 inline static constexpr type lowest() noexcept { return android::half(android::half::binary, 0xfbff); } 194 inline static constexpr type epsilon() noexcept { return android::half(android::half::binary, 0x1400); } 195 inline static constexpr type infinity() noexcept { return android::half(android::half::binary, 0x7c00); } 196 inline static constexpr type quiet_NaN() noexcept { return android::half(android::half::binary, 0x7fff); } 197 inline static constexpr type denorm_min() noexcept { return android::half(android::half::binary, 0x0001); } 198 inline static constexpr type signaling_NaN() noexcept { return android::half(android::half::binary, 0x7dff); } 199}; 200 201} // namespace std 202 203#undef LIKELY 204#undef UNLIKELY 205#undef CONSTEXPR 206