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}