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