half/
slice.rs

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