1#[cfg(feature = "python")]
2use std::convert::Infallible;
3use std::fmt::{Display, LowerExp};
4use std::iter::Sum;
5use std::ops::*;
6
7use bytemuck::{Pod, Zeroable};
8use half;
9use num_derive::*;
10use num_traits::real::Real;
11use num_traits::{AsPrimitive, Bounded, FromBytes, One, Pow, ToBytes, Zero};
12#[cfg(feature = "python")]
13use numpy::Element;
14#[cfg(feature = "python")]
15use pyo3::types::{PyAnyMethods, PyFloat};
16#[cfg(feature = "python")]
17use pyo3::{FromPyObject, IntoPyObject, Python};
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20
21use crate::nulls::IsNull;
22
23#[derive(
28 Debug,
29 Copy,
30 Clone,
31 Default,
32 PartialEq,
33 PartialOrd,
34 Zeroable,
35 Pod,
36 Float,
37 FromPrimitive,
38 Num,
39 NumCast,
40 NumOps,
41 One,
42 ToPrimitive,
43 Zero,
44)]
45#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46#[allow(non_camel_case_types)]
47#[repr(transparent)]
48pub struct pf16(pub half::f16);
49
50#[cfg(feature = "dsl-schema")]
51impl schemars::JsonSchema for pf16 {
52 fn schema_name() -> std::borrow::Cow<'static, str> {
53 "f16".into()
54 }
55
56 fn schema_id() -> std::borrow::Cow<'static, str> {
57 std::borrow::Cow::Borrowed(concat!(module_path!(), "::", "pf16"))
58 }
59
60 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
61 f32::json_schema(generator)
62 }
63}
64
65impl pf16 {
66 pub const NAN: Self = pf16(half::f16::NAN);
67 pub const INFINITY: Self = pf16(half::f16::INFINITY);
68 pub const NEG_INFINITY: Self = pf16(half::f16::NEG_INFINITY);
69
70 #[inline]
71 pub fn to_le_bytes(&self) -> [u8; 2] {
72 self.0.to_le_bytes()
73 }
74
75 #[inline]
76 pub fn is_nan(self) -> bool {
77 self.0.is_nan()
78 }
79
80 #[inline]
81 pub fn is_finite(self) -> bool {
82 self.0.is_finite()
83 }
84
85 #[inline]
86 pub fn abs(self) -> Self {
87 pf16(self.0.abs())
88 }
89
90 #[inline]
91 pub fn trunc(self) -> Self {
92 pf16(self.0.trunc())
93 }
94
95 #[inline]
96 pub fn round(self) -> Self {
97 pf16(self.0.round())
98 }
99
100 #[inline]
101 pub fn floor(self) -> Self {
102 pf16(self.0.floor())
103 }
104
105 #[inline]
106 pub fn ceil(self) -> Self {
107 pf16(self.0.ceil())
108 }
109
110 #[inline]
111 pub fn log(self, base: Self) -> Self {
112 pf16(self.0.log(base.0))
113 }
114
115 #[inline]
116 pub fn to_bits(self) -> u16 {
117 self.0.to_bits()
118 }
119
120 #[inline]
121 pub fn from_bits(b: u16) -> Self {
122 pf16(half::f16::from_bits(b))
123 }
124
125 #[inline]
126 pub fn min(self, other: Self) -> Self {
127 pf16(self.0.min(other.0))
128 }
129
130 #[inline]
131 pub fn max(self, other: Self) -> Self {
132 pf16(self.0.max(other.0))
133 }
134}
135
136impl Display for pf16 {
137 #[inline]
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 Display::fmt(&self.0.to_f32(), f)
140 }
141}
142
143impl Neg for pf16 {
144 type Output = Self;
145
146 #[inline]
147 fn neg(self) -> Self::Output {
148 pf16(-self.0)
149 }
150}
151
152impl AddAssign for pf16 {
153 #[inline]
154 fn add_assign(&mut self, other: Self) {
155 self.0 = self.0 + other.0;
156 }
157}
158
159impl SubAssign for pf16 {
160 #[inline]
161 fn sub_assign(&mut self, other: Self) {
162 self.0 = self.0 - other.0;
163 }
164}
165
166impl MulAssign for pf16 {
167 #[inline]
168 fn mul_assign(&mut self, other: Self) {
169 self.0 = self.0 * other.0;
170 }
171}
172
173impl DivAssign for pf16 {
174 #[inline]
175 fn div_assign(&mut self, other: Self) {
176 self.0 = self.0 / other.0;
177 }
178}
179
180impl RemAssign for pf16 {
181 #[inline]
182 fn rem_assign(&mut self, other: Self) {
183 self.0 = self.0 % other.0;
184 }
185}
186
187impl Sum for pf16 {
188 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
189 let mut acc = Zero::zero();
190 for v in iter {
191 acc += v.0;
192 }
193 pf16(acc)
194 }
195}
196
197impl Pow<pf16> for pf16 {
198 type Output = Self;
199
200 #[inline]
201 fn pow(self, rhs: pf16) -> Self::Output {
202 pf16(self.0.powf(rhs.0))
203 }
204}
205
206impl From<bool> for pf16 {
207 #[inline]
208 fn from(value: bool) -> Self {
209 if value { One::one() } else { Zero::zero() }
210 }
211}
212
213impl From<pf16> for f32 {
214 #[inline]
215 fn from(value: pf16) -> Self {
216 value.0.to_f32()
217 }
218}
219
220impl From<pf16> for f64 {
221 #[inline]
222 fn from(value: pf16) -> Self {
223 value.0.to_f64()
224 }
225}
226
227impl From<f32> for pf16 {
228 #[inline]
229 fn from(value: f32) -> Self {
230 pf16(half::f16::from_f32(value))
231 }
232}
233
234impl From<f64> for pf16 {
235 #[inline]
236 fn from(value: f64) -> Self {
237 pf16(half::f16::from_f64(value))
238 }
239}
240
241impl Bounded for pf16 {
242 fn min_value() -> Self {
243 pf16(half::f16::MIN)
244 }
245
246 fn max_value() -> Self {
247 pf16(half::f16::MAX)
248 }
249}
250
251macro_rules! impl_as_primitive {
252 ($ty:ty) => {
253 impl AsPrimitive<$ty> for pf16 {
254 #[inline]
255 fn as_(self) -> $ty {
256 self.0.as_()
257 }
258 }
259 };
260}
261
262impl_as_primitive!(u8);
263impl_as_primitive!(u16);
264impl_as_primitive!(u32);
265impl_as_primitive!(u64);
266impl_as_primitive!(i8);
267impl_as_primitive!(i16);
268impl_as_primitive!(i32);
269impl_as_primitive!(i64);
270impl_as_primitive!(f32);
271impl_as_primitive!(f64);
272
273impl AsPrimitive<pf16> for pf16 {
274 #[inline]
275 fn as_(self) -> pf16 {
276 self
277 }
278}
279
280impl AsPrimitive<u128> for pf16 {
281 #[inline]
282 fn as_(self) -> u128 {
283 self.0.to_f64() as u128
284 }
285}
286
287impl AsPrimitive<i128> for pf16 {
288 #[inline]
289 fn as_(self) -> i128 {
290 self.0.to_f64() as i128
291 }
292}
293
294macro_rules! impl_as_primitive_pf16_from {
295 ($ty:ty) => {
296 impl AsPrimitive<pf16> for $ty {
297 #[inline]
298 fn as_(self) -> pf16 {
299 pf16(<$ty>::as_(self))
300 }
301 }
302 };
303}
304impl_as_primitive_pf16_from!(usize);
305impl_as_primitive_pf16_from!(u8);
306impl_as_primitive_pf16_from!(u16);
307impl_as_primitive_pf16_from!(u32);
308impl_as_primitive_pf16_from!(u64);
309impl_as_primitive_pf16_from!(isize);
310impl_as_primitive_pf16_from!(i8);
311impl_as_primitive_pf16_from!(i16);
312impl_as_primitive_pf16_from!(i32);
313impl_as_primitive_pf16_from!(i64);
314impl_as_primitive_pf16_from!(f32);
315impl_as_primitive_pf16_from!(f64);
316
317impl AsPrimitive<pf16> for i128 {
318 #[inline]
319 fn as_(self) -> pf16 {
320 pf16(half::f16::from_f64(self as f64))
321 }
322}
323
324impl AsPrimitive<pf16> for u128 {
325 #[inline]
326 fn as_(self) -> pf16 {
327 pf16(half::f16::from_f64(self as f64))
328 }
329}
330
331impl IsNull for pf16 {
332 const HAS_NULLS: bool = false;
333 type Inner = pf16;
334
335 #[inline(always)]
336 fn is_null(&self) -> bool {
337 false
338 }
339 #[inline]
340 fn unwrap_inner(self) -> Self::Inner {
341 self
342 }
343}
344
345impl ToBytes for pf16 {
346 type Bytes = [u8; 2];
347
348 #[inline]
349 fn to_be_bytes(&self) -> Self::Bytes {
350 self.0.to_be_bytes()
351 }
352
353 #[inline]
354 fn to_le_bytes(&self) -> Self::Bytes {
355 self.0.to_le_bytes()
356 }
357
358 #[inline]
359 fn to_ne_bytes(&self) -> Self::Bytes {
360 self.0.to_ne_bytes()
361 }
362}
363
364impl FromBytes for pf16 {
365 type Bytes = [u8; 2];
366
367 #[inline]
368 fn from_be_bytes(bytes: &Self::Bytes) -> Self {
369 pf16(half::f16::from_be_bytes(*bytes))
370 }
371
372 #[inline]
373 fn from_le_bytes(bytes: &Self::Bytes) -> Self {
374 pf16(half::f16::from_le_bytes(*bytes))
375 }
376
377 #[inline]
378 fn from_ne_bytes(bytes: &Self::Bytes) -> Self {
379 pf16(half::f16::from_ne_bytes(*bytes))
380 }
381}
382
383impl LowerExp for pf16 {
384 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
385 LowerExp::fmt(&self.0.to_f32(), f)
386 }
387}
388
389#[cfg(feature = "python")]
390impl<'py> IntoPyObject<'py> for pf16 {
391 type Target = PyFloat;
392 type Output = pyo3::Bound<'py, Self::Target>;
393 type Error = Infallible;
394
395 #[inline]
396 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
397 f32::into_pyobject(self.into(), py)
398 }
399}
400
401#[cfg(feature = "python")]
402impl<'py> FromPyObject<'py> for pf16 {
403 fn extract_bound(ob: &pyo3::Bound<'py, pyo3::PyAny>) -> pyo3::PyResult<Self> {
404 let v: f32 = ob.extract()?;
405 Ok(v.as_())
406 }
407}
408
409#[cfg(feature = "python")]
410unsafe impl Element for pf16 {
411 const IS_COPY: bool = half::f16::IS_COPY;
412
413 fn get_dtype(py: Python<'_>) -> pyo3::Bound<'_, numpy::PyArrayDescr> {
414 half::f16::get_dtype(py)
415 }
416 fn clone_ref(&self, py: Python<'_>) -> Self {
417 pf16(half::f16::clone_ref(&self.0, py))
418 }
419}