Giter Site home page Giter Site logo

starkat99 / half-rs Goto Github PK

View Code? Open in Web Editor NEW
226.0 12.0 49.0 573 KB

Half-precision floating point types f16 and bf16 for Rust.

Home Page: https://docs.rs/half/

License: Other

Rust 100.00%
rust floating-point crates f16 bfloat16 ieee754 float16 binary16 rust-embedded

half-rs's People

Contributors

bzm3r avatar cameron1024 avatar charles-r-earp avatar coreylowman avatar eiz avatar encounter avatar fogti avatar gyunghee-park avatar jfrimmel avatar johannesvollmer avatar joseluis avatar kali avatar klosspeter avatar ma2bd avatar noratrieb avatar pseitz avatar pthariensflame avatar samcrow avatar shnatsel avatar starkat99 avatar sylvestre avatar tspiteri avatar wazed-matthis avatar wx-csy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

half-rs's Issues

Improve CI solution for other architectures

See if there's a Github action runner host that can do AArch64 images, would speed up CI immensely by avoiding running on QEMU. Compile times are just atrocious, even for small crate like this. Or find some other solution for testing AArch64.

Convert an u16 array to f16 array

I am currently implementing a popular file format in Rust which stores binary f16 arrays. As byteorder does not support f16, I need to read these f16 arrays as u16 arrays and then convert them to f16, in order to correctly handle endianness.

I wondered if there could be some functionality in this library, which prevents users to just do array.iter().map(|u| f16::from_bits(u)).collect::<Vec<f16>>(). This code iterates the whole array and allocates a new vector, but (I assume that) in memory, not a single bit is changed. All it probably does is basically copying the contents of the array element by element. But all it needs to do is really just interpreting the bits in a different way by representing it with a different type at compile time.

Is it maybe possible to reinterpret an array of u16 as an array of f16 by simply unsafely casting the raw pointers?

If not, certainly it's possible to provide an F16Slice <'a> (&'a [u16]) which maybe even implements ::std::ops::Index with f16::from_bits(self.0[index]), or something similar.

On the other hand, I can imagine that my use case is rather rare and not many people need to convert between large arrays of u16 and f16. Anyways, what do you think of that?

Also, Please correct me if I have overlooked something.

Debug for f16 and bf16 should convert to f32, like Display

Debug is used more than Display since it can be derived, and is also used for containers. The interior u16 is an implementation detail, and almost certainly the user wants to see the numerical value not the bit value when using Debug, for example when working with vecs or arrays. Assertions, errors, all work with Debug, and this makes those unreadable.

lossless `TryFrom<f{32,64}>` implementations for `f16` and `bf16`

Would it be possible to introduce lossless TryFrom implementations for bf16 and f16 types from Rust primitive f32 and f64 types so that for example f16::try_from(value).map(f16::to_f32) is either Err or Ok(value2) with value == value2 for all possible values?

This means that if TryFrom is Ok the conversion was lossless and it is possible to fully recover the f32 or f64 value later on if no mutations happen in between. If TryFrom yields Err then it is not possible to losslessly convert the particular f32 or f64 value. No rounding shall take place.

I actually need this if this can be implemented efficiently. :)

Implement rand_distr::SampleUniform for f16

We would like to use f16 in dfdx, a deep learning library. It would be very convenient if this crate implemented rand_distr::SampleUniform for f16.

Relevant issue in dfdx: coreylowman/dfdx#423

The trait would allow us to sample a random f16 from a uniform distribution. This seems like a generally useful feature, perhaps behind a feature gate. Other alternatives exist from our side, but they make the implementation more annoying.

I would be willing to implement this feature if a maintainer agrees that it is a good idea. Closing this issue is also a completely valid response if you believe that this trait implementation does not belong in this crate.

How do you cast into f16?

How do you cast a f32 variable into a f16 variable?

	use half::f16;
	use num::traits::FromPrimitive;
	use half::*;
	use half;
	
	let a: f16 = (0.2f32).into();

	println!("a {}",a);

| let a: f16 = (0.2f32).into();
| ^^^^^^^^ ---- required by a bound introduced by this call
| |
| the trait From<f32> is not implemented for f16
|
= help: the following other types implement trait From<T>:
<f16 as From>
<f16 as From>
= note: required for f32 to implement Into<f16>

Deprecation Note Markdown not working

When I tried to run an old project, I received a deprecation message.

warning: use of deprecated item 'half::vec::from_bits': use [`HalfBitsVecExt::reinterpret_into`](trait.HalfBitsVecExt.html#tymethod.reinterpret_into) instead
   --> src\file\io.rs:344:12
    |
344 |         Ok(::half::vec::from_bits(data))
    |

Looks like markdown source code. Could it be possible that the deprecation note does not support markdown?

Version 2.3.0 - CI breaks

Hi there,

It seems that the arrow crate depends on half.

├── arrow v42.0.0
│   ├── ahash v0.8.3
│   │   ├── cfg-if v1.0.0
│   │   ├── getrandom v0.2.10
│   │   │   ├── cfg-if v1.0.0
│   │   │   └── libc v0.2.146
│   │   └── once_cell v1.18.0
│   │   [build-dependencies]
│   │   └── version_check v0.9.4
│   ├── arrow-arith v42.0.0
│   │   ├── arrow-array v42.0.0
│   │   │   ├── ahash v0.8.3 (*)
│   │   │   ├── arrow-buffer v42.0.0
│   │   │   │   ├── half v2.2.1
(...)

With the version 2.3.0, the CI on my project seems to break: https://github.com/nyx-space/nyx/actions/runs/5370402979/jobs/9742460842 .

   Compiling half v2.3.0
error[E0425]: cannot find function `_mm_cvtps_ph` in this scope
  --> /root/.cargo/registry/src/index.crates.io-1cd66030c949c28d/half-2.3.0/src/binary16/arch/x86.rs:32:18
   |
32 |     let retval = _mm_cvtps_ph(vec.assume_init(), _MM_FROUND_TO_NEAREST_INT);
   |                  ^^^^^^^^^^^^
  --> /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/../../stdarch/crates/core_arch/src/x86/f16c.rs:33:1
   |
   = note: similarly named function `_mm_cvtph_ps` defined here
   |
help: a function with a similar name exists
   |
32 |     let retval = _mm_cvtph_ps(vec.assume_init(), _MM_FROUND_TO_NEAREST_INT);
   |                  ~~~~~~~~~~~~
help: consider importing this function
   |
1  + use core::arch::x86::_mm_cvtps_ph;
   |

error[E0425]: cannot find function `_mm_cvtps_ph` in this scope
  --> /root/.cargo/registry/src/index.crates.io-1cd66030c949c28d/half-2.3.0/src/binary16/arch/x86.rs:50:18
   |
50 |     let retval = _mm_cvtps_ph(vec.assume_init(), _MM_FROUND_TO_NEAREST_INT);
   |                  ^^^^^^^^^^^^
  --> /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/../../stdarch/crates/core_arch/src/x86/f16c.rs:33:1
   |
   = note: similarly named function `_mm_cvtph_ps` defined here
   |
help: a function with a similar name exists
   |
50 |     let retval = _mm_cvtph_ps(vec.assume_init(), _MM_FROUND_TO_NEAREST_INT);
   |                  ~~~~~~~~~~~~
help: consider importing this function
   |
1  + use core::arch::x86::_mm_cvtps_ph;
   |

For more information about this error, try `rustc --explain E0425`.

Any idea if there is something I can do to fix this or do I need to wait until arrow fixes something on their end ? Or do you think this could be Github CI being slow at updating all of its dependencies ? (I suspect the latter is possible since another workflow seems to build).

Thanks

Requiring Rust 1.70.0 and changing backwards compatibility policy in a minor version bump seems a mistake

Two points of data from the Changelog:

Breaking Change Minimum supported Rust version is now 1.70.

and

Breaking Change Minimum supported Rust version policy reverted to original policy of allowing minimum supported Rust version updates for minor releases instead of only major to avoid segmentation and allow optimizing hardware implementations without unnecessary major releases.

Look, I can understand that this crate is probably depended upon by projects that have some anxiety about actually following semver to the letter, even if cargo is going to complain as-such if you don't. However, this change presents the following problem:

  1. Downstream crates that use this package now need to force all downstream consumers to use your specified rust version even though they didn't opt into the new version bump, because cargo by default uses ^MAJOR.MINOR.PATCH instead of =MAJOR.MINOR.PATCH (assuming one just writes e.g. 2.2.0 that actually means ^2.2.0 instead of =2.2.0.
  2. As a result, everything up the stack ends up inheriting this issue. The image crate for example uses exr with the following dependency on 0.24.6: https://github.com/image-rs/image/blob/v0.24.6/Cargo.toml#L47C10-L47C10. The latest version of exr (untagged) uses ^2.1.0 https://github.com/johannesvollmer/exrs/blob/master/Cargo.toml#L31.
  3. As a result, old versions of the exr and image crate which used to work now don't. You've broken your stated policy without a new major release, so if you're one of these crate maintainers, you have no way of knowing that a minor version bump is now imposing a rusc1.70.0 dependency across the board for both previously released versions and currently released versions.

The first point above (requiring 1.70.0) isn't necessarily a problem. It's not even a problem for your project to make a requirement that a minor version bump may impose a new minimum version requirement. What is a problem is that you changed that policy (where previously maintainers would expect to see a major version bump if there's a new min-req) with a minor version bump, which negates the whole point of the thing.

My organization is wasting time on this at a higher level by using the image crate. This isn't their fault, and it is something we can work around because we're able to relatively easily upgrade to a newer rustc. But it's completely unexpected and you're breaking every downstream crate by not making that policy explicit to crate maintainers who can opt into it (e.g. the maintainer of the exr crate, @johannesvollmer).

Can you please yank 2.3.0 and 2.3.1 and please focus on a 3.0 release with this breaking change for the future? This is only going to cause more chaos as people start to update and time goes on...

rkyv support?

I'm using rkyv for a project and it's quite helpful. I'd like to add optional support for it here as I'd like to have the space savings of half in my archived types. With the use of zerocopy it should be quite straight forward.

Support approximate comparisons using the `approx` crate

There are many situations when an approximate comparison is useful for floats. The approx crate appears to the the de-facto standard crate supporting standard approximate comparisons, so implementing the traits for f16 as an optional feature could be a useful addition.

Allow rounding mode selection?

Allow selecting how to round when converting down to f16. Note that while x86 F16C hardware allows selecting rounding mode, ARM in particular does not, so keeping consistent across implementation may be an issue (current defaults on supported hardware/software are consistent for the moment, though adding ARM and other hardware later may not be consistent). Will be a bit tricky to get the interface right.

Preserve the sign of NaNs when converted to f32?

Hello,

I noticed that the sign of f32 NaNs are preserved when they are converted to f64 as indicated by this experiment: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=b23459b96256c673aa6d84ed79a10f50.

But it appears f16 NaNs do not have this behavior. For example, the second assertion fails.

extern crate half;

use half::*;

fn main() {
    let x = f16::from_bits(64513);
    let y = x.to_f32();
    assert!(x.is_sign_negative());
    println!("{}", y);
    assert!(y.is_sign_negative());
}

I couldn't find any useful information about whether the standard specifies this. So I'm not sure if f16 should be consistent with f32 with respect to this behavior.

Inconsistent rounding when converting from f32

Hello,

I found that some f32 values are converted differently depending on whether use-intrinsics is enabled or not. I am using the 1.3.0 release version.

For example:

use half::f16;

let f = 2.9802322e-8f32;
let f2 = f16::from_f32(f);
println!("{}", f2);

prints 0 when intrinsics are enabled and 0.000000059604645 when intrinsics are not enabled.

I also found an example that is potentially a rounding direction mismatch:

use half::f16;

let f = 520.25f32;
let f2 = f16::from_f32(f);
println!("{}", f2);

prints 520 when intrinsics are enabled and 520.5 when not enabled.

Add vector arithmetic operations

Add vector arithmetic operations on slices/arrays of f16, that can utilize SIMD hardware when available, like is already done for conversions.

Fall back on C implementation of operators

In sonos/tract#916 I've been investigating fp16 math support with ARM hardware that supports it, and while it's not ready for a PR yet, I think that what I've found so far is promising.

By having a C file with simple functions like:

void add_f16(_Float16 *c, const _Float16 *a, const _Float16 *b) { *c = *a + *b; }

for add/sub/mul/div, and using them when a target arch or target feature is available (fp16 or fp16fhm?) would allow for significantly better performance in applications relying on the half crate (no need to convert constantly from f32 to f16).

When combined with LTO, it's possible to create applications and static libraries that properly embed and optimize these core operators, allowing for significant performance improvement on platforms that have hardware support!

The main problem is that not every toolchain supports _Float16, and so I'm worried that a combination of 'target supports fp16' + 'compiler does not support _Float16' will be true...

This would also add a dependency on the cc crate.

Introducing a breaking change "policy" on a minor version is problematic

To be clear: While I think the purported value in allowing breaking changes vis-a-vis changing the MSRV in a minor version is debatable, this issue isn't about the policy itself, but rather how it was introduced.

Prior to 2.3.0, there was no indication that this crate would not adhere to SemVer, which in the Rust ecosystem is therefore tantamount to implicitly doing so. Therefore downstream crates with their own MSRVs can - and in at least 1 instance have - reasonably assumed they could depend on any 2.x version of half. This is in fact the default behavior in Cargo if the version is specified as either 2.2 or 2.2.0, for instance, as the resolver allows the rightmost non-zero version to change with new releases.

The fixed crate is one example, with an explicit MSRV of 1.67, fully compatible with this crate's own MSRV of 1.58 up until 2.3. My own crate fast_poisson, which also has an MSRV of 1.67, unexpectedly broke in CI this week, as it (indirectly) depends on fixed which in turn depends on half at version >= 1.8, < 3.0 - fixed quite reasonably assumed this crate, saying nothing to the contrary, would follow SemVer.

I'm sure crates other than these two have had their MSRVs broken by half suddenly introducing this policy of breaking changes in minor versions. Whether or not the policy itself is good, introducing it in a minor version is not, as the policy itself is a breaking change in its own right. I believe that the 2.3.x versions should be yanked and republished as 3.0, and the policy made explicit in the README (currently it exists nowhere I can see but in the 2.3.0 release notes) so that future users can be forewarned that this crate may not adhere to SemVer in future minor versions. Alternatively, a new 2.4.0 version that reverts the changes necessitating the MSRV bump could supersede the 2.3.x, with a 3.0 version re-introducing those changes and bump and explicitly publishing the policy.

Not able to build using rust 1.26

On rust version 1.26 I get the following error. When I updated to Rust 1.27 the error went away.

error[E0599]: no function or associated item named from_bits found for type f64 in the current scope
--> /Users/joshuabatty/.cargo/registry/src/github.com-1ecc6299db9ec823/half-1.1.1/src/lib.rs:808:9
|
808 | f64::from_bits(sign | exp | man)
| ^^^^^^^^^^^^^^ function or associated item not found in f64
|
= help: items from traits can only be used if the trait is in scope
= note: the following trait is implemented but not in scope, perhaps add a use for it:
candidate #1: use core::num::Float;

f16 serialization

Hi. I'm trying to serialize f16, but I'm stuck on it.
I'm using serde feature, but when I use f16_var.serialize(serializer) I'm getting unexpected results.

Example:
Value: 1.0
Serialization result: "15360"`

If I convert the value to f32 and serialize it, everything is fine, I will get "1.0"` as expected.

Running on Ubuntu 20 under WSL

Illegal instruction on Android Virtual Device running on Github Action Runner

Hello,

im working on an issue in the Android/Termux CI from uutils project.
The issue: It's currently only reproducable in our CI.
On my private PC I can't reproduce the issue.

After adding more logs and several CI test-runs, I managed to trace it down to the half-rs crate:

#[test]
fn test_f16c_f16_to_f32_direct() {
    let bo = ::od::byteorder_io::ByteOrder::Little;
    let bits = bo.read_u16(&[0x00, 0x3c]);

    let result_f16 = half::f16::from_bits(bits);
    let result = f64::from(result_f16); // crashes here
    assert_eq!(1.0, result);
}

The function in half-rs responsible for converting f16 to f64 is this:

#[inline]
pub(crate) fn f16_to_f64(i: u16) -> f64 {
    convert_fn! {
        if x86_feature("f16c") {
            unsafe { x86::f16_to_f32_x86_f16c(i) as f64 }   // crashes here
        } else if aarch64_feature("fp16") {
            unsafe { aarch64::f16_to_f64_fp16(i) }
        } else {
            f16_to_f64_fallback(i)
        }
    }
}

I tried to trace it down even further, by extracting relevant code into a own test.
This test fails with SIG 4. Which is "illegal instruction".

#[test]
fn test_f16c_direct() {

    #[cfg(target_arch = "x86_64")]
    use std::arch::x86_64::{_mm_cvtph_ps, __m128i, __m128};
    #[cfg(target_arch = "x86")]
    use std::arch::x86::{_mm_cvtph_ps, __m128i, __m128};

    let i = 0u16;

    let result: f32 = unsafe {
        let mut vec = std::mem::MaybeUninit::<__m128i>::zeroed();
        vec.as_mut_ptr().cast::<u16>().write(i);
        let retval = _mm_cvtph_ps(vec.assume_init());
        *(&retval as *const __m128).cast()
    };

    assert_eq!(0.0, result);
}

#[test]
fn test_if_f16c_is_detected() {

    let detected = std::is_x86_feature_detected!("f16c");
    if detected {
        println!("f16c detected!");
    } else {
        println!("f16c not detected!");
    }

    assert_eq!(true, detected);
}

According to the last test (test_if_f16c_is_detected) f16c is supportted.
Also the /proc/cpuinfo states that f16c is supported.
I can't explain why its crashing then.

I have the feeling that its really a bug in the android emulator.
It states that the f16c is supported, but actually fails to execute it.

Do you have experience with such kind of error?
What can I do ro reproduce it locally?
Is it related to the actual CPU? The GitHub action runner has a AMD EPYC 7763 64-Core Processor.
My machine has Intel I7.
Is the github runner running in a own VM and can the setup of VM in VM cause this issue?
We are using the reactivecircus/android-emulator-runner for creating the android virtual device.

Any hints or clues?
Is there an other way to test if the f16c instruction set is supported?
Such that we can create an error report for google?

need impl num_traits::ApproxEq for half data type

so that we can compare by using the num_traits::assert_approx_eq macro

assert_approx_eq!(half::f16, self.test_atomic_add_result(input), out);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ApproxEq` is not implemented for `f16`

BUG: upgrade from 2.3.1 to 2.4.0 breaks no_std build

We use half lib extensively in our Burn project and we have a git action to build for no_std which is failing when upgrading from 2.3.1 to 2.4.0.

I recommend CI step is added specifically to test std feature off (no_std testing) because a similar problem occurred in the past (see #84).

See errors:

Compiling bincode v2.0.0-rc.3
  error: cannot find macro `vec` in this scope
     --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/half-2.4.0/src/slice.rs:368:23
      |
  368 |         let mut vec = vec![0f32; self.len()];
      |                       ^^^
      |
  help: consider importing this macro
      |
  10  + use alloc::vec;
      |
  
  error: cannot find macro `vec` in this scope
     --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/half-2.4.0/src/slice.rs:377:23
      |
  377 |         let mut vec = vec![0f64; self.len()];
      |                       ^^^
      |
  help: consider importing this macro
      |
  10  + use alloc::vec;
      |
  
  error: cannot find macro `vec` in this scope
     --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/half-2.4.0/src/slice.rs:462:23
      |
  462 |         let mut vec = vec![0f32; self.len()];
      |                       ^^^
      |
  help: consider importing this macro
      |
  10  + use alloc::vec;
      |
  
  error: cannot find macro `vec` in this scope
     --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/half-2.4.0/src/slice.rs:471:23
      |
  471 |         let mut vec = vec![0f64; self.len()];
      |                       ^^^
      |
  help: consider importing this macro
      |
  10  + use alloc::vec;
      |
  
  error: cannot find macro `vec` in this scope
     --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/half-2.4.0/src/vec.rs:139:23
      |
  139 |         let mut vec = vec![f16::from_bits(0); slice.len()];
      |                       ^^^
      |
  help: consider importing this macro
      |
  12  + use alloc::vec;
      |
  
  error: cannot find macro `vec` in this scope
     --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/half-2.4.0/src/vec.rs:146:23
      |
  146 |         let mut vec = vec![f16::from_bits(0); slice.len()];
      |                       ^^^
      |
  help: consider importing this macro
      |
  12  + use alloc::vec;
      |
  
  error: cannot find macro `vec` in this scope
     --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/half-2.4.0/src/vec.rs:[175](https://github.com/tracel-ai/burn/actions/runs/8042757366/job/21963835704?pr=1364#step:11:178):23
      |
  175 |         let mut vec = vec![bf16::from_bits(0); slice.len()];
      |                       ^^^
      |
  help: consider importing this macro
      |
  12  + use alloc::vec;
      |
  
  error: cannot find macro `vec` in this scope
     --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/half-2.4.0/src/vec.rs:[182](https://github.com/tracel-ai/burn/actions/runs/8042757366/job/21963835704?pr=1364#step:11:185):23
      |
  182 |         let mut vec = vec![bf16::from_bits(0); slice.len()];
      |                       ^^^
      |
  help: consider importing this macro
      |
  12  + use alloc::vec;
      |

Mutable Slice Conversion

In my last pull request I blindly stated that conversion of mutable slices could not be implemented because I thought it would violate mutability rules.

As it turns out, the borrow checker is really smart, and it is indeed possible to reinterpret mutable slices without incorrect behaviour. I need this functionality for efficient binary deserialization of f16 numbers.

I have implemented from_bits_mut and to_bits_mut in f16::slice in my fork. I'd like to send a pull request, if you approve.

test failures with Rust 1.75+ when running in `--release` mode

We're running the half crate's tests during our package builds in Fedora Linux and our CI has detected that since the update to Rust 1.75.0, some tests have started to fail - but only when run in --release mode:

failures:
---- bfloat::test::test_nan_conversion_to_larger stdout ----
thread 'bfloat::test::test_nan_conversion_to_larger' panicked at src/bfloat.rs:1531:9:
assertion failed: neg_nan64_from_32.is_nan() && neg_nan64_from_32.is_sign_negative()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
---- bfloat::test::test_nan_conversion_to_smaller stdout ----
thread 'bfloat::test::test_nan_conversion_to_smaller' panicked at src/bfloat.rs:1502:9:
assertion failed: neg_nan32_from_64.is_nan() && neg_nan32_from_64.is_sign_negative()
---- binary16::test::test_nan_conversion_to_larger stdout ----
thread 'binary16::test::test_nan_conversion_to_larger' panicked at src/binary16.rs:1599:9:
assertion failed: neg_nan64_from_32.is_nan() && neg_nan64_from_32.is_sign_negative()
---- binary16::test::test_nan_conversion_to_smaller stdout ----
thread 'binary16::test::test_nan_conversion_to_smaller' panicked at src/binary16.rs:1570:9:
assertion failed: neg_nan32_from_64.is_nan() && neg_nan32_from_64.is_sign_negative()
failures:
    bfloat::test::test_nan_conversion_to_larger
    bfloat::test::test_nan_conversion_to_smaller
    binary16::test::test_nan_conversion_to_larger
    binary16::test::test_nan_conversion_to_smaller

Implements dtoa

Thanks for the library. Would you see it feasible to include an implementation of dtoa over a u8 mutable pointer?

support total ordering

Rust stabilized in 1.62 the total_cmp method that follows the totalOrder predicate from the IEEE754 spec (v2008, 5.10).

The same method could be added easily if it calculated the total order after converting to f32. There could also be total_cmp & total_cmp_const variants.

If bumping the MSRV to 1.62 is a problem, it'd be also very easy to reimplement it from scratch.

NaN behaviour of is_sign_positive and is_sign_negative is not like for primitive types

extern crate half;
use half::f16;
use std::f32;
use std::mem;
fn main() {
    let nan32 = f32::NAN;
    println!(
        "nan32.is_sign_positive() == nan32.is_sign_negative() -> {}",
        nan32.is_sign_positive() == nan32.is_sign_negative()
    );
    let unan32: u32 = unsafe { mem::transmute(nan32) };
    let negated32: f32 = unsafe { mem::transmute(unan32 ^ 0x8000_0000) };
    println!(
        "nan32.is_sign_positive() == negated32.is_sign_positive() -> {}",
        nan32.is_sign_positive() == negated32.is_sign_positive()
    );

    let nan16 = half::consts::NAN;
    println!(
        "nan16.is_sign_positive() == nan16.is_sign_negative() -> {}",
        nan16.is_sign_positive() == nan16.is_sign_negative()
    );
    let unan16: u16 = unsafe { mem::transmute(nan16) };
    let negated16: f16 = unsafe { mem::transmute(unan16 ^ 0x8000) };
    println!(
        "nan16.is_sign_positive() == negated16.is_sign_positive() -> {}",
        nan16.is_sign_positive() == negated16.is_sign_positive()
    );
}

Output:

nan32.is_sign_positive() == nan32.is_sign_negative() -> false
nan32.is_sign_positive() == negated32.is_sign_positive() -> false
nan16.is_sign_positive() == nan16.is_sign_negative() -> true
nan16.is_sign_positive() == negated16.is_sign_positive() -> true

Note that in Rust version 1.20.0, rust-lang/rust#42431, the behaviour of is_sign_positive and is_sign_negative for NaN was updated to conform to IEEE754.

comparison of +0 and -0 gives wrong result

extern crate half;
use half::f16;
fn main() {
    let plus32 = 0f32;
    let minus32 = -plus32;
    let plus16 = f16::from_f32(plus32);
    let minus16 = f16::from_f32(minus32);
    println!("plus32 == minus32 -> {}", plus32 == minus32);
    println!("plus16 == minus16 -> {}", plus16 == minus16);
    println!("plus32.partial_cmp(&minus32) -> {:?}", plus32.partial_cmp(&minus32));
    println!("plus16.partial_cmp(&minus16) -> {:?}", plus16.partial_cmp(&minus16));
}

Output:

plus32 == minus32 -> true
plus16 == minus16 -> false
plus32.partial_cmp(&minus32) -> Some(Equal)
plus16.partial_cmp(&minus16) -> Some(Less)

build fails when selecting serde feature but not std feature

Build fails with this dependency setting:

[dependencies.half]
version = "2"
default-features = false
features = ["serde"]

Adding the "std" feature makes the build work.

[dependencies.half]
version = "2"
default-features = false
features = ["serde", "std"]

converting from f64 nan produces infinity if only lower mantissa bits are nonzero

The f64 obtained from transmuting 0x7ff0_0000_0000_0001u64 is NaN, as it has all exponent bits set and has one bit set in the mantissa. The current conversion function from f64 always discards the least significant 32 bits, so it converts this into infinity instead of NaN.

Also, for both the f32 and f64 conversion functions, the sign of a converted NaN is independent of the source, unlike the primitive conversions where the sign bit is retained when converting say from an f64 NaN to an f32.

Run tests for i686 targets in CircleCI

Github Actions CI now runs i686 and aarch64 builds like it used to, but no tests are being run for i686. Use CircleCI to do this like is being done with aarch64.

Don't build with serde support and `no_std`

I'm not able to build half when I use it with no_std and serde support.

   Compiling half v2.2.1
error[E0599]: no method named `to_string` found for reference `&bf16` in the current scope
   --> /home/nathaniel/.cargo/registry/src/github.com-1ecc6299db9ec823/half-2.2.1/src/bfloat.rs:697:40
    |
697 |         serializer.serialize_str(&self.to_string())
    |                                        ^^^^^^^^^ method not found in `&bf16`
    |
    = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
1   | use crate::alloc::string::ToString;

I use the following configuration half = {version = "2", features = ["alloc", "num-traits", "serde"], default-features = false}

I believe the fix should be easy, since it's just a missing import with those specific feature flags.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.