File indexing completed on 2025-08-28 08:27:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #pragma once
0019
0020 #include <array>
0021 #include <cstdint>
0022 #include <cstring>
0023 #include <iosfwd>
0024 #include <limits>
0025 #include <type_traits>
0026
0027 #include "arrow/util/endian.h"
0028 #include "arrow/util/macros.h"
0029 #include "arrow/util/ubsan.h"
0030 #include "arrow/util/visibility.h"
0031
0032 namespace arrow {
0033 namespace util {
0034
0035
0036
0037
0038
0039
0040
0041
0042 class ARROW_EXPORT Float16 {
0043 public:
0044 Float16() = default;
0045 explicit Float16(float f) : Float16(FromFloat(f)) {}
0046 explicit Float16(double d) : Float16(FromDouble(d)) {}
0047 template <typename T,
0048 typename std::enable_if_t<std::is_convertible_v<T, double>>* = NULLPTR>
0049 explicit Float16(T v) : Float16(static_cast<double>(v)) {}
0050
0051
0052 constexpr static Float16 FromBits(uint16_t bits) { return Float16{bits, bool{}}; }
0053
0054 static Float16 FromFloat(float f);
0055
0056 static Float16 FromDouble(double d);
0057
0058
0059 static Float16 FromBytes(const uint8_t* src) {
0060 return FromBits(SafeLoadAs<uint16_t>(src));
0061 }
0062
0063
0064 static Float16 FromLittleEndian(const uint8_t* src) {
0065 return FromBits(::arrow::bit_util::FromLittleEndian(SafeLoadAs<uint16_t>(src)));
0066 }
0067
0068
0069 static Float16 FromBigEndian(const uint8_t* src) {
0070 return FromBits(::arrow::bit_util::FromBigEndian(SafeLoadAs<uint16_t>(src)));
0071 }
0072
0073
0074 constexpr uint16_t bits() const { return bits_; }
0075
0076
0077 constexpr bool signbit() const { return (bits_ & 0x8000) != 0; }
0078
0079
0080 constexpr bool is_nan() const { return (bits_ & 0x7fff) > 0x7c00; }
0081
0082 constexpr bool is_infinity() const { return (bits_ & 0x7fff) == 0x7c00; }
0083
0084 constexpr bool is_finite() const { return (bits_ & 0x7c00) != 0x7c00; }
0085
0086 constexpr bool is_zero() const { return (bits_ & 0x7fff) == 0; }
0087
0088
0089 float ToFloat() const;
0090
0091 double ToDouble() const;
0092
0093 explicit operator float() const { return ToFloat(); }
0094 explicit operator double() const { return ToDouble(); }
0095
0096
0097 void ToBytes(uint8_t* dest) const { std::memcpy(dest, &bits_, sizeof(bits_)); }
0098
0099 constexpr std::array<uint8_t, 2> ToBytes() const {
0100 #if ARROW_LITTLE_ENDIAN
0101 return ToLittleEndian();
0102 #else
0103 return ToBigEndian();
0104 #endif
0105 }
0106
0107
0108 void ToLittleEndian(uint8_t* dest) const {
0109 const auto bytes = ToLittleEndian();
0110 std::memcpy(dest, bytes.data(), bytes.size());
0111 }
0112
0113 constexpr std::array<uint8_t, 2> ToLittleEndian() const {
0114 return {uint8_t(bits_ & 0xff), uint8_t(bits_ >> 8)};
0115 }
0116
0117
0118 void ToBigEndian(uint8_t* dest) const {
0119 const auto bytes = ToBigEndian();
0120 std::memcpy(dest, bytes.data(), bytes.size());
0121 }
0122
0123 constexpr std::array<uint8_t, 2> ToBigEndian() const {
0124 return {uint8_t(bits_ >> 8), uint8_t(bits_ & 0xff)};
0125 }
0126
0127 constexpr Float16 operator-() const { return FromBits(bits_ ^ 0x8000); }
0128 constexpr Float16 operator+() const { return FromBits(bits_); }
0129
0130 friend constexpr bool operator==(Float16 lhs, Float16 rhs) {
0131 if (lhs.is_nan() || rhs.is_nan()) return false;
0132 return Float16::CompareEq(lhs, rhs);
0133 }
0134 friend constexpr bool operator!=(Float16 lhs, Float16 rhs) { return !(lhs == rhs); }
0135
0136 friend constexpr bool operator<(Float16 lhs, Float16 rhs) {
0137 if (lhs.is_nan() || rhs.is_nan()) return false;
0138 return Float16::CompareLt(lhs, rhs);
0139 }
0140 friend constexpr bool operator>(Float16 lhs, Float16 rhs) { return rhs < lhs; }
0141
0142 friend constexpr bool operator<=(Float16 lhs, Float16 rhs) {
0143 if (lhs.is_nan() || rhs.is_nan()) return false;
0144 return !Float16::CompareLt(rhs, lhs);
0145 }
0146 friend constexpr bool operator>=(Float16 lhs, Float16 rhs) { return rhs <= lhs; }
0147
0148 ARROW_FRIEND_EXPORT friend std::ostream& operator<<(std::ostream& os, Float16 arg);
0149
0150 protected:
0151 uint16_t bits_;
0152
0153 private:
0154 constexpr Float16(uint16_t bits, bool) : bits_(bits) {}
0155
0156
0157 static constexpr bool CompareEq(Float16 lhs, Float16 rhs) {
0158 return (lhs.bits() == rhs.bits()) || (lhs.is_zero() && rhs.is_zero());
0159 }
0160 static constexpr bool CompareLt(Float16 lhs, Float16 rhs) {
0161 if (lhs.signbit()) {
0162 if (rhs.signbit()) {
0163
0164 return lhs.bits() > rhs.bits();
0165 } else {
0166
0167 return !lhs.is_zero() || rhs.bits() != 0;
0168 }
0169 } else if (rhs.signbit()) {
0170 return false;
0171 } else {
0172
0173 return lhs.bits() < rhs.bits();
0174 }
0175 }
0176 };
0177
0178 static_assert(std::is_trivial_v<Float16>);
0179
0180 }
0181 }
0182
0183
0184 template <>
0185 class std::numeric_limits<arrow::util::Float16> {
0186 using T = arrow::util::Float16;
0187
0188 public:
0189 static constexpr bool is_specialized = true;
0190 static constexpr bool is_signed = true;
0191 static constexpr bool has_infinity = true;
0192 static constexpr bool has_quiet_NaN = true;
0193
0194 static constexpr T min() { return T::FromBits(0b0000010000000000); }
0195 static constexpr T max() { return T::FromBits(0b0111101111111111); }
0196 static constexpr T lowest() { return -max(); }
0197
0198 static constexpr T infinity() { return T::FromBits(0b0111110000000000); }
0199
0200 static constexpr T quiet_NaN() { return T::FromBits(0b0111111111111111); }
0201 };