half/
slice.rs

1//! Contains utility functions and traits to convert between slices of [`u16`] bits and [`struct@f16`] or
2//! [`struct@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 zerocopy::{transmute_mut, transmute_ref};
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 [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@bf16`] numbers.
230    ///
231    /// `H` is the type to cast to, and must be either the [`struct@f16`] or [`struct@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 [`struct@f16`] or [`struct@bf16`]
255    /// numbers.
256    ///
257    /// `H` is the type to cast to, and must be either the [`struct@f16`] or [`struct@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        transmute_ref!(self)
305    }
306
307    #[inline]
308    fn reinterpret_cast_mut(&mut self) -> &mut [u16] {
309        transmute_mut!(self)
310    }
311
312    #[inline]
313    fn convert_from_f32_slice(&mut self, src: &[f32]) {
314        assert_eq!(
315            self.len(),
316            src.len(),
317            "destination and source slices have different lengths"
318        );
319
320        arch::f32_to_f16_slice(src, self.reinterpret_cast_mut())
321    }
322
323    #[inline]
324    fn convert_from_f64_slice(&mut self, src: &[f64]) {
325        assert_eq!(
326            self.len(),
327            src.len(),
328            "destination and source slices have different lengths"
329        );
330
331        arch::f64_to_f16_slice(src, self.reinterpret_cast_mut())
332    }
333
334    #[inline]
335    fn convert_to_f32_slice(&self, dst: &mut [f32]) {
336        assert_eq!(
337            self.len(),
338            dst.len(),
339            "destination and source slices have different lengths"
340        );
341
342        arch::f16_to_f32_slice(self.reinterpret_cast(), dst)
343    }
344
345    #[inline]
346    fn convert_to_f64_slice(&self, dst: &mut [f64]) {
347        assert_eq!(
348            self.len(),
349            dst.len(),
350            "destination and source slices have different lengths"
351        );
352
353        arch::f16_to_f64_slice(self.reinterpret_cast(), dst)
354    }
355
356    #[cfg(any(feature = "alloc", feature = "std"))]
357    #[inline]
358    #[allow(clippy::uninit_vec)]
359    fn to_f32_vec(&self) -> Vec<f32> {
360        let mut vec = vec![0f32; self.len()];
361        self.convert_to_f32_slice(&mut vec);
362        vec
363    }
364
365    #[cfg(any(feature = "alloc", feature = "std"))]
366    #[inline]
367    #[allow(clippy::uninit_vec)]
368    fn to_f64_vec(&self) -> Vec<f64> {
369        let mut vec = vec![0f64; self.len()];
370        self.convert_to_f64_slice(&mut vec);
371        vec
372    }
373}
374
375impl HalfFloatSliceExt for [bf16] {
376    #[inline]
377    fn reinterpret_cast(&self) -> &[u16] {
378        transmute_ref!(self)
379    }
380
381    #[inline]
382    fn reinterpret_cast_mut(&mut self) -> &mut [u16] {
383        transmute_mut!(self)
384    }
385
386    #[inline]
387    fn convert_from_f32_slice(&mut self, src: &[f32]) {
388        assert_eq!(
389            self.len(),
390            src.len(),
391            "destination and source slices have different lengths"
392        );
393
394        // Just use regular loop here until there's any bf16 SIMD support.
395        for (i, f) in src.iter().enumerate() {
396            self[i] = bf16::from_f32(*f);
397        }
398    }
399
400    #[inline]
401    fn convert_from_f64_slice(&mut self, src: &[f64]) {
402        assert_eq!(
403            self.len(),
404            src.len(),
405            "destination and source slices have different lengths"
406        );
407
408        // Just use regular loop here until there's any bf16 SIMD support.
409        for (i, f) in src.iter().enumerate() {
410            self[i] = bf16::from_f64(*f);
411        }
412    }
413
414    #[inline]
415    fn convert_to_f32_slice(&self, dst: &mut [f32]) {
416        assert_eq!(
417            self.len(),
418            dst.len(),
419            "destination and source slices have different lengths"
420        );
421
422        // Just use regular loop here until there's any bf16 SIMD support.
423        for (i, f) in self.iter().enumerate() {
424            dst[i] = f.to_f32();
425        }
426    }
427
428    #[inline]
429    fn convert_to_f64_slice(&self, dst: &mut [f64]) {
430        assert_eq!(
431            self.len(),
432            dst.len(),
433            "destination and source slices have different lengths"
434        );
435
436        // Just use regular loop here until there's any bf16 SIMD support.
437        for (i, f) in self.iter().enumerate() {
438            dst[i] = f.to_f64();
439        }
440    }
441
442    #[cfg(any(feature = "alloc", feature = "std"))]
443    #[inline]
444    #[allow(clippy::uninit_vec)]
445    fn to_f32_vec(&self) -> Vec<f32> {
446        let mut vec = vec![0f32; self.len()];
447        self.convert_to_f32_slice(&mut vec);
448        vec
449    }
450
451    #[cfg(any(feature = "alloc", feature = "std"))]
452    #[inline]
453    #[allow(clippy::uninit_vec)]
454    fn to_f64_vec(&self) -> Vec<f64> {
455        let mut vec = vec![0f64; self.len()];
456        self.convert_to_f64_slice(&mut vec);
457        vec
458    }
459}
460
461impl HalfBitsSliceExt for [u16] {
462    // Since we sealed all the traits involved, these are safe.
463    #[inline]
464    fn reinterpret_cast<H>(&self) -> &[H]
465    where
466        H: crate::private::SealedHalf,
467    {
468        transmute_ref!(self)
469    }
470
471    #[inline]
472    fn reinterpret_cast_mut<H>(&mut self) -> &mut [H]
473    where
474        H: crate::private::SealedHalf,
475    {
476        transmute_mut!(self)
477    }
478}
479
480#[allow(clippy::float_cmp)]
481#[cfg(test)]
482mod test {
483    use super::{HalfBitsSliceExt, HalfFloatSliceExt};
484    use crate::{bf16, f16};
485
486    #[test]
487    fn test_slice_conversions_f16() {
488        let bits = &[
489            f16::E.to_bits(),
490            f16::PI.to_bits(),
491            f16::EPSILON.to_bits(),
492            f16::FRAC_1_SQRT_2.to_bits(),
493        ];
494        let numbers = &[f16::E, f16::PI, f16::EPSILON, f16::FRAC_1_SQRT_2];
495
496        // Convert from bits to numbers
497        let from_bits = bits.reinterpret_cast::<f16>();
498        assert_eq!(from_bits, numbers);
499
500        // Convert from numbers back to bits
501        let to_bits = from_bits.reinterpret_cast();
502        assert_eq!(to_bits, bits);
503    }
504
505    #[test]
506    fn test_mutablility_f16() {
507        let mut bits_array = [f16::PI.to_bits()];
508        let bits = &mut bits_array[..];
509
510        {
511            // would not compile without these braces
512            let numbers = bits.reinterpret_cast_mut();
513            numbers[0] = f16::E;
514        }
515
516        assert_eq!(bits, &[f16::E.to_bits()]);
517
518        bits[0] = f16::LN_2.to_bits();
519        assert_eq!(bits, &[f16::LN_2.to_bits()]);
520    }
521
522    #[test]
523    fn test_slice_conversions_bf16() {
524        let bits = &[
525            bf16::E.to_bits(),
526            bf16::PI.to_bits(),
527            bf16::EPSILON.to_bits(),
528            bf16::FRAC_1_SQRT_2.to_bits(),
529        ];
530        let numbers = &[bf16::E, bf16::PI, bf16::EPSILON, bf16::FRAC_1_SQRT_2];
531
532        // Convert from bits to numbers
533        let from_bits = bits.reinterpret_cast::<bf16>();
534        assert_eq!(from_bits, numbers);
535
536        // Convert from numbers back to bits
537        let to_bits = from_bits.reinterpret_cast();
538        assert_eq!(to_bits, bits);
539    }
540
541    #[test]
542    fn test_mutablility_bf16() {
543        let mut bits_array = [bf16::PI.to_bits()];
544        let bits = &mut bits_array[..];
545
546        {
547            // would not compile without these braces
548            let numbers = bits.reinterpret_cast_mut();
549            numbers[0] = bf16::E;
550        }
551
552        assert_eq!(bits, &[bf16::E.to_bits()]);
553
554        bits[0] = bf16::LN_2.to_bits();
555        assert_eq!(bits, &[bf16::LN_2.to_bits()]);
556    }
557
558    #[test]
559    fn slice_convert_f16_f32() {
560        // Exact chunks
561        let vf32 = [1., 2., 3., 4., 5., 6., 7., 8.];
562        let vf16 = [
563            f16::from_f32(1.),
564            f16::from_f32(2.),
565            f16::from_f32(3.),
566            f16::from_f32(4.),
567            f16::from_f32(5.),
568            f16::from_f32(6.),
569            f16::from_f32(7.),
570            f16::from_f32(8.),
571        ];
572        let mut buf32 = vf32;
573        let mut buf16 = vf16;
574
575        vf16.convert_to_f32_slice(&mut buf32);
576        assert_eq!(&vf32, &buf32);
577
578        buf16.convert_from_f32_slice(&vf32);
579        assert_eq!(&vf16, &buf16);
580
581        // Partial with chunks
582        let vf32 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
583        let vf16 = [
584            f16::from_f32(1.),
585            f16::from_f32(2.),
586            f16::from_f32(3.),
587            f16::from_f32(4.),
588            f16::from_f32(5.),
589            f16::from_f32(6.),
590            f16::from_f32(7.),
591            f16::from_f32(8.),
592            f16::from_f32(9.),
593        ];
594        let mut buf32 = vf32;
595        let mut buf16 = vf16;
596
597        vf16.convert_to_f32_slice(&mut buf32);
598        assert_eq!(&vf32, &buf32);
599
600        buf16.convert_from_f32_slice(&vf32);
601        assert_eq!(&vf16, &buf16);
602
603        // Partial with chunks
604        let vf32 = [1., 2.];
605        let vf16 = [f16::from_f32(1.), f16::from_f32(2.)];
606        let mut buf32 = vf32;
607        let mut buf16 = vf16;
608
609        vf16.convert_to_f32_slice(&mut buf32);
610        assert_eq!(&vf32, &buf32);
611
612        buf16.convert_from_f32_slice(&vf32);
613        assert_eq!(&vf16, &buf16);
614    }
615
616    #[test]
617    fn slice_convert_bf16_f32() {
618        // Exact chunks
619        let vf32 = [1., 2., 3., 4., 5., 6., 7., 8.];
620        let vf16 = [
621            bf16::from_f32(1.),
622            bf16::from_f32(2.),
623            bf16::from_f32(3.),
624            bf16::from_f32(4.),
625            bf16::from_f32(5.),
626            bf16::from_f32(6.),
627            bf16::from_f32(7.),
628            bf16::from_f32(8.),
629        ];
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        // Partial with chunks
640        let vf32 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
641        let vf16 = [
642            bf16::from_f32(1.),
643            bf16::from_f32(2.),
644            bf16::from_f32(3.),
645            bf16::from_f32(4.),
646            bf16::from_f32(5.),
647            bf16::from_f32(6.),
648            bf16::from_f32(7.),
649            bf16::from_f32(8.),
650            bf16::from_f32(9.),
651        ];
652        let mut buf32 = vf32;
653        let mut buf16 = vf16;
654
655        vf16.convert_to_f32_slice(&mut buf32);
656        assert_eq!(&vf32, &buf32);
657
658        buf16.convert_from_f32_slice(&vf32);
659        assert_eq!(&vf16, &buf16);
660
661        // Partial with chunks
662        let vf32 = [1., 2.];
663        let vf16 = [bf16::from_f32(1.), bf16::from_f32(2.)];
664        let mut buf32 = vf32;
665        let mut buf16 = vf16;
666
667        vf16.convert_to_f32_slice(&mut buf32);
668        assert_eq!(&vf32, &buf32);
669
670        buf16.convert_from_f32_slice(&vf32);
671        assert_eq!(&vf16, &buf16);
672    }
673
674    #[test]
675    fn slice_convert_f16_f64() {
676        // Exact chunks
677        let vf64 = [1., 2., 3., 4., 5., 6., 7., 8.];
678        let vf16 = [
679            f16::from_f64(1.),
680            f16::from_f64(2.),
681            f16::from_f64(3.),
682            f16::from_f64(4.),
683            f16::from_f64(5.),
684            f16::from_f64(6.),
685            f16::from_f64(7.),
686            f16::from_f64(8.),
687        ];
688        let mut buf64 = vf64;
689        let mut buf16 = vf16;
690
691        vf16.convert_to_f64_slice(&mut buf64);
692        assert_eq!(&vf64, &buf64);
693
694        buf16.convert_from_f64_slice(&vf64);
695        assert_eq!(&vf16, &buf16);
696
697        // Partial with chunks
698        let vf64 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
699        let vf16 = [
700            f16::from_f64(1.),
701            f16::from_f64(2.),
702            f16::from_f64(3.),
703            f16::from_f64(4.),
704            f16::from_f64(5.),
705            f16::from_f64(6.),
706            f16::from_f64(7.),
707            f16::from_f64(8.),
708            f16::from_f64(9.),
709        ];
710        let mut buf64 = vf64;
711        let mut buf16 = vf16;
712
713        vf16.convert_to_f64_slice(&mut buf64);
714        assert_eq!(&vf64, &buf64);
715
716        buf16.convert_from_f64_slice(&vf64);
717        assert_eq!(&vf16, &buf16);
718
719        // Partial with chunks
720        let vf64 = [1., 2.];
721        let vf16 = [f16::from_f64(1.), f16::from_f64(2.)];
722        let mut buf64 = vf64;
723        let mut buf16 = vf16;
724
725        vf16.convert_to_f64_slice(&mut buf64);
726        assert_eq!(&vf64, &buf64);
727
728        buf16.convert_from_f64_slice(&vf64);
729        assert_eq!(&vf16, &buf16);
730    }
731
732    #[test]
733    fn slice_convert_bf16_f64() {
734        // Exact chunks
735        let vf64 = [1., 2., 3., 4., 5., 6., 7., 8.];
736        let vf16 = [
737            bf16::from_f64(1.),
738            bf16::from_f64(2.),
739            bf16::from_f64(3.),
740            bf16::from_f64(4.),
741            bf16::from_f64(5.),
742            bf16::from_f64(6.),
743            bf16::from_f64(7.),
744            bf16::from_f64(8.),
745        ];
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        // Partial with chunks
756        let vf64 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
757        let vf16 = [
758            bf16::from_f64(1.),
759            bf16::from_f64(2.),
760            bf16::from_f64(3.),
761            bf16::from_f64(4.),
762            bf16::from_f64(5.),
763            bf16::from_f64(6.),
764            bf16::from_f64(7.),
765            bf16::from_f64(8.),
766            bf16::from_f64(9.),
767        ];
768        let mut buf64 = vf64;
769        let mut buf16 = vf16;
770
771        vf16.convert_to_f64_slice(&mut buf64);
772        assert_eq!(&vf64, &buf64);
773
774        buf16.convert_from_f64_slice(&vf64);
775        assert_eq!(&vf16, &buf16);
776
777        // Partial with chunks
778        let vf64 = [1., 2.];
779        let vf16 = [bf16::from_f64(1.), bf16::from_f64(2.)];
780        let mut buf64 = vf64;
781        let mut buf16 = vf16;
782
783        vf16.convert_to_f64_slice(&mut buf64);
784        assert_eq!(&vf64, &buf64);
785
786        buf16.convert_from_f64_slice(&vf64);
787        assert_eq!(&vf16, &buf16);
788    }
789
790    #[test]
791    #[should_panic]
792    fn convert_from_f32_slice_len_mismatch_panics() {
793        let mut slice1 = [f16::ZERO; 3];
794        let slice2 = [0f32; 4];
795        slice1.convert_from_f32_slice(&slice2);
796    }
797
798    #[test]
799    #[should_panic]
800    fn convert_from_f64_slice_len_mismatch_panics() {
801        let mut slice1 = [f16::ZERO; 3];
802        let slice2 = [0f64; 4];
803        slice1.convert_from_f64_slice(&slice2);
804    }
805
806    #[test]
807    #[should_panic]
808    fn convert_to_f32_slice_len_mismatch_panics() {
809        let slice1 = [f16::ZERO; 3];
810        let mut slice2 = [0f32; 4];
811        slice1.convert_to_f32_slice(&mut slice2);
812    }
813
814    #[test]
815    #[should_panic]
816    fn convert_to_f64_slice_len_mismatch_panics() {
817        let slice1 = [f16::ZERO; 3];
818        let mut slice2 = [0f64; 4];
819        slice1.convert_to_f64_slice(&mut slice2);
820    }
821}