1use half::f16;
2
3use crate::{Error, Float, Result, Value, float::Inner};
4
5impl Float {
6 pub const fn to_f16(self) -> Result<f16> {
10 match self.0 {
11 Inner::F16(bits) => Ok(f16::from_bits(bits)),
12 Inner::F32(_) => Err(Error::Precision),
13 Inner::F64(_) => Err(Error::Precision),
14 }
15 }
16}
17
18impl From<f16> for Float {
19 fn from(value: f16) -> Self {
20 Self(Inner::F16(value.to_bits()))
21 }
22}
23
24impl Value {
25 pub fn to_f16(&self) -> Result<f16> {
29 match self {
30 Self::Float(float) => float.to_f16(),
31 Self::Tag(_number, content) => content.untagged().to_f16(),
32 _ => Err(Error::IncompatibleType(self.data_type())),
33 }
34 }
35}
36
37impl From<f16> for Value {
38 fn from(value: f16) -> Self {
39 Self::Float(value.into())
40 }
41}
42
43impl TryFrom<Value> for f16 {
44 type Error = Error;
45 fn try_from(value: Value) -> Result<Self> {
46 value.to_f16()
47 }
48}
49
50#[cfg(test)]
55mod tests {
56 use half::f16;
57
58 use crate::{DataType, Error, Float, Value, float::Inner};
59
60 #[test]
65 fn float_to_f16_from_f16_storage() {
66 let f: Float = f16::from_f32(1.0).into();
67 assert_eq!(f.to_f16(), Ok(f16::from_f32(1.0)));
68 }
69
70 #[test]
71 fn float_to_f16_rejects_f32() {
72 let f: Float = 1e10_f32.into();
74 assert!(matches!(f.0, Inner::F32(_)));
75 assert_eq!(f.to_f16(), Err(Error::Precision));
76 }
77
78 #[test]
79 fn float_to_f16_rejects_f64() {
80 let f: Float = 1e100_f64.into();
82 assert!(matches!(f.0, Inner::F64(_)));
83 assert_eq!(f.to_f16(), Err(Error::Precision));
84 }
85
86 #[test]
87 fn float_to_f16_zero() {
88 let f: Float = f16::ZERO.into();
89 assert_eq!(f.to_f16().unwrap().to_bits(), f16::ZERO.to_bits());
90 assert_eq!(f.to_f32().unwrap().to_bits(), 0.0_f32.to_bits());
91 assert_eq!(f.to_f64().to_bits(), 0.0_f64.to_bits());
92 }
93
94 #[test]
95 fn float_to_f16_neg_zero() {
96 let f: Float = f16::NEG_ZERO.into();
97 assert_eq!(f.to_f16().unwrap().to_bits(), f16::NEG_ZERO.to_bits());
98 assert_eq!(f.to_f32().unwrap().to_bits(), (-0.0_f32).to_bits());
99 assert_eq!(f.to_f64().to_bits(), (-0.0_f64).to_bits());
100 }
101
102 #[test]
103 fn float_to_f16_infinity() {
104 let f: Float = f16::INFINITY.into();
105 assert_eq!(f.to_f16().unwrap(), f16::INFINITY);
106 assert_eq!(f.to_f32().unwrap(), f32::INFINITY);
107 assert_eq!(f.to_f64(), f64::INFINITY);
108 }
109
110 #[test]
111 fn float_to_f16_nan() {
112 let f: Float = f16::NAN.into();
113 assert!(f.to_f16().unwrap().is_nan());
114 assert!(f.to_f32().unwrap().is_nan());
115 assert!(f.to_f64().is_nan());
116 }
117
118 #[test]
123 fn from_f16_stores_as_f16_bits() {
124 let v = f16::from_f32(42.0);
125 let f: Float = v.into();
126 assert!(matches!(f.0, Inner::F16(_)));
127 }
128
129 #[test]
130 fn from_f16_roundtrips() {
131 for bits in 0_u16..=0x7fff {
132 let v = f16::from_bits(bits);
133 if v.is_nan() {
134 continue;
135 }
136 let f: Float = v.into();
137 assert_eq!(
138 f.to_f16().unwrap().to_bits(),
139 bits,
140 "roundtrip failed for bits 0x{bits:04x}"
141 );
142 }
143 }
144
145 #[test]
150 fn value_to_f16_from_float_value() {
151 let val: Value = f16::from_f32(1.5).into();
152 assert_eq!(val.to_f16(), Ok(f16::from_f32(1.5)));
153 }
154
155 #[test]
156 fn value_to_f16_incompatible_type() {
157 let val = Value::Unsigned(42);
158 assert_eq!(val.to_f16(), Err(Error::IncompatibleType(DataType::Int)));
159 }
160
161 #[test]
162 fn value_to_f16_string_is_incompatible() {
163 let val = Value::from("hello");
164 assert_eq!(val.to_f16(), Err(Error::IncompatibleType(DataType::Text)));
165 }
166
167 #[test]
168 fn value_to_f16_f32_precision_error() {
169 let val: Value = 1e10_f32.into();
170 assert_eq!(val.to_f16(), Err(Error::Precision));
171 }
172
173 #[test]
178 fn value_from_f16_is_float_variant() {
179 let val: Value = f16::from_f32(2.0).into();
180 assert!(matches!(val, Value::Float(_)));
181 }
182
183 #[test]
188 fn try_from_value_for_f16_ok() {
189 let val: Value = f16::from_f32(3.41).into();
190 let result = f16::try_from(val).unwrap();
191 assert_eq!(result, f16::from_f32(3.41));
192 }
193
194 #[test]
195 fn try_from_value_for_f16_err() {
196 let val = Value::Unsigned(1);
197 assert_eq!(f16::try_from(val), Err(Error::IncompatibleType(DataType::Int)));
198 }
199}