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;
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}
846