1 //! Contains utility functions and traits to convert between vectors of `u16` bits and `f16` or
2 //! `bf16` vectors.
3 //!
4 //! The utility [`HalfBitsVecExt`] sealed extension trait is implemented for `Vec<u16>` vectors,
5 //! while the utility [`HalfFloatVecExt`] sealed extension trait is implemented for both `Vec<f16>`
6 //! and `Vec<bf16>` vectors. These traits provide efficient conversions and reinterpret casting of
7 //! larger buffers of floating point values, and are automatically included in the [`prelude`]
8 //! module.
9 //!
10 //! This module is only available with the `std` or `alloc` feature.
11 //!
12 //! [`HalfBitsVecExt`]: trait.HalfBitsVecExt.html
13 //! [`HalfFloatVecExt`]: trait.HalfFloatVecExt.html
14 //! [`prelude`]: ../prelude/index.html
15
16 #![cfg(any(feature = "alloc", feature = "std"))]
17
18 use super::{bf16, f16, slice::HalfFloatSliceExt};
19 #[cfg(all(feature = "alloc", not(feature = "std")))]
20 use alloc::vec::Vec;
21 use core::mem;
22
23 /// Extensions to `Vec<f16>` and `Vec<bf16>` to support reinterpret operations.
24 ///
25 /// This trait is sealed and cannot be implemented outside of this crate.
26 pub trait HalfFloatVecExt: private::SealedHalfFloatVec {
27 /// Reinterpret a vector of [`f16`](../struct.f16.html) or [`bf16`](../struct.bf16.html)
28 /// numbers as a vector of `u16` bits.
29 ///
30 /// This is a zero-copy operation. The reinterpreted vector has the same memory location as
31 /// `self`.
32 ///
33 /// # Examples
34 ///
35 /// ```rust
36 /// # use half::prelude::*;
37 /// let float_buffer = vec![f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)];
38 /// let int_buffer = float_buffer.reinterpret_into();
39 ///
40 /// assert_eq!(int_buffer, [f16::from_f32(1.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()]);
41 /// ```
reinterpret_into(self) -> Vec<u16>42 fn reinterpret_into(self) -> Vec<u16>;
43
44 /// Convert all of the elements of a `[f32]` slice into a new [`f16`](../struct.f16.html) or
45 /// [`bf16`](../struct.bf16.html) vector.
46 ///
47 /// The conversion operation is vectorized over the slice, meaning the conversion may be more
48 /// efficient than converting individual elements on some hardware that supports SIMD
49 /// conversions. See [crate documentation](../index.html) for more information on hardware
50 /// conversion support.
51 ///
52 /// # Examples
53 /// ```rust
54 /// # use half::prelude::*;
55 /// let float_values = [1., 2., 3., 4.];
56 /// let vec: Vec<f16> = Vec::from_f32_slice(&float_values);
57 ///
58 /// assert_eq!(vec, vec![f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.), f16::from_f32(4.)]);
59 /// ```
from_f32_slice(slice: &[f32]) -> Self60 fn from_f32_slice(slice: &[f32]) -> Self;
61
62 /// Convert all of the elements of a `[f64]` slice into a new [`f16`](../struct.f16.html) or
63 /// [`bf16`](../struct.bf16.html) vector.
64 ///
65 /// The conversion operation is vectorized over the slice, meaning the conversion may be more
66 /// efficient than converting individual elements on some hardware that supports SIMD
67 /// conversions. See [crate documentation](../index.html) for more information on hardware
68 /// conversion support.
69 ///
70 /// # Examples
71 /// ```rust
72 /// # use half::prelude::*;
73 /// let float_values = [1., 2., 3., 4.];
74 /// let vec: Vec<f16> = Vec::from_f64_slice(&float_values);
75 ///
76 /// assert_eq!(vec, vec![f16::from_f64(1.), f16::from_f64(2.), f16::from_f64(3.), f16::from_f64(4.)]);
77 /// ```
from_f64_slice(slice: &[f64]) -> Self78 fn from_f64_slice(slice: &[f64]) -> Self;
79 }
80
81 /// Extensions to `Vec<u16>` to support reinterpret operations.
82 ///
83 /// This trait is sealed and cannot be implemented outside of this crate.
84 pub trait HalfBitsVecExt: private::SealedHalfBitsVec {
85 /// Reinterpret a vector of `u16` bits as a vector of [`f16`](../struct.f16.html) or
86 /// [`bf16`](../struct.bf16.html) numbers.
87 ///
88 /// `H` is the type to cast to, and must be either the [`f16`](../struct.f16.html) or
89 /// [`bf16`](../struct.bf16.html) type.
90 ///
91 /// This is a zero-copy operation. The reinterpreted vector has the same memory location as
92 /// `self`.
93 ///
94 /// # Examples
95 ///
96 /// ```rust
97 /// # use half::prelude::*;
98 /// let int_buffer = vec![f16::from_f32(1.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()];
99 /// let float_buffer = int_buffer.reinterpret_into::<f16>();
100 ///
101 /// assert_eq!(float_buffer, [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)]);
102 /// ```
reinterpret_into<H>(self) -> Vec<H> where H: crate::private::SealedHalf103 fn reinterpret_into<H>(self) -> Vec<H>
104 where
105 H: crate::private::SealedHalf;
106 }
107
108 mod private {
109 use crate::{bf16, f16};
110 #[cfg(all(feature = "alloc", not(feature = "std")))]
111 use alloc::vec::Vec;
112
113 pub trait SealedHalfFloatVec {}
114 impl SealedHalfFloatVec for Vec<f16> {}
115 impl SealedHalfFloatVec for Vec<bf16> {}
116
117 pub trait SealedHalfBitsVec {}
118 impl SealedHalfBitsVec for Vec<u16> {}
119 }
120
121 impl HalfFloatVecExt for Vec<f16> {
122 #[inline]
reinterpret_into(mut self) -> Vec<u16>123 fn reinterpret_into(mut self) -> Vec<u16> {
124 // An f16 array has same length and capacity as u16 array
125 let length = self.len();
126 let capacity = self.capacity();
127
128 // Actually reinterpret the contents of the Vec<f16> as u16,
129 // knowing that structs are represented as only their members in memory,
130 // which is the u16 part of `f16(u16)`
131 let pointer = self.as_mut_ptr() as *mut u16;
132
133 // Prevent running a destructor on the old Vec<u16>, so the pointer won't be deleted
134 mem::forget(self);
135
136 // Finally construct a new Vec<f16> from the raw pointer
137 // SAFETY: We are reconstructing full length and capacity of original vector,
138 // using its original pointer, and the size of elements are identical.
139 unsafe { Vec::from_raw_parts(pointer, length, capacity) }
140 }
141
from_f32_slice(slice: &[f32]) -> Self142 fn from_f32_slice(slice: &[f32]) -> Self {
143 let mut vec = Vec::with_capacity(slice.len());
144 // SAFETY: convert will initialize every value in the vector without reading them,
145 // so this is safe to do instead of double initialize from resize, and we're setting it to
146 // same value as capacity.
147 unsafe { vec.set_len(slice.len()) };
148 vec.convert_from_f32_slice(&slice);
149 vec
150 }
151
from_f64_slice(slice: &[f64]) -> Self152 fn from_f64_slice(slice: &[f64]) -> Self {
153 let mut vec = Vec::with_capacity(slice.len());
154 // SAFETY: convert will initialize every value in the vector without reading them,
155 // so this is safe to do instead of double initialize from resize, and we're setting it to
156 // same value as capacity.
157 unsafe { vec.set_len(slice.len()) };
158 vec.convert_from_f64_slice(&slice);
159 vec
160 }
161 }
162
163 impl HalfFloatVecExt for Vec<bf16> {
164 #[inline]
reinterpret_into(mut self) -> Vec<u16>165 fn reinterpret_into(mut self) -> Vec<u16> {
166 // An f16 array has same length and capacity as u16 array
167 let length = self.len();
168 let capacity = self.capacity();
169
170 // Actually reinterpret the contents of the Vec<f16> as u16,
171 // knowing that structs are represented as only their members in memory,
172 // which is the u16 part of `f16(u16)`
173 let pointer = self.as_mut_ptr() as *mut u16;
174
175 // Prevent running a destructor on the old Vec<u16>, so the pointer won't be deleted
176 mem::forget(self);
177
178 // Finally construct a new Vec<f16> from the raw pointer
179 // SAFETY: We are reconstructing full length and capacity of original vector,
180 // using its original pointer, and the size of elements are identical.
181 unsafe { Vec::from_raw_parts(pointer, length, capacity) }
182 }
183
from_f32_slice(slice: &[f32]) -> Self184 fn from_f32_slice(slice: &[f32]) -> Self {
185 let mut vec = Vec::with_capacity(slice.len());
186 // SAFETY: convert will initialize every value in the vector without reading them,
187 // so this is safe to do instead of double initialize from resize, and we're setting it to
188 // same value as capacity.
189 unsafe { vec.set_len(slice.len()) };
190 vec.convert_from_f32_slice(&slice);
191 vec
192 }
193
from_f64_slice(slice: &[f64]) -> Self194 fn from_f64_slice(slice: &[f64]) -> Self {
195 let mut vec = Vec::with_capacity(slice.len());
196 // SAFETY: convert will initialize every value in the vector without reading them,
197 // so this is safe to do instead of double initialize from resize, and we're setting it to
198 // same value as capacity.
199 unsafe { vec.set_len(slice.len()) };
200 vec.convert_from_f64_slice(&slice);
201 vec
202 }
203 }
204
205 impl HalfBitsVecExt for Vec<u16> {
206 // This is safe because all traits are sealed
207 #[inline]
reinterpret_into<H>(mut self) -> Vec<H> where H: crate::private::SealedHalf,208 fn reinterpret_into<H>(mut self) -> Vec<H>
209 where
210 H: crate::private::SealedHalf,
211 {
212 // An f16 array has same length and capacity as u16 array
213 let length = self.len();
214 let capacity = self.capacity();
215
216 // Actually reinterpret the contents of the Vec<u16> as f16,
217 // knowing that structs are represented as only their members in memory,
218 // which is the u16 part of `f16(u16)`
219 let pointer = self.as_mut_ptr() as *mut H;
220
221 // Prevent running a destructor on the old Vec<u16>, so the pointer won't be deleted
222 mem::forget(self);
223
224 // Finally construct a new Vec<f16> from the raw pointer
225 // SAFETY: We are reconstructing full length and capacity of original vector,
226 // using its original pointer, and the size of elements are identical.
227 unsafe { Vec::from_raw_parts(pointer, length, capacity) }
228 }
229 }
230
231 /// Converts a vector of `u16` elements into a vector of [`f16`](../struct.f16.html) elements.
232 ///
233 /// This function merely reinterprets the contents of the vector, so it's a zero-copy operation.
234 #[deprecated(
235 since = "1.4.0",
236 note = "use [`HalfBitsVecExt::reinterpret_into`](trait.HalfBitsVecExt.html#tymethod.reinterpret_into) instead"
237 )]
238 #[inline]
from_bits(bits: Vec<u16>) -> Vec<f16>239 pub fn from_bits(bits: Vec<u16>) -> Vec<f16> {
240 bits.reinterpret_into()
241 }
242
243 /// Converts a vector of [`f16`](../struct.f16.html) elements into a vector of `u16` elements.
244 ///
245 /// This function merely reinterprets the contents of the vector, so it's a zero-copy operation.
246 #[deprecated(
247 since = "1.4.0",
248 note = "use [`HalfFloatVecExt::reinterpret_into`](trait.HalfFloatVecExt.html#tymethod.reinterpret_into) instead"
249 )]
250 #[inline]
to_bits(numbers: Vec<f16>) -> Vec<u16>251 pub fn to_bits(numbers: Vec<f16>) -> Vec<u16> {
252 numbers.reinterpret_into()
253 }
254
255 #[cfg(test)]
256 mod test {
257 use super::{HalfBitsVecExt, HalfFloatVecExt};
258 use crate::{bf16, f16};
259 #[cfg(all(feature = "alloc", not(feature = "std")))]
260 use alloc::vec;
261
262 #[test]
test_vec_conversions_f16()263 fn test_vec_conversions_f16() {
264 let numbers = vec![f16::E, f16::PI, f16::EPSILON, f16::FRAC_1_SQRT_2];
265 let bits = vec![
266 f16::E.to_bits(),
267 f16::PI.to_bits(),
268 f16::EPSILON.to_bits(),
269 f16::FRAC_1_SQRT_2.to_bits(),
270 ];
271 let bits_cloned = bits.clone();
272
273 // Convert from bits to numbers
274 let from_bits = bits.reinterpret_into::<f16>();
275 assert_eq!(&from_bits[..], &numbers[..]);
276
277 // Convert from numbers back to bits
278 let to_bits = from_bits.reinterpret_into();
279 assert_eq!(&to_bits[..], &bits_cloned[..]);
280 }
281
282 #[test]
test_vec_conversions_bf16()283 fn test_vec_conversions_bf16() {
284 let numbers = vec![bf16::E, bf16::PI, bf16::EPSILON, bf16::FRAC_1_SQRT_2];
285 let bits = vec![
286 bf16::E.to_bits(),
287 bf16::PI.to_bits(),
288 bf16::EPSILON.to_bits(),
289 bf16::FRAC_1_SQRT_2.to_bits(),
290 ];
291 let bits_cloned = bits.clone();
292
293 // Convert from bits to numbers
294 let from_bits = bits.reinterpret_into::<bf16>();
295 assert_eq!(&from_bits[..], &numbers[..]);
296
297 // Convert from numbers back to bits
298 let to_bits = from_bits.reinterpret_into();
299 assert_eq!(&to_bits[..], &bits_cloned[..]);
300 }
301 }
302