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