Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  slice.rs   Sprache: unbekannt

 
//! Contains utility functions and traits to convert between slices of [`u16`] bits and [`f16`] or
//! [`bf16`] numbers.
//!
//! The utility [`HalfBitsSliceExt`] sealed extension trait is implemented for `[u16]` slices,
//! while the utility [`HalfFloatSliceExt`] sealed extension trait is implemented for both `[f16]`
//! and `[bf16]` slices. These traits provide efficient conversions and reinterpret casting of
//! larger buffers of floating point values, and are automatically included in the
//! [`prelude`][crate::prelude] module.

use crate::{bf16, binary16::convert, f16};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::slice;

/// Extensions to `[f16]` and `[bf16]` slices to support conversion and reinterpret operations.
///
/// This trait is sealed and cannot be implemented outside of this crate.
pub trait HalfFloatSliceExt: private::SealedHalfFloatSlice {
    /// Reinterprets a slice of [`f16`] or [`bf16`] numbers as a slice of [`u16`] bits.
    ///
    /// This is a zero-copy operation. The reinterpreted slice has the same lifetime and memory
    /// location as `self`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use half::prelude::*;
    /// let float_buffer = [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)];
    /// let int_buffer = float_buffer.reinterpret_cast();
    ///
    /// assert_eq!(int_buffer, [float_buffer[0].to_bits(), float_buffer[1].to_bits(), float_buffer[2].to_bits()]);
    /// ```
    fn reinterpret_cast(&self) -> &[u16];

    /// Reinterprets a mutable slice of [`f16`] or [`bf16`] numbers as a mutable slice of [`u16`].
    /// bits
    ///
    /// This is a zero-copy operation. The transmuted slice has the same lifetime as the original,
    /// which prevents mutating `self` as long as the returned `&mut [u16]` is borrowed.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use half::prelude::*;
    /// let mut float_buffer = [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)];
    ///
    /// {
    ///     let int_buffer = float_buffer.reinterpret_cast_mut();
    ///
    ///     assert_eq!(int_buffer, [f16::from_f32(1.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()]);
    ///
    ///     // Mutating the u16 slice will mutating the original
    ///     int_buffer[0] = 0;
    /// }
    ///
    /// // Note that we need to drop int_buffer before using float_buffer again or we will get a borrow error.
    /// assert_eq!(float_buffer, [f16::from_f32(0.), f16::from_f32(2.), f16::from_f32(3.)]);
    /// ```
    fn reinterpret_cast_mut(&mut self) -> &mut [u16];

    /// Converts all of the elements of a `[f32]` slice into [`f16`] or [`bf16`] values in `self`.
    ///
    /// The length of `src` must be the same as `self`.
    ///
    /// The conversion operation is vectorized over the slice, meaning the conversion may be more
    /// efficient than converting individual elements on some hardware that supports SIMD
    /// conversions. See [crate documentation](crate) for more information on hardware conversion
    /// support.
    ///
    /// # Panics
    ///
    /// This function will panic if the two slices have different lengths.
    ///
    /// # Examples
    /// ```rust
    /// # use half::prelude::*;
    /// // Initialize an empty buffer
    /// let mut buffer = [0u16; 4];
    /// let buffer = buffer.reinterpret_cast_mut::<f16>();
    ///
    /// let float_values = [1., 2., 3., 4.];
    ///
    /// // Now convert
    /// buffer.convert_from_f32_slice(&float_values);
    ///
    /// assert_eq!(buffer, [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.), f16::from_f32(4.)]);
    /// ```
    fn convert_from_f32_slice(&mut self, src: &[f32]);

    /// Converts all of the elements of a `[f64]` slice into [`f16`] or [`bf16`] values in `self`.
    ///
    /// The length of `src` must be the same as `self`.
    ///
    /// The conversion operation is vectorized over the slice, meaning the conversion may be more
    /// efficient than converting individual elements on some hardware that supports SIMD
    /// conversions. See [crate documentation](crate) for more information on hardware conversion
    /// support.
    ///
    /// # Panics
    ///
    /// This function will panic if the two slices have different lengths.
    ///
    /// # Examples
    /// ```rust
    /// # use half::prelude::*;
    /// // Initialize an empty buffer
    /// let mut buffer = [0u16; 4];
    /// let buffer = buffer.reinterpret_cast_mut::<f16>();
    ///
    /// let float_values = [1., 2., 3., 4.];
    ///
    /// // Now convert
    /// buffer.convert_from_f64_slice(&float_values);
    ///
    /// assert_eq!(buffer, [f16::from_f64(1.), f16::from_f64(2.), f16::from_f64(3.), f16::from_f64(4.)]);
    /// ```
    fn convert_from_f64_slice(&mut self, src: &[f64]);

    /// Converts all of the [`f16`] or [`bf16`] elements of `self` into [`f32`] values in `dst`.
    ///
    /// The length of `src` must be the same as `self`.
    ///
    /// The conversion operation is vectorized over the slice, meaning the conversion may be more
    /// efficient than converting individual elements on some hardware that supports SIMD
    /// conversions. See [crate documentation](crate) for more information on hardware conversion
    /// support.
    ///
    /// # Panics
    ///
    /// This function will panic if the two slices have different lengths.
    ///
    /// # Examples
    /// ```rust
    /// # use half::prelude::*;
    /// // Initialize an empty buffer
    /// let mut buffer = [0f32; 4];
    ///
    /// let half_values = [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.), f16::from_f32(4.)];
    ///
    /// // Now convert
    /// half_values.convert_to_f32_slice(&mut buffer);
    ///
    /// assert_eq!(buffer, [1., 2., 3., 4.]);
    /// ```
    fn convert_to_f32_slice(&self, dst: &mut [f32]);

    /// Converts all of the [`f16`] or [`bf16`] elements of `self` into [`f64`] values in `dst`.
    ///
    /// The length of `src` must be the same as `self`.
    ///
    /// The conversion operation is vectorized over the slice, meaning the conversion may be more
    /// efficient than converting individual elements on some hardware that supports SIMD
    /// conversions. See [crate documentation](crate) for more information on hardware conversion
    /// support.
    ///
    /// # Panics
    ///
    /// This function will panic if the two slices have different lengths.
    ///
    /// # Examples
    /// ```rust
    /// # use half::prelude::*;
    /// // Initialize an empty buffer
    /// let mut buffer = [0f64; 4];
    ///
    /// let half_values = [f16::from_f64(1.), f16::from_f64(2.), f16::from_f64(3.), f16::from_f64(4.)];
    ///
    /// // Now convert
    /// half_values.convert_to_f64_slice(&mut buffer);
    ///
    /// assert_eq!(buffer, [1., 2., 3., 4.]);
    /// ```
    fn convert_to_f64_slice(&self, dst: &mut [f64]);

    // Because trait is sealed, we can get away with different interfaces between features.

    /// Converts all of the [`f16`] or [`bf16`] elements of `self` into [`f32`] values in a new
    /// vector
    ///
    /// The conversion operation is vectorized over the slice, meaning the conversion may be more
    /// efficient than converting individual elements on some hardware that supports SIMD
    /// conversions. See [crate documentation](crate) for more information on hardware conversion
    /// support.
    ///
    /// This method is only available with the `std` or `alloc` feature.
    ///
    /// # Examples
    /// ```rust
    /// # use half::prelude::*;
    /// let half_values = [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.), f16::from_f32(4.)];
    /// let vec = half_values.to_f32_vec();
    ///
    /// assert_eq!(vec, vec![1., 2., 3., 4.]);
    /// ```
    #[cfg(any(feature = "alloc", feature = "std"))]
    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
    fn to_f32_vec(&self) -> Vec<f32>;

    /// Converts all of the [`f16`] or [`bf16`] elements of `self` into [`f64`] values in a new
    /// vector.
    ///
    /// The conversion operation is vectorized over the slice, meaning the conversion may be more
    /// efficient than converting individual elements on some hardware that supports SIMD
    /// conversions. See [crate documentation](crate) for more information on hardware conversion
    /// support.
    ///
    /// This method is only available with the `std` or `alloc` feature.
    ///
    /// # Examples
    /// ```rust
    /// # use half::prelude::*;
    /// let half_values = [f16::from_f64(1.), f16::from_f64(2.), f16::from_f64(3.), f16::from_f64(4.)];
    /// let vec = half_values.to_f64_vec();
    ///
    /// assert_eq!(vec, vec![1., 2., 3., 4.]);
    /// ```
    #[cfg(feature = "alloc")]
    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
    fn to_f64_vec(&self) -> Vec<f64>;
}

/// Extensions to `[u16]` slices to support reinterpret operations.
///
/// This trait is sealed and cannot be implemented outside of this crate.
pub trait HalfBitsSliceExt: private::SealedHalfBitsSlice {
    /// Reinterprets a slice of [`u16`] bits as a slice of [`f16`] or [`bf16`] numbers.
    ///
    /// `H` is the type to cast to, and must be either the [`f16`] or [`bf16`] type.
    ///
    /// This is a zero-copy operation. The reinterpreted slice has the same lifetime and memory
    /// location as `self`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use half::prelude::*;
    /// let int_buffer = [f16::from_f32(1.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()];
    /// let float_buffer: &[f16] = int_buffer.reinterpret_cast();
    ///
    /// assert_eq!(float_buffer, [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)]);
    ///
    /// // You may have to specify the cast type directly if the compiler can't infer the type.
    /// // The following is also valid in Rust.
    /// let typed_buffer = int_buffer.reinterpret_cast::<f16>();
    /// ```
    fn reinterpret_cast<H>(&self) -> &[H]
    where
        H: crate::private::SealedHalf;

    /// Reinterprets a mutable slice of [`u16`] bits as a mutable slice of [`f16`] or [`bf16`]
    /// numbers.
    ///
    /// `H` is the type to cast to, and must be either the [`f16`] or [`bf16`] type.
    ///
    /// This is a zero-copy operation. The transmuted slice has the same lifetime as the original,
    /// which prevents mutating `self` as long as the returned `&mut [f16]` is borrowed.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use half::prelude::*;
    /// let mut int_buffer = [f16::from_f32(1.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()];
    ///
    /// {
    ///     let float_buffer: &mut [f16] = int_buffer.reinterpret_cast_mut();
    ///
    ///     assert_eq!(float_buffer, [f16::from_f32(1.), f16::from_f32(2.), f16::from_f32(3.)]);
    ///
    ///     // Mutating the f16 slice will mutating the original
    ///     float_buffer[0] = f16::from_f32(0.);
    /// }
    ///
    /// // Note that we need to drop float_buffer before using int_buffer again or we will get a borrow error.
    /// assert_eq!(int_buffer, [f16::from_f32(0.).to_bits(), f16::from_f32(2.).to_bits(), f16::from_f32(3.).to_bits()]);
    ///
    /// // You may have to specify the cast type directly if the compiler can't infer the type.
    /// // The following is also valid in Rust.
    /// let typed_buffer = int_buffer.reinterpret_cast_mut::<f16>();
    /// ```
    fn reinterpret_cast_mut<H>(&mut self) -> &mut [H]
    where
        H: crate::private::SealedHalf;
}

mod private {
    use crate::{bf16, f16};

    pub trait SealedHalfFloatSlice {}
    impl SealedHalfFloatSlice for [f16] {}
    impl SealedHalfFloatSlice for [bf16] {}

    pub trait SealedHalfBitsSlice {}
    impl SealedHalfBitsSlice for [u16] {}
}

impl HalfFloatSliceExt for [f16] {
    #[inline]
    fn reinterpret_cast(&self) -> &[u16] {
        let pointer = self.as_ptr() as *const u16;
        let length = self.len();
        // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
        // and the size of elements are identical
        unsafe { slice::from_raw_parts(pointer, length) }
    }

    #[inline]
    fn reinterpret_cast_mut(&mut self) -> &mut [u16] {
        let pointer = self.as_ptr() as *mut u16;
        let length = self.len();
        // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
        // and the size of elements are identical
        unsafe { slice::from_raw_parts_mut(pointer, length) }
    }

    fn convert_from_f32_slice(&mut self, src: &[f32]) {
        assert_eq!(
            self.len(),
            src.len(),
            "destination and source slices have different lengths"
        );

        let mut chunks = src.chunks_exact(4);
        let mut chunk_count = 0usize; // Not using .enumerate() because we need this value for remainder
        for chunk in &mut chunks {
            let vec = convert::f32x4_to_f16x4(chunk);
            let dst_idx = chunk_count * 4;
            self[dst_idx..dst_idx + 4].copy_from_slice(vec.reinterpret_cast());
            chunk_count += 1;
        }

        // Process remainder
        if !chunks.remainder().is_empty() {
            let mut buf = [0f32; 4];
            buf[..chunks.remainder().len()].copy_from_slice(chunks.remainder());
            let vec = convert::f32x4_to_f16x4(&buf);
            let dst_idx = chunk_count * 4;
            self[dst_idx..dst_idx + chunks.remainder().len()]
                .copy_from_slice(vec[..chunks.remainder().len()].reinterpret_cast());
        }
    }

    fn convert_from_f64_slice(&mut self, src: &[f64]) {
        assert_eq!(
            self.len(),
            src.len(),
            "destination and source slices have different lengths"
        );

        let mut chunks = src.chunks_exact(4);
        let mut chunk_count = 0usize; // Not using .enumerate() because we need this value for remainder
        for chunk in &mut chunks {
            let vec = convert::f64x4_to_f16x4(chunk);
            let dst_idx = chunk_count * 4;
            self[dst_idx..dst_idx + 4].copy_from_slice(vec.reinterpret_cast());
            chunk_count += 1;
        }

        // Process remainder
        if !chunks.remainder().is_empty() {
            let mut buf = [0f64; 4];
            buf[..chunks.remainder().len()].copy_from_slice(chunks.remainder());
            let vec = convert::f64x4_to_f16x4(&buf);
            let dst_idx = chunk_count * 4;
            self[dst_idx..dst_idx + chunks.remainder().len()]
                .copy_from_slice(vec[..chunks.remainder().len()].reinterpret_cast());
        }
    }

    fn convert_to_f32_slice(&self, dst: &mut [f32]) {
        assert_eq!(
            self.len(),
            dst.len(),
            "destination and source slices have different lengths"
        );

        let mut chunks = self.chunks_exact(4);
        let mut chunk_count = 0usize; // Not using .enumerate() because we need this value for remainder
        for chunk in &mut chunks {
            let vec = convert::f16x4_to_f32x4(chunk.reinterpret_cast());
            let dst_idx = chunk_count * 4;
            dst[dst_idx..dst_idx + 4].copy_from_slice(&vec);
            chunk_count += 1;
        }

        // Process remainder
        if !chunks.remainder().is_empty() {
            let mut buf = [0u16; 4];
            buf[..chunks.remainder().len()].copy_from_slice(chunks.remainder().reinterpret_cast());
            let vec = convert::f16x4_to_f32x4(&buf);
            let dst_idx = chunk_count * 4;
            dst[dst_idx..dst_idx + chunks.remainder().len()]
                .copy_from_slice(&vec[..chunks.remainder().len()]);
        }
    }

    fn convert_to_f64_slice(&self, dst: &mut [f64]) {
        assert_eq!(
            self.len(),
            dst.len(),
            "destination and source slices have different lengths"
        );

        let mut chunks = self.chunks_exact(4);
        let mut chunk_count = 0usize; // Not using .enumerate() because we need this value for remainder
        for chunk in &mut chunks {
            let vec = convert::f16x4_to_f64x4(chunk.reinterpret_cast());
            let dst_idx = chunk_count * 4;
            dst[dst_idx..dst_idx + 4].copy_from_slice(&vec);
            chunk_count += 1;
        }

        // Process remainder
        if !chunks.remainder().is_empty() {
            let mut buf = [0u16; 4];
            buf[..chunks.remainder().len()].copy_from_slice(chunks.remainder().reinterpret_cast());
            let vec = convert::f16x4_to_f64x4(&buf);
            let dst_idx = chunk_count * 4;
            dst[dst_idx..dst_idx + chunks.remainder().len()]
                .copy_from_slice(&vec[..chunks.remainder().len()]);
        }
    }

    #[cfg(any(feature = "alloc", feature = "std"))]
    #[inline]
    fn to_f32_vec(&self) -> Vec<f32> {
        let mut vec = Vec::with_capacity(self.len());
        // SAFETY: convert will initialize every value in the vector without reading them,
        // so this is safe to do instead of double initialize from resize, and we're setting it to
        // same value as capacity.
        unsafe { vec.set_len(self.len()) };
        self.convert_to_f32_slice(&mut vec);
        vec
    }

    #[cfg(any(feature = "alloc", feature = "std"))]
    #[inline]
    fn to_f64_vec(&self) -> Vec<f64> {
        let mut vec = Vec::with_capacity(self.len());
        // SAFETY: convert will initialize every value in the vector without reading them,
        // so this is safe to do instead of double initialize from resize, and we're setting it to
        // same value as capacity.
        unsafe { vec.set_len(self.len()) };
        self.convert_to_f64_slice(&mut vec);
        vec
    }
}

impl HalfFloatSliceExt for [bf16] {
    #[inline]
    fn reinterpret_cast(&self) -> &[u16] {
        let pointer = self.as_ptr() as *const u16;
        let length = self.len();
        // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
        // and the size of elements are identical
        unsafe { slice::from_raw_parts(pointer, length) }
    }

    #[inline]
    fn reinterpret_cast_mut(&mut self) -> &mut [u16] {
        let pointer = self.as_ptr() as *mut u16;
        let length = self.len();
        // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
        // and the size of elements are identical
        unsafe { slice::from_raw_parts_mut(pointer, length) }
    }

    fn convert_from_f32_slice(&mut self, src: &[f32]) {
        assert_eq!(
            self.len(),
            src.len(),
            "destination and source slices have different lengths"
        );

        // Just use regular loop here until there's any bf16 SIMD support.
        for (i, f) in src.iter().enumerate() {
            self[i] = bf16::from_f32(*f);
        }
    }

    fn convert_from_f64_slice(&mut self, src: &[f64]) {
        assert_eq!(
            self.len(),
            src.len(),
            "destination and source slices have different lengths"
        );

        // Just use regular loop here until there's any bf16 SIMD support.
        for (i, f) in src.iter().enumerate() {
            self[i] = bf16::from_f64(*f);
        }
    }

    fn convert_to_f32_slice(&self, dst: &mut [f32]) {
        assert_eq!(
            self.len(),
            dst.len(),
            "destination and source slices have different lengths"
        );

        // Just use regular loop here until there's any bf16 SIMD support.
        for (i, f) in self.iter().enumerate() {
            dst[i] = f.to_f32();
        }
    }

    fn convert_to_f64_slice(&self, dst: &mut [f64]) {
        assert_eq!(
            self.len(),
            dst.len(),
            "destination and source slices have different lengths"
        );

        // Just use regular loop here until there's any bf16 SIMD support.
        for (i, f) in self.iter().enumerate() {
            dst[i] = f.to_f64();
        }
    }

    #[cfg(any(feature = "alloc", feature = "std"))]
    #[inline]
    fn to_f32_vec(&self) -> Vec<f32> {
        let mut vec = Vec::with_capacity(self.len());
        // SAFETY: convert will initialize every value in the vector without reading them,
        // so this is safe to do instead of double initialize from resize, and we're setting it to
        // same value as capacity.
        unsafe { vec.set_len(self.len()) };
        self.convert_to_f32_slice(&mut vec);
        vec
    }

    #[cfg(any(feature = "alloc", feature = "std"))]
    #[inline]
    fn to_f64_vec(&self) -> Vec<f64> {
        let mut vec = Vec::with_capacity(self.len());
        // SAFETY: convert will initialize every value in the vector without reading them,
        // so this is safe to do instead of double initialize from resize, and we're setting it to
        // same value as capacity.
        unsafe { vec.set_len(self.len()) };
        self.convert_to_f64_slice(&mut vec);
        vec
    }
}

impl HalfBitsSliceExt for [u16] {
    // Since we sealed all the traits involved, these are safe.
    #[inline]
    fn reinterpret_cast<H>(&self) -> &[H]
    where
        H: crate::private::SealedHalf,
    {
        let pointer = self.as_ptr() as *const H;
        let length = self.len();
        // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
        // and the size of elements are identical
        unsafe { slice::from_raw_parts(pointer, length) }
    }

    #[inline]
    fn reinterpret_cast_mut<H>(&mut self) -> &mut [H]
    where
        H: crate::private::SealedHalf,
    {
        let pointer = self.as_mut_ptr() as *mut H;
        let length = self.len();
        // SAFETY: We are reconstructing full length of original slice, using its same lifetime,
        // and the size of elements are identical
        unsafe { slice::from_raw_parts_mut(pointer, length) }
    }
}

#[doc(hidden)]
#[deprecated(
    since = "1.4.0",
    note = "use `HalfBitsSliceExt::reinterpret_cast_mut` instead"
)]
#[inline]
pub fn from_bits_mut(bits: &mut [u16]) -> &mut [f16] {
    bits.reinterpret_cast_mut()
}

#[doc(hidden)]
#[deprecated(
    since = "1.4.0",
    note = "use `HalfFloatSliceExt::reinterpret_cast_mut` instead"
)]
#[inline]
pub fn to_bits_mut(bits: &mut [f16]) -> &mut [u16] {
    bits.reinterpret_cast_mut()
}

#[doc(hidden)]
#[deprecated(
    since = "1.4.0",
    note = "use `HalfBitsSliceExt::reinterpret_cast` instead"
)]
#[inline]
pub fn from_bits(bits: &[u16]) -> &[f16] {
    bits.reinterpret_cast()
}

#[doc(hidden)]
#[deprecated(
    since = "1.4.0",
    note = "use `HalfFloatSliceExt::reinterpret_cast` instead"
)]
#[inline]
pub fn to_bits(bits: &[f16]) -> &[u16] {
    bits.reinterpret_cast()
}

#[allow(clippy::float_cmp)]
#[cfg(test)]
mod test {
    use super::{HalfBitsSliceExt, HalfFloatSliceExt};
    use crate::{bf16, f16};

    #[test]
    fn test_slice_conversions_f16() {
        let bits = &[
            f16::E.to_bits(),
            f16::PI.to_bits(),
            f16::EPSILON.to_bits(),
            f16::FRAC_1_SQRT_2.to_bits(),
        ];
        let numbers = &[f16::E, f16::PI, f16::EPSILON, f16::FRAC_1_SQRT_2];

        // Convert from bits to numbers
        let from_bits = bits.reinterpret_cast::<f16>();
        assert_eq!(from_bits, numbers);

        // Convert from numbers back to bits
        let to_bits = from_bits.reinterpret_cast();
        assert_eq!(to_bits, bits);
    }

    #[test]
    fn test_mutablility_f16() {
        let mut bits_array = [f16::PI.to_bits()];
        let bits = &mut bits_array[..];

        {
            // would not compile without these braces
            let numbers = bits.reinterpret_cast_mut();
            numbers[0] = f16::E;
        }

        assert_eq!(bits, &[f16::E.to_bits()]);

        bits[0] = f16::LN_2.to_bits();
        assert_eq!(bits, &[f16::LN_2.to_bits()]);
    }

    #[test]
    fn test_slice_conversions_bf16() {
        let bits = &[
            bf16::E.to_bits(),
            bf16::PI.to_bits(),
            bf16::EPSILON.to_bits(),
            bf16::FRAC_1_SQRT_2.to_bits(),
        ];
        let numbers = &[bf16::E, bf16::PI, bf16::EPSILON, bf16::FRAC_1_SQRT_2];

        // Convert from bits to numbers
        let from_bits = bits.reinterpret_cast::<bf16>();
        assert_eq!(from_bits, numbers);

        // Convert from numbers back to bits
        let to_bits = from_bits.reinterpret_cast();
        assert_eq!(to_bits, bits);
    }

    #[test]
    fn test_mutablility_bf16() {
        let mut bits_array = [bf16::PI.to_bits()];
        let bits = &mut bits_array[..];

        {
            // would not compile without these braces
            let numbers = bits.reinterpret_cast_mut();
            numbers[0] = bf16::E;
        }

        assert_eq!(bits, &[bf16::E.to_bits()]);

        bits[0] = bf16::LN_2.to_bits();
        assert_eq!(bits, &[bf16::LN_2.to_bits()]);
    }

    #[test]
    fn slice_convert_f16_f32() {
        // Exact chunks
        let vf32 = [1., 2., 3., 4., 5., 6., 7., 8.];
        let vf16 = [
            f16::from_f32(1.),
            f16::from_f32(2.),
            f16::from_f32(3.),
            f16::from_f32(4.),
            f16::from_f32(5.),
            f16::from_f32(6.),
            f16::from_f32(7.),
            f16::from_f32(8.),
        ];
        let mut buf32 = vf32;
        let mut buf16 = vf16;

        vf16.convert_to_f32_slice(&mut buf32);
        assert_eq!(&vf32, &buf32);

        buf16.convert_from_f32_slice(&vf32);
        assert_eq!(&vf16, &buf16);

        // Partial with chunks
        let vf32 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
        let vf16 = [
            f16::from_f32(1.),
            f16::from_f32(2.),
            f16::from_f32(3.),
            f16::from_f32(4.),
            f16::from_f32(5.),
            f16::from_f32(6.),
            f16::from_f32(7.),
            f16::from_f32(8.),
            f16::from_f32(9.),
        ];
        let mut buf32 = vf32;
        let mut buf16 = vf16;

        vf16.convert_to_f32_slice(&mut buf32);
        assert_eq!(&vf32, &buf32);

        buf16.convert_from_f32_slice(&vf32);
        assert_eq!(&vf16, &buf16);

        // Partial with chunks
        let vf32 = [1., 2.];
        let vf16 = [f16::from_f32(1.), f16::from_f32(2.)];
        let mut buf32 = vf32;
        let mut buf16 = vf16;

        vf16.convert_to_f32_slice(&mut buf32);
        assert_eq!(&vf32, &buf32);

        buf16.convert_from_f32_slice(&vf32);
        assert_eq!(&vf16, &buf16);
    }

    #[test]
    fn slice_convert_bf16_f32() {
        // Exact chunks
        let vf32 = [1., 2., 3., 4., 5., 6., 7., 8.];
        let vf16 = [
            bf16::from_f32(1.),
            bf16::from_f32(2.),
            bf16::from_f32(3.),
            bf16::from_f32(4.),
            bf16::from_f32(5.),
            bf16::from_f32(6.),
            bf16::from_f32(7.),
            bf16::from_f32(8.),
        ];
        let mut buf32 = vf32;
        let mut buf16 = vf16;

        vf16.convert_to_f32_slice(&mut buf32);
        assert_eq!(&vf32, &buf32);

        buf16.convert_from_f32_slice(&vf32);
        assert_eq!(&vf16, &buf16);

        // Partial with chunks
        let vf32 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
        let vf16 = [
            bf16::from_f32(1.),
            bf16::from_f32(2.),
            bf16::from_f32(3.),
            bf16::from_f32(4.),
            bf16::from_f32(5.),
            bf16::from_f32(6.),
            bf16::from_f32(7.),
            bf16::from_f32(8.),
            bf16::from_f32(9.),
        ];
        let mut buf32 = vf32;
        let mut buf16 = vf16;

        vf16.convert_to_f32_slice(&mut buf32);
        assert_eq!(&vf32, &buf32);

        buf16.convert_from_f32_slice(&vf32);
        assert_eq!(&vf16, &buf16);

        // Partial with chunks
        let vf32 = [1., 2.];
        let vf16 = [bf16::from_f32(1.), bf16::from_f32(2.)];
        let mut buf32 = vf32;
        let mut buf16 = vf16;

        vf16.convert_to_f32_slice(&mut buf32);
        assert_eq!(&vf32, &buf32);

        buf16.convert_from_f32_slice(&vf32);
        assert_eq!(&vf16, &buf16);
    }

    #[test]
    fn slice_convert_f16_f64() {
        // Exact chunks
        let vf64 = [1., 2., 3., 4., 5., 6., 7., 8.];
        let vf16 = [
            f16::from_f64(1.),
            f16::from_f64(2.),
            f16::from_f64(3.),
            f16::from_f64(4.),
            f16::from_f64(5.),
            f16::from_f64(6.),
            f16::from_f64(7.),
            f16::from_f64(8.),
        ];
        let mut buf64 = vf64;
        let mut buf16 = vf16;

        vf16.convert_to_f64_slice(&mut buf64);
        assert_eq!(&vf64, &buf64);

        buf16.convert_from_f64_slice(&vf64);
        assert_eq!(&vf16, &buf16);

        // Partial with chunks
        let vf64 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
        let vf16 = [
            f16::from_f64(1.),
            f16::from_f64(2.),
            f16::from_f64(3.),
            f16::from_f64(4.),
            f16::from_f64(5.),
            f16::from_f64(6.),
            f16::from_f64(7.),
            f16::from_f64(8.),
            f16::from_f64(9.),
        ];
        let mut buf64 = vf64;
        let mut buf16 = vf16;

        vf16.convert_to_f64_slice(&mut buf64);
        assert_eq!(&vf64, &buf64);

        buf16.convert_from_f64_slice(&vf64);
        assert_eq!(&vf16, &buf16);

        // Partial with chunks
        let vf64 = [1., 2.];
        let vf16 = [f16::from_f64(1.), f16::from_f64(2.)];
        let mut buf64 = vf64;
        let mut buf16 = vf16;

        vf16.convert_to_f64_slice(&mut buf64);
        assert_eq!(&vf64, &buf64);

        buf16.convert_from_f64_slice(&vf64);
        assert_eq!(&vf16, &buf16);
    }

    #[test]
    fn slice_convert_bf16_f64() {
        // Exact chunks
        let vf64 = [1., 2., 3., 4., 5., 6., 7., 8.];
        let vf16 = [
            bf16::from_f64(1.),
            bf16::from_f64(2.),
            bf16::from_f64(3.),
            bf16::from_f64(4.),
            bf16::from_f64(5.),
            bf16::from_f64(6.),
            bf16::from_f64(7.),
            bf16::from_f64(8.),
        ];
        let mut buf64 = vf64;
        let mut buf16 = vf16;

        vf16.convert_to_f64_slice(&mut buf64);
        assert_eq!(&vf64, &buf64);

        buf16.convert_from_f64_slice(&vf64);
        assert_eq!(&vf16, &buf16);

        // Partial with chunks
        let vf64 = [1., 2., 3., 4., 5., 6., 7., 8., 9.];
        let vf16 = [
            bf16::from_f64(1.),
            bf16::from_f64(2.),
            bf16::from_f64(3.),
            bf16::from_f64(4.),
            bf16::from_f64(5.),
            bf16::from_f64(6.),
            bf16::from_f64(7.),
            bf16::from_f64(8.),
            bf16::from_f64(9.),
        ];
        let mut buf64 = vf64;
        let mut buf16 = vf16;

        vf16.convert_to_f64_slice(&mut buf64);
        assert_eq!(&vf64, &buf64);

        buf16.convert_from_f64_slice(&vf64);
        assert_eq!(&vf16, &buf16);

        // Partial with chunks
        let vf64 = [1., 2.];
        let vf16 = [bf16::from_f64(1.), bf16::from_f64(2.)];
        let mut buf64 = vf64;
        let mut buf16 = vf16;

        vf16.convert_to_f64_slice(&mut buf64);
        assert_eq!(&vf64, &buf64);

        buf16.convert_from_f64_slice(&vf64);
        assert_eq!(&vf16, &buf16);
    }

    #[test]
    #[should_panic]
    fn convert_from_f32_slice_len_mismatch_panics() {
        let mut slice1 = [f16::ZERO; 3];
        let slice2 = [0f32; 4];
        slice1.convert_from_f32_slice(&slice2);
    }

    #[test]
    #[should_panic]
    fn convert_from_f64_slice_len_mismatch_panics() {
        let mut slice1 = [f16::ZERO; 3];
        let slice2 = [0f64; 4];
        slice1.convert_from_f64_slice(&slice2);
    }

    #[test]
    #[should_panic]
    fn convert_to_f32_slice_len_mismatch_panics() {
        let slice1 = [f16::ZERO; 3];
        let mut slice2 = [0f32; 4];
        slice1.convert_to_f32_slice(&mut slice2);
    }

    #[test]
    #[should_panic]
    fn convert_to_f64_slice_len_mismatch_panics() {
        let slice1 = [f16::ZERO; 3];
        let mut slice2 = [0f64; 4];
        slice1.convert_to_f64_slice(&mut slice2);
    }
}

[ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge