1 //! Contains utility functions and traits to convert between slices of [`u16`] bits and [`f16`] or
2 //! [`bf16`] numbers.
3 //!
4 //! The utility [`HalfBitsSliceExt`] sealed extension trait is implemented for `[u16]` slices,
5 //! while the utility [`HalfFloatSliceExt`] sealed extension trait is implemented for both `[f16]`
6 //! and `[bf16]` slices. These traits provide efficient conversions and reinterpret casting of
7 //! larger buffers of floating point values, and are automatically included in the
8 //! [`prelude`][crate::prelude] module.
9 
10 use crate::{bf16, binary16::convert, f16};
11 #[cfg(feature = "alloc")]
12 use alloc::vec::Vec;
13 use core::slice;
14 
15 /// Extensions to `[f16]` and `[bf16]` slices to support conversion and reinterpret operations.
16 ///
17 /// This trait is sealed and cannot be implemented outside of this crate.
18 pub trait HalfFloatSliceExt: private::SealedHalfFloatSlice {
19     /// Reinterprets a slice of [`f16`] or [`bf16`] numbers as a slice of [`u16`] bits.
20     ///
21     /// This is a zero-copy operation. The reinterpreted slice has the same lifetime and memory
22     /// location as `self`.
23     ///
24     /// # Examples
25     ///
26     /// ```rust
27     /// # use half::prelude::*;
28     /// let float_buffer = [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)];
29     /// let int_buffer = float_buffer.reinterpret_cast();
30     ///
31     /// assert_eq!(int_buffer, [float_buffer[0].to_bits(), float_buffer[1].to_bits(), float_buffer[2].to_bits()]);
32     /// ```
33     fn reinterpret_cast(&self) -> &[u16];
34 
35     /// Reinterprets a mutable slice of [`f16`] or [`bf16`] numbers as a mutable slice of [`u16`].
36     /// bits
37     ///
38     /// This is a zero-copy operation. The transmuted slice has the same lifetime as the original,
39     /// which prevents mutating `self` as long as the returned `&mut [u16]` is borrowed.
40     ///
41     /// # Examples
42     ///
43     /// ```rust
44     /// # use half::prelude::*;
45     /// let mut float_buffer = [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)];
46     ///
47     /// {
48     ///     let int_buffer = float_buffer.reinterpret_cast_mut();
49     ///
50     ///     assert_eq!(int_buffer, [f16::from_f32(1.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()]);
51     ///
52     ///     // Mutating the u16 slice will mutating the original
53     ///     int_buffer[0] = 0;
54     /// }
55     ///
56     /// // Note that we need to drop int_buffer before using float_buffer again or we will get a borrow error.
57     /// assert_eq!(float_buffer, [f16::from_f32(0.), f16::from_f32(2.), f16::from_f32(3.)]);
58     /// ```
59     fn reinterpret_cast_mut(&mut self) -> &mut [u16];
60 
61     /// Converts all of the elements of a `[f32]` slice into [`f16`] or [`bf16`] values in `self`.
62     ///
63     /// The length of `src` must be the same as `self`.
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](crate) for more information on hardware conversion
68     /// support.
69     ///
70     /// # Panics
71     ///
72     /// This function will panic if the two slices have different lengths.
73     ///
74     /// # Examples
75     /// ```rust
76     /// # use half::prelude::*;
77     /// // Initialize an empty buffer
78     /// let mut buffer = [0u16; 4];
79     /// let buffer = buffer.reinterpret_cast_mut::<f16>();
80     ///
81     /// let float_values = [1., 2., 3., 4.];
82     ///
83     /// // Now convert
84     /// buffer.convert_from_f32_slice(&float_values);
85     ///
86     /// assert_eq!(buffer, [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.), f16::from_f32(4.)]);
87     /// ```
88     fn convert_from_f32_slice(&mut self, src: &[f32]);
89 
90     /// Converts all of the elements of a `[f64]` slice into [`f16`] or [`bf16`] values in `self`.
91     ///
92     /// The length of `src` must be the same as `self`.
93     ///
94     /// The conversion operation is vectorized over the slice, meaning the conversion may be more
95     /// efficient than converting individual elements on some hardware that supports SIMD
96     /// conversions. See [crate documentation](crate) for more information on hardware conversion
97     /// support.
98     ///
99     /// # Panics
100     ///
101     /// This function will panic if the two slices have different lengths.
102     ///
103     /// # Examples
104     /// ```rust
105     /// # use half::prelude::*;
106     /// // Initialize an empty buffer
107     /// let mut buffer = [0u16; 4];
108     /// let buffer = buffer.reinterpret_cast_mut::<f16>();
109     ///
110     /// let float_values = [1., 2., 3., 4.];
111     ///
112     /// // Now convert
113     /// buffer.convert_from_f64_slice(&float_values);
114     ///
115     /// assert_eq!(buffer, [f16::from_f64(1.), f16::from_f64(2.), f16::from_f64(3.), f16::from_f64(4.)]);
116     /// ```
117     fn convert_from_f64_slice(&mut self, src: &[f64]);
118 
119     /// Converts all of the [`f16`] or [`bf16`] elements of `self` into [`f32`] values in `dst`.
120     ///
121     /// The length of `src` must be the same as `self`.
122     ///
123     /// The conversion operation is vectorized over the slice, meaning the conversion may be more
124     /// efficient than converting individual elements on some hardware that supports SIMD
125     /// conversions. See [crate documentation](crate) for more information on hardware conversion
126     /// support.
127     ///
128     /// # Panics
129     ///
130     /// This function will panic if the two slices have different lengths.
131     ///
132     /// # Examples
133     /// ```rust
134     /// # use half::prelude::*;
135     /// // Initialize an empty buffer
136     /// let mut buffer = [0f32; 4];
137     ///
138     /// let half_values = [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.), f16::from_f32(4.)];
139     ///
140     /// // Now convert
141     /// half_values.convert_to_f32_slice(&mut buffer);
142     ///
143     /// assert_eq!(buffer, [1., 2., 3., 4.]);
144     /// ```
145     fn convert_to_f32_slice(&self, dst: &mut [f32]);
146 
147     /// Converts all of the [`f16`] or [`bf16`] elements of `self` into [`f64`] values in `dst`.
148     ///
149     /// The length of `src` must be the same as `self`.
150     ///
151     /// The conversion operation is vectorized over the slice, meaning the conversion may be more
152     /// efficient than converting individual elements on some hardware that supports SIMD
153     /// conversions. See [crate documentation](crate) for more information on hardware conversion
154     /// support.
155     ///
156     /// # Panics
157     ///
158     /// This function will panic if the two slices have different lengths.
159     ///
160     /// # Examples
161     /// ```rust
162     /// # use half::prelude::*;
163     /// // Initialize an empty buffer
164     /// let mut buffer = [0f64; 4];
165     ///
166     /// let half_values = [f16::from_f64(1.), f16::from_f64(2.), f16::from_f64(3.), f16::from_f64(4.)];
167     ///
168     /// // Now convert
169     /// half_values.convert_to_f64_slice(&mut buffer);
170     ///
171     /// assert_eq!(buffer, [1., 2., 3., 4.]);
172     /// ```
173     fn convert_to_f64_slice(&self, dst: &mut [f64]);
174 
175     // Because trait is sealed, we can get away with different interfaces between features.
176 
177     /// Converts all of the [`f16`] or [`bf16`] elements of `self` into [`f32`] values in a new
178     /// vector
179     ///
180     /// The conversion operation is vectorized over the slice, meaning the conversion may be more
181     /// efficient than converting individual elements on some hardware that supports SIMD
182     /// conversions. See [crate documentation](crate) for more information on hardware conversion
183     /// support.
184     ///
185     /// This method is only available with the `std` or `alloc` feature.
186     ///
187     /// # Examples
188     /// ```rust
189     /// # use half::prelude::*;
190     /// let half_values = [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.), f16::from_f32(4.)];
191     /// let vec = half_values.to_f32_vec();
192     ///
193     /// assert_eq!(vec, vec![1., 2., 3., 4.]);
194     /// ```
195     #[cfg(any(feature = "alloc", feature = "std"))]
196     #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
197     fn to_f32_vec(&self) -> Vec<f32>;
198 
199     /// Converts all of the [`f16`] or [`bf16`] elements of `self` into [`f64`] values in a new
200     /// vector.
201     ///
202     /// The conversion operation is vectorized over the slice, meaning the conversion may be more
203     /// efficient than converting individual elements on some hardware that supports SIMD
204     /// conversions. See [crate documentation](crate) for more information on hardware conversion
205     /// support.
206     ///
207     /// This method is only available with the `std` or `alloc` feature.
208     ///
209     /// # Examples
210     /// ```rust
211     /// # use half::prelude::*;
212     /// let half_values = [f16::from_f64(1.), f16::from_f64(2.), f16::from_f64(3.), f16::from_f64(4.)];
213     /// let vec = half_values.to_f64_vec();
214     ///
215     /// assert_eq!(vec, vec![1., 2., 3., 4.]);
216     /// ```
217     #[cfg(feature = "alloc")]
218     #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
219     fn to_f64_vec(&self) -> Vec<f64>;
220 }
221 
222 /// Extensions to `[u16]` slices to support reinterpret operations.
223 ///
224 /// This trait is sealed and cannot be implemented outside of this crate.
225 pub trait HalfBitsSliceExt: private::SealedHalfBitsSlice {
226     /// Reinterprets a slice of [`u16`] bits as a slice of [`f16`] or [`bf16`] numbers.
227     ///
228     /// `H` is the type to cast to, and must be either the [`f16`] or [`bf16`] type.
229     ///
230     /// This is a zero-copy operation. The reinterpreted slice has the same lifetime and memory
231     /// location as `self`.
232     ///
233     /// # Examples
234     ///
235     /// ```rust
236     /// # use half::prelude::*;
237     /// let int_buffer = [f16::from_f32(1.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()];
238     /// let float_buffer: &[f16] = int_buffer.reinterpret_cast();
239     ///
240     /// assert_eq!(float_buffer, [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)]);
241     ///
242     /// // You may have to specify the cast type directly if the compiler can't infer the type.
243     /// // The following is also valid in Rust.
244     /// let typed_buffer = int_buffer.reinterpret_cast::<f16>();
245     /// ```
246     fn reinterpret_cast<H>(&self) -> &[H]
247     where
248         H: crate::private::SealedHalf;
249 
250     /// Reinterprets a mutable slice of [`u16`] bits as a mutable slice of [`f16`] or [`bf16`]
251     /// numbers.
252     ///
253     /// `H` is the type to cast to, and must be either the [`f16`] or [`bf16`] type.
254     ///
255     /// This is a zero-copy operation. The transmuted slice has the same lifetime as the original,
256     /// which prevents mutating `self` as long as the returned `&mut [f16]` is borrowed.
257     ///
258     /// # Examples
259     ///
260     /// ```rust
261     /// # use half::prelude::*;
262     /// let mut int_buffer = [f16::from_f32(1.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()];
263     ///
264     /// {
265     ///     let float_buffer: &mut [f16] = int_buffer.reinterpret_cast_mut();
266     ///
267     ///     assert_eq!(float_buffer, [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)]);
268     ///
269     ///     // Mutating the f16 slice will mutating the original
270     ///     float_buffer[0] = f16::from_f32(0.);
271     /// }
272     ///
273     /// // Note that we need to drop float_buffer before using int_buffer again or we will get a borrow error.
274     /// assert_eq!(int_buffer, [f16::from_f32(0.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()]);
275     ///
276     /// // You may have to specify the cast type directly if the compiler can't infer the type.
277     /// // The following is also valid in Rust.
278     /// let typed_buffer = int_buffer.reinterpret_cast_mut::<f16>();
279     /// ```
280     fn reinterpret_cast_mut<H>(&mut self) -> &mut [H]
281     where
282         H: crate::private::SealedHalf;
283 }
284 
285 mod private {
286     use crate::{bf16, f16};
287 
288     pub trait SealedHalfFloatSlice {}
289     impl SealedHalfFloatSlice for [f16] {}
290     impl SealedHalfFloatSlice for [bf16] {}
291 
292     pub trait SealedHalfBitsSlice {}
293     impl SealedHalfBitsSlice for [u16] {}
294 }
295 
296 impl HalfFloatSliceExt for [f16] {
297     #[inline]
298     fn reinterpret_cast(&self) -> &[u16] {
299         let pointer = self.as_ptr() as *const u16;
300         let length = self.len();
301         // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
302         // and the size of elements are identical
303         unsafe { slice::from_raw_parts(pointer, length) }
304     }
305 
306     #[inline]
307     fn reinterpret_cast_mut(&mut self) -> &mut [u16] {
308         let pointer = self.as_ptr() as *mut u16;
309         let length = self.len();
310         // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
311         // and the size of elements are identical
312         unsafe { slice::from_raw_parts_mut(pointer, length) }
313     }
314 
315     fn convert_from_f32_slice(&mut self, src: &[f32]) {
316         assert_eq!(
317             self.len(),
318             src.len(),
319             "destination and source slices have different lengths"
320         );
321 
322         let mut chunks = src.chunks_exact(4);
323         let mut chunk_count = 0usize; // Not using .enumerate() because we need this value for remainder
324         for chunk in &mut chunks {
325             let vec = convert::f32x4_to_f16x4(chunk);
326             let dst_idx = chunk_count * 4;
327             self[dst_idx..dst_idx + 4].copy_from_slice(vec.reinterpret_cast());
328             chunk_count += 1;
329         }
330 
331         // Process remainder
332         if !chunks.remainder().is_empty() {
333             let mut buf = [0f32; 4];
334             buf[..chunks.remainder().len()].copy_from_slice(chunks.remainder());
335             let vec = convert::f32x4_to_f16x4(&buf);
336             let dst_idx = chunk_count * 4;
337             self[dst_idx..dst_idx + chunks.remainder().len()]
338                 .copy_from_slice(vec[..chunks.remainder().len()].reinterpret_cast());
339         }
340     }
341 
342     fn convert_from_f64_slice(&mut self, src: &[f64]) {
343         assert_eq!(
344             self.len(),
345             src.len(),
346             "destination and source slices have different lengths"
347         );
348 
349         let mut chunks = src.chunks_exact(4);
350         let mut chunk_count = 0usize; // Not using .enumerate() because we need this value for remainder
351         for chunk in &mut chunks {
352             let vec = convert::f64x4_to_f16x4(chunk);
353             let dst_idx = chunk_count * 4;
354             self[dst_idx..dst_idx + 4].copy_from_slice(vec.reinterpret_cast());
355             chunk_count += 1;
356         }
357 
358         // Process remainder
359         if !chunks.remainder().is_empty() {
360             let mut buf = [0f64; 4];
361             buf[..chunks.remainder().len()].copy_from_slice(chunks.remainder());
362             let vec = convert::f64x4_to_f16x4(&buf);
363             let dst_idx = chunk_count * 4;
364             self[dst_idx..dst_idx + chunks.remainder().len()]
365                 .copy_from_slice(vec[..chunks.remainder().len()].reinterpret_cast());
366         }
367     }
368 
369     fn convert_to_f32_slice(&self, dst: &mut [f32]) {
370         assert_eq!(
371             self.len(),
372             dst.len(),
373             "destination and source slices have different lengths"
374         );
375 
376         let mut chunks = self.chunks_exact(4);
377         let mut chunk_count = 0usize; // Not using .enumerate() because we need this value for remainder
378         for chunk in &mut chunks {
379             let vec = convert::f16x4_to_f32x4(chunk.reinterpret_cast());
380             let dst_idx = chunk_count * 4;
381             dst[dst_idx..dst_idx + 4].copy_from_slice(&vec);
382             chunk_count += 1;
383         }
384 
385         // Process remainder
386         if !chunks.remainder().is_empty() {
387             let mut buf = [0u16; 4];
388             buf[..chunks.remainder().len()].copy_from_slice(chunks.remainder().reinterpret_cast());
389             let vec = convert::f16x4_to_f32x4(&buf);
390             let dst_idx = chunk_count * 4;
391             dst[dst_idx..dst_idx + chunks.remainder().len()]
392                 .copy_from_slice(&vec[..chunks.remainder().len()]);
393         }
394     }
395 
396     fn convert_to_f64_slice(&self, dst: &mut [f64]) {
397         assert_eq!(
398             self.len(),
399             dst.len(),
400             "destination and source slices have different lengths"
401         );
402 
403         let mut chunks = self.chunks_exact(4);
404         let mut chunk_count = 0usize; // Not using .enumerate() because we need this value for remainder
405         for chunk in &mut chunks {
406             let vec = convert::f16x4_to_f64x4(chunk.reinterpret_cast());
407             let dst_idx = chunk_count * 4;
408             dst[dst_idx..dst_idx + 4].copy_from_slice(&vec);
409             chunk_count += 1;
410         }
411 
412         // Process remainder
413         if !chunks.remainder().is_empty() {
414             let mut buf = [0u16; 4];
415             buf[..chunks.remainder().len()].copy_from_slice(chunks.remainder().reinterpret_cast());
416             let vec = convert::f16x4_to_f64x4(&buf);
417             let dst_idx = chunk_count * 4;
418             dst[dst_idx..dst_idx + chunks.remainder().len()]
419                 .copy_from_slice(&vec[..chunks.remainder().len()]);
420         }
421     }
422 
423     #[cfg(any(feature = "alloc", feature = "std"))]
424     #[inline]
425     fn to_f32_vec(&self) -> Vec<f32> {
426         let mut vec = Vec::with_capacity(self.len());
427         // SAFETY: convert will initialize every value in the vector without reading them,
428         // so this is safe to do instead of double initialize from resize, and we're setting it to
429         // same value as capacity.
430         unsafe { vec.set_len(self.len()) };
431         self.convert_to_f32_slice(&mut vec);
432         vec
433     }
434 
435     #[cfg(any(feature = "alloc", feature = "std"))]
436     #[inline]
437     fn to_f64_vec(&self) -> Vec<f64> {
438         let mut vec = Vec::with_capacity(self.len());
439         // SAFETY: convert will initialize every value in the vector without reading them,
440         // so this is safe to do instead of double initialize from resize, and we're setting it to
441         // same value as capacity.
442         unsafe { vec.set_len(self.len()) };
443         self.convert_to_f64_slice(&mut vec);
444         vec
445     }
446 }
447 
448 impl HalfFloatSliceExt for [bf16] {
449     #[inline]
450     fn reinterpret_cast(&self) -> &[u16] {
451         let pointer = self.as_ptr() as *const u16;
452         let length = self.len();
453         // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
454         // and the size of elements are identical
455         unsafe { slice::from_raw_parts(pointer, length) }
456     }
457 
458     #[inline]
459     fn reinterpret_cast_mut(&mut self) -> &mut [u16] {
460         let pointer = self.as_ptr() as *mut u16;
461         let length = self.len();
462         // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
463         // and the size of elements are identical
464         unsafe { slice::from_raw_parts_mut(pointer, length) }
465     }
466 
467     fn convert_from_f32_slice(&mut self, src: &[f32]) {
468         assert_eq!(
469             self.len(),
470             src.len(),
471             "destination and source slices have different lengths"
472         );
473 
474         // Just use regular loop here until there's any bf16 SIMD support.
475         for (i, f) in src.iter().enumerate() {
476             self[i] = bf16::from_f32(*f);
477         }
478     }
479 
480     fn convert_from_f64_slice(&mut self, src: &[f64]) {
481         assert_eq!(
482             self.len(),
483             src.len(),
484             "destination and source slices have different lengths"
485         );
486 
487         // Just use regular loop here until there's any bf16 SIMD support.
488         for (i, f) in src.iter().enumerate() {
489             self[i] = bf16::from_f64(*f);
490         }
491     }
492 
493     fn convert_to_f32_slice(&self, dst: &mut [f32]) {
494         assert_eq!(
495             self.len(),
496             dst.len(),
497             "destination and source slices have different lengths"
498         );
499 
500         // Just use regular loop here until there's any bf16 SIMD support.
501         for (i, f) in self.iter().enumerate() {
502             dst[i] = f.to_f32();
503         }
504     }
505 
506     fn convert_to_f64_slice(&self, dst: &mut [f64]) {
507         assert_eq!(
508             self.len(),
509             dst.len(),
510             "destination and source slices have different lengths"
511         );
512 
513         // Just use regular loop here until there's any bf16 SIMD support.
514         for (i, f) in self.iter().enumerate() {
515             dst[i] = f.to_f64();
516         }
517     }
518 
519     #[cfg(any(feature = "alloc", feature = "std"))]
520     #[inline]
521     fn to_f32_vec(&self) -> Vec<f32> {
522         let mut vec = Vec::with_capacity(self.len());
523         // SAFETY: convert will initialize every value in the vector without reading them,
524         // so this is safe to do instead of double initialize from resize, and we're setting it to
525         // same value as capacity.
526         unsafe { vec.set_len(self.len()) };
527         self.convert_to_f32_slice(&mut vec);
528         vec
529     }
530 
531     #[cfg(any(feature = "alloc", feature = "std"))]
532     #[inline]
533     fn to_f64_vec(&self) -> Vec<f64> {
534         let mut vec = Vec::with_capacity(self.len());
535         // SAFETY: convert will initialize every value in the vector without reading them,
536         // so this is safe to do instead of double initialize from resize, and we're setting it to
537         // same value as capacity.
538         unsafe { vec.set_len(self.len()) };
539         self.convert_to_f64_slice(&mut vec);
540         vec
541     }
542 }
543 
544 impl HalfBitsSliceExt for [u16] {
545     // Since we sealed all the traits involved, these are safe.
546     #[inline]
547     fn reinterpret_cast<H>(&self) -> &[H]
548     where
549         H: crate::private::SealedHalf,
550     {
551         let pointer = self.as_ptr() as *const H;
552         let length = self.len();
553         // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
554         // and the size of elements are identical
555         unsafe { slice::from_raw_parts(pointer, length) }
556     }
557 
558     #[inline]
559     fn reinterpret_cast_mut<H>(&mut self) -> &mut [H]
560     where
561         H: crate::private::SealedHalf,
562     {
563         let pointer = self.as_mut_ptr() as *mut H;
564         let length = self.len();
565         // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
566         // and the size of elements are identical
567         unsafe { slice::from_raw_parts_mut(pointer, length) }
568     }
569 }
570 
571 #[doc(hidden)]
572 #[deprecated(
573     since = "1.4.0",
574     note = "use `HalfBitsSliceExt::reinterpret_cast_mut` instead"
575 )]
576 #[inline]
577 pub fn from_bits_mut(bits: &mut [u16]) -> &mut [f16] {
578     bits.reinterpret_cast_mut()
579 }
580 
581 #[doc(hidden)]
582 #[deprecated(
583     since = "1.4.0",
584     note = "use `HalfFloatSliceExt::reinterpret_cast_mut` instead"
585 )]
586 #[inline]
587 pub fn to_bits_mut(bits: &mut [f16]) -> &mut [u16] {
588     bits.reinterpret_cast_mut()
589 }
590 
591 #[doc(hidden)]
592 #[deprecated(
593     since = "1.4.0",
594     note = "use `HalfBitsSliceExt::reinterpret_cast` instead"
595 )]
596 #[inline]
597 pub fn from_bits(bits: &[u16]) -> &[f16] {
598     bits.reinterpret_cast()
599 }
600 
601 #[doc(hidden)]
602 #[deprecated(
603     since = "1.4.0",
604     note = "use `HalfFloatSliceExt::reinterpret_cast` instead"
605 )]
606 #[inline]
607 pub fn to_bits(bits: &[f16]) -> &[u16] {
608     bits.reinterpret_cast()
609 }
610 
611 #[allow(clippy::float_cmp)]
612 #[cfg(test)]
613 mod test {
614     use super::{HalfBitsSliceExt, HalfFloatSliceExt};
615     use crate::{bf16, f16};
616 
617     #[test]
618     fn test_slice_conversions_f16() {
619         let bits = &[
620             f16::E.to_bits(),
621             f16::PI.to_bits(),
622             f16::EPSILON.to_bits(),
623             f16::FRAC_1_SQRT_2.to_bits(),
624         ];
625         let numbers = &[f16::E, f16::PI, f16::EPSILON, f16::FRAC_1_SQRT_2];
626 
627         // Convert from bits to numbers
628         let from_bits = bits.reinterpret_cast::<f16>();
629         assert_eq!(from_bits, numbers);
630 
631         // Convert from numbers back to bits
632         let to_bits = from_bits.reinterpret_cast();
633         assert_eq!(to_bits, bits);
634     }
635 
636     #[test]
637     fn test_mutablility_f16() {
638         let mut bits_array = [f16::PI.to_bits()];
639         let bits = &mut bits_array[..];
640 
641         {
642             // would not compile without these braces
643             let numbers = bits.reinterpret_cast_mut();
644             numbers[0] = f16::E;
645         }
646 
647         assert_eq!(bits, &[f16::E.to_bits()]);
648 
649         bits[0] = f16::LN_2.to_bits();
650         assert_eq!(bits, &[f16::LN_2.to_bits()]);
651     }
652 
653     #[test]
654     fn test_slice_conversions_bf16() {
655         let bits = &[
656             bf16::E.to_bits(),
657             bf16::PI.to_bits(),
658             bf16::EPSILON.to_bits(),
659             bf16::FRAC_1_SQRT_2.to_bits(),
660         ];
661         let numbers = &[bf16::E, bf16::PI, bf16::EPSILON, bf16::FRAC_1_SQRT_2];
662 
663         // Convert from bits to numbers
664         let from_bits = bits.reinterpret_cast::<bf16>();
665         assert_eq!(from_bits, numbers);
666 
667         // Convert from numbers back to bits
668         let to_bits = from_bits.reinterpret_cast();
669         assert_eq!(to_bits, bits);
670     }
671 
672     #[test]
673     fn test_mutablility_bf16() {
674         let mut bits_array = [bf16::PI.to_bits()];
675         let bits = &mut bits_array[..];
676 
677         {
678             // would not compile without these braces
679             let numbers = bits.reinterpret_cast_mut();
680             numbers[0] = bf16::E;
681         }
682 
683         assert_eq!(bits, &[bf16::E.to_bits()]);
684 
685         bits[0] = bf16::LN_2.to_bits();
686         assert_eq!(bits, &[bf16::LN_2.to_bits()]);
687     }
688 
689     #[test]
690     fn slice_convert_f16_f32() {
691         // Exact chunks
692         let vf32 = [1., 2., 3., 4., 5., 6., 7., 8.];
693         let vf16 = [
694             f16::from_f32(1.),
695             f16::from_f32(2.),
696             f16::from_f32(3.),
697             f16::from_f32(4.),
698             f16::from_f32(5.),
699             f16::from_f32(6.),
700             f16::from_f32(7.),
701             f16::from_f32(8.),
702         ];
703         let mut buf32 = vf32;
704         let mut buf16 = vf16;
705 
706         vf16.convert_to_f32_slice(&mut buf32);
707         assert_eq!(&vf32, &buf32);
708 
709         buf16.convert_from_f32_slice(&vf32);
710         assert_eq!(&vf16, &buf16);
711 
712         // Partial with chunks
713         let vf32 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
714         let vf16 = [
715             f16::from_f32(1.),
716             f16::from_f32(2.),
717             f16::from_f32(3.),
718             f16::from_f32(4.),
719             f16::from_f32(5.),
720             f16::from_f32(6.),
721             f16::from_f32(7.),
722             f16::from_f32(8.),
723             f16::from_f32(9.),
724         ];
725         let mut buf32 = vf32;
726         let mut buf16 = vf16;
727 
728         vf16.convert_to_f32_slice(&mut buf32);
729         assert_eq!(&vf32, &buf32);
730 
731         buf16.convert_from_f32_slice(&vf32);
732         assert_eq!(&vf16, &buf16);
733 
734         // Partial with chunks
735         let vf32 = [1., 2.];
736         let vf16 = [f16::from_f32(1.), f16::from_f32(2.)];
737         let mut buf32 = vf32;
738         let mut buf16 = vf16;
739 
740         vf16.convert_to_f32_slice(&mut buf32);
741         assert_eq!(&vf32, &buf32);
742 
743         buf16.convert_from_f32_slice(&vf32);
744         assert_eq!(&vf16, &buf16);
745     }
746 
747     #[test]
748     fn slice_convert_bf16_f32() {
749         // Exact chunks
750         let vf32 = [1., 2., 3., 4., 5., 6., 7., 8.];
751         let vf16 = [
752             bf16::from_f32(1.),
753             bf16::from_f32(2.),
754             bf16::from_f32(3.),
755             bf16::from_f32(4.),
756             bf16::from_f32(5.),
757             bf16::from_f32(6.),
758             bf16::from_f32(7.),
759             bf16::from_f32(8.),
760         ];
761         let mut buf32 = vf32;
762         let mut buf16 = vf16;
763 
764         vf16.convert_to_f32_slice(&mut buf32);
765         assert_eq!(&vf32, &buf32);
766 
767         buf16.convert_from_f32_slice(&vf32);
768         assert_eq!(&vf16, &buf16);
769 
770         // Partial with chunks
771         let vf32 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
772         let vf16 = [
773             bf16::from_f32(1.),
774             bf16::from_f32(2.),
775             bf16::from_f32(3.),
776             bf16::from_f32(4.),
777             bf16::from_f32(5.),
778             bf16::from_f32(6.),
779             bf16::from_f32(7.),
780             bf16::from_f32(8.),
781             bf16::from_f32(9.),
782         ];
783         let mut buf32 = vf32;
784         let mut buf16 = vf16;
785 
786         vf16.convert_to_f32_slice(&mut buf32);
787         assert_eq!(&vf32, &buf32);
788 
789         buf16.convert_from_f32_slice(&vf32);
790         assert_eq!(&vf16, &buf16);
791 
792         // Partial with chunks
793         let vf32 = [1., 2.];
794         let vf16 = [bf16::from_f32(1.), bf16::from_f32(2.)];
795         let mut buf32 = vf32;
796         let mut buf16 = vf16;
797 
798         vf16.convert_to_f32_slice(&mut buf32);
799         assert_eq!(&vf32, &buf32);
800 
801         buf16.convert_from_f32_slice(&vf32);
802         assert_eq!(&vf16, &buf16);
803     }
804 
805     #[test]
806     fn slice_convert_f16_f64() {
807         // Exact chunks
808         let vf64 = [1., 2., 3., 4., 5., 6., 7., 8.];
809         let vf16 = [
810             f16::from_f64(1.),
811             f16::from_f64(2.),
812             f16::from_f64(3.),
813             f16::from_f64(4.),
814             f16::from_f64(5.),
815             f16::from_f64(6.),
816             f16::from_f64(7.),
817             f16::from_f64(8.),
818         ];
819         let mut buf64 = vf64;
820         let mut buf16 = vf16;
821 
822         vf16.convert_to_f64_slice(&mut buf64);
823         assert_eq!(&vf64, &buf64);
824 
825         buf16.convert_from_f64_slice(&vf64);
826         assert_eq!(&vf16, &buf16);
827 
828         // Partial with chunks
829         let vf64 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
830         let vf16 = [
831             f16::from_f64(1.),
832             f16::from_f64(2.),
833             f16::from_f64(3.),
834             f16::from_f64(4.),
835             f16::from_f64(5.),
836             f16::from_f64(6.),
837             f16::from_f64(7.),
838             f16::from_f64(8.),
839             f16::from_f64(9.),
840         ];
841         let mut buf64 = vf64;
842         let mut buf16 = vf16;
843 
844         vf16.convert_to_f64_slice(&mut buf64);
845         assert_eq!(&vf64, &buf64);
846 
847         buf16.convert_from_f64_slice(&vf64);
848         assert_eq!(&vf16, &buf16);
849 
850         // Partial with chunks
851         let vf64 = [1., 2.];
852         let vf16 = [f16::from_f64(1.), f16::from_f64(2.)];
853         let mut buf64 = vf64;
854         let mut buf16 = vf16;
855 
856         vf16.convert_to_f64_slice(&mut buf64);
857         assert_eq!(&vf64, &buf64);
858 
859         buf16.convert_from_f64_slice(&vf64);
860         assert_eq!(&vf16, &buf16);
861     }
862 
863     #[test]
864     fn slice_convert_bf16_f64() {
865         // Exact chunks
866         let vf64 = [1., 2., 3., 4., 5., 6., 7., 8.];
867         let vf16 = [
868             bf16::from_f64(1.),
869             bf16::from_f64(2.),
870             bf16::from_f64(3.),
871             bf16::from_f64(4.),
872             bf16::from_f64(5.),
873             bf16::from_f64(6.),
874             bf16::from_f64(7.),
875             bf16::from_f64(8.),
876         ];
877         let mut buf64 = vf64;
878         let mut buf16 = vf16;
879 
880         vf16.convert_to_f64_slice(&mut buf64);
881         assert_eq!(&vf64, &buf64);
882 
883         buf16.convert_from_f64_slice(&vf64);
884         assert_eq!(&vf16, &buf16);
885 
886         // Partial with chunks
887         let vf64 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
888         let vf16 = [
889             bf16::from_f64(1.),
890             bf16::from_f64(2.),
891             bf16::from_f64(3.),
892             bf16::from_f64(4.),
893             bf16::from_f64(5.),
894             bf16::from_f64(6.),
895             bf16::from_f64(7.),
896             bf16::from_f64(8.),
897             bf16::from_f64(9.),
898         ];
899         let mut buf64 = vf64;
900         let mut buf16 = vf16;
901 
902         vf16.convert_to_f64_slice(&mut buf64);
903         assert_eq!(&vf64, &buf64);
904 
905         buf16.convert_from_f64_slice(&vf64);
906         assert_eq!(&vf16, &buf16);
907 
908         // Partial with chunks
909         let vf64 = [1., 2.];
910         let vf16 = [bf16::from_f64(1.), bf16::from_f64(2.)];
911         let mut buf64 = vf64;
912         let mut buf16 = vf16;
913 
914         vf16.convert_to_f64_slice(&mut buf64);
915         assert_eq!(&vf64, &buf64);
916 
917         buf16.convert_from_f64_slice(&vf64);
918         assert_eq!(&vf16, &buf16);
919     }
920 
921     #[test]
922     #[should_panic]
923     fn convert_from_f32_slice_len_mismatch_panics() {
924         let mut slice1 = [f16::ZERO; 3];
925         let slice2 = [0f32; 4];
926         slice1.convert_from_f32_slice(&slice2);
927     }
928 
929     #[test]
930     #[should_panic]
931     fn convert_from_f64_slice_len_mismatch_panics() {
932         let mut slice1 = [f16::ZERO; 3];
933         let slice2 = [0f64; 4];
934         slice1.convert_from_f64_slice(&slice2);
935     }
936 
937     #[test]
938     #[should_panic]
939     fn convert_to_f32_slice_len_mismatch_panics() {
940         let slice1 = [f16::ZERO; 3];
941         let mut slice2 = [0f32; 4];
942         slice1.convert_to_f32_slice(&mut slice2);
943     }
944 
945     #[test]
946     #[should_panic]
947     fn convert_to_f64_slice_len_mismatch_panics() {
948         let slice1 = [f16::ZERO; 3];
949         let mut slice2 = [0f64; 4];
950         slice1.convert_to_f64_slice(&mut slice2);
951     }
952 }
953