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