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 10 use crate::{bf16, binary16::convert, f16}; 11 #[cfg(feature = "alloc")] 12 use alloc::vec::Vec; 13 use 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. 18 pub 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. 225 pub 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 285 mod 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 296 impl 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 448 impl 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 544 impl 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] 577 pub 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] 587 pub 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] 597 pub 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] 607 pub fn to_bits(bits: &[f16]) -> &[u16] { 608 bits.reinterpret_cast() 609 } 610 611 #[allow(clippy::float_cmp)] 612 #[cfg(test)] 613 mod 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