Expand description
Convert floating point values to integer types faster than the standard as
operator.
The standard way of converting floating point values to integers is with the as
operator. This conversion has various guarantees as listed in the reference. One of them is that it saturates: Input values out of range of the output type convert to the minimal/maximal value of the output type.
assert_eq!(300f32 as u8, 255);
assert_eq!(-5f32 as u8, 0);
This contrasts C/C++, where this kind of cast is undefined behavior. Saturation comes with a downside. It is slower than the C/C++ version. On many hardware targets a float to integer conversion can be done in one instruction. For example CVTTSS2SI
on x86_84+SSE. Rust has to do more work than this, because the instruction does not provide saturation.
Sometimes you want faster conversions and don’t need saturation. This is what this crate provides. The behavior of the conversion functions in this crate depends on whether the input value is in range of the output type. If in range, then the conversion functions work like the standard as
operator conversion. If not in range (including NaN), then you get an unspecified value.
You never get undefined behavior but you can get unspecified behavior. In the unspecified case, you get an arbitrary value. The function returns and you get a valid value of the output type, but there is no guarantee what that value is.
This crate picks an implementation automatically at compile time based on the target and features. If there is no specialized implementation, then this crate picks the standard as
operator conversion. This crate has optimized implementations on the following targets:
target_arch = "x86_64", target_feature = "sse"
: all conversions except 128 bit integerstarget_arch = "x86", target_feature = "sse"
: all conversions except 64 bit and 128 bit integers
§Assembly comparison
The repository contains generated assembly for every conversion and target. Here are some typical examples on x86_64+SSE.
standard:
f32_to_i64:
cvttss2si rax, xmm0
ucomiss xmm0, dword ptr [rip + .L_0]
movabs rcx, 9223372036854775807
cmovbe rcx, rax
xor eax, eax
ucomiss xmm0, xmm0
cmovnp rax, rcx
ret
fast:
f32_to_i64:
cvttss2si rax, xmm0
ret
standard:
f32_to_u64:
cvttss2si rax, xmm0
mov rcx, rax
sar rcx, 63
movaps xmm1, xmm0
subss xmm1, dword ptr [rip + .L_0]
cvttss2si rdx, xmm1
and rdx, rcx
or rdx, rax
xor ecx, ecx
xorps xmm1, xmm1
ucomiss xmm0, xmm1
cmovae rcx, rdx
ucomiss xmm0, dword ptr [rip + .L_1]
mov rax, -1
cmovbe rax, rcx
ret
fast:
f32_to_u64:
cvttss2si rcx, xmm0
addss xmm0, dword ptr [rip + .L_0]
cvttss2si rdx, xmm0
mov rax, rcx
sar rax, 63
and rax, rdx
or rax, rcx
ret
Functions§
- f32_
to_ i8 - Convert the input floating point value to the output integer type.
- f32_
to_ i16 - Convert the input floating point value to the output integer type.
- f32_
to_ i32 - Convert the input floating point value to the output integer type.
- f32_
to_ i64 - Convert the input floating point value to the output integer type.
- f32_
to_ i128 - Convert the input floating point value to the output integer type.
- f32_
to_ u8 - Convert the input floating point value to the output integer type.
- f32_
to_ u16 - Convert the input floating point value to the output integer type.
- f32_
to_ u32 - Convert the input floating point value to the output integer type.
- f32_
to_ u64 - Convert the input floating point value to the output integer type.
- f32_
to_ u128 - Convert the input floating point value to the output integer type.
- f64_
to_ i8 - Convert the input floating point value to the output integer type.
- f64_
to_ i16 - Convert the input floating point value to the output integer type.
- f64_
to_ i32 - Convert the input floating point value to the output integer type.
- f64_
to_ i64 - Convert the input floating point value to the output integer type.
- f64_
to_ i128 - Convert the input floating point value to the output integer type.
- f64_
to_ u8 - Convert the input floating point value to the output integer type.
- f64_
to_ u16 - Convert the input floating point value to the output integer type.
- f64_
to_ u32 - Convert the input floating point value to the output integer type.
- f64_
to_ u64 - Convert the input floating point value to the output integer type.
- f64_
to_ u128 - Convert the input floating point value to the output integer type.