-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add {f32,f64}::approx_unchecked_to<Int>
unsafe methods
#66841
Conversation
r? @KodrAus (rust_highfive has picked a reviewer for you, use r? to override) |
Regarding naming: we already have These new methods differ from those in that they round towards zero. However they are already different enough in their return type that perhaps documentation is enough and this different rounding behavior doesn’t need to be called out in the method name? |
28486c3
to
296dc11
Compare
r? @rkruppe |
src/libcore/num/f32.rs
Outdated
/// | ||
/// # Safety | ||
/// | ||
/// The value must be finite and fit in the return type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this could be elaborated upon what finite and fitting entails?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Finite is defined in the docs of the is_finite
method, but I can repeat in this comment.
As discussed in the PR description, “fit” is copied from https://llvm.org/docs/LangRef.html#fptoui-to-instruction and I couldn’t find anything more precise. I’d prefer to find out what LLVM does exactly rather than documenting suppositions as fact, but I’m not sure how.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re. finite, maybe link to is_finite
saying "as defined by is_finite
"?
Hopefully @rkruppe is more knowledgeable re. "fit".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bit of doc-comment is now “The value must be finite (not infinite or NaN
) and fit in the return type.” and I’ve added a (non-doc-) comment with a link to relevant LLVM docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's not spelled out in LLVM's LangRef, then my working knowledge of how the instruction works probably isn't worth much. There's dozens of places in LLVM that could deviate from the expected semantics (various IR passes and utilities, as well as the lowerings in the backends) and I do not know all of them.
The implementation looks good to me. Regarding naming: I don't think "round" is a good name. Not only do we already have APIs that use "round" in a different sense for the same pairs of types (even if the signatures are not literally identical because these new functions are generic), I would also never think to suspect that something named just "round" defaults to RTZ mode, even with the context of a float -> int signature. I don't love any of these but here are some alternatives that seem less misleading to me:
|
Presumably C11 standard https://port70.net/~nsz/c/c11/n1570.html#6.3.1.4
C++17 standard http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf#section.7.10
So “fit” is indeed after rounding/truncation. |
@rkruppe What do you think of just |
Seems fine to me. I assume we don't really have to worry about a future name collision with a hypothetical |
I’m considering whether the trait should be something like |
These methods could fit among other conversion methods: https://internals.rust-lang.org/t/pre-rfc-add-explicitly-named-numeric-conversion-apis/11395 |
{f32,f64}::round_unchecked_to<Int>
unsafe methods{f32,f64}::approx_unchecked_to<Int>
unsafe methods
I’ve renamed the methods to |
427ec1b
to
16a4fc3
Compare
I'm happy with the final diff but FWIW I also don't have any opinion on the API design aspects (e.g., the entirety of the The individual commits seem worth revising before merging, though:
|
As discussed in rust-lang#10184 Currently, casting a floating point number to an integer with `as` is Undefined Behavior if the value is out of range. `-Z saturating-float-casts` fixes this soundness hole by making `as` “saturate” to the maximum or minimum value of the integer type (or zero for `NaN`), but has measurable negative performance impact in some benchmarks. There is some consensus in that thread for enabling saturation by default anyway, but provide an `unsafe fn` alternative for users who know through some other mean that their values are in range.
This makes `libcore/num/mod.rs` slightly smaller. It’s still 4911 lines and not easy to navigate. This doesn’t change any public API.
37595ce
to
a213ff8
Compare
Squashed. Input from @rust-lang/libs about the API design is welcome here. This is all |
Yes, let's merge this and bikeshedding can happen on the tracking issues. @bors r+ |
📌 Commit a213ff8 has been approved by |
…, r=rkruppe Add `{f32,f64}::approx_unchecked_to<Int>` unsafe methods As discussed in rust-lang#10184 Currently, casting a floating point number to an integer with `as` is Undefined Behavior if the value is out of range. `-Z saturating-float-casts` fixes this soundness hole by making `as` “saturate” to the maximum or minimum value of the integer type (or zero for `NaN`), but has measurable negative performance impact in some benchmarks. There is some consensus in that thread for enabling saturation by default anyway, but provide an `unsafe fn` alternative for users who know through some other mean that their values are in range. <del>The “fit” wording is copied from https://llvm.org/docs/LangRef.html#fptoui-to-instruction, but I’m not certain what it means exactly. Presumably this is after rounding towards zero, and the doc-test with `i8::MIN` seems to confirm this.</del> Clang presumably uses those LLVM intrinsics to implement C and C++ casts, whose respective standard specify that the value *after truncating to keep its integral part* must be representable in the target type.
Rollup of 10 pull requests Successful merges: - #66606 (Add feature gate for mut refs in const fn) - #66841 (Add `{f32,f64}::approx_unchecked_to<Int>` unsafe methods) - #67009 (Emit coercion suggestions in more places) - #67052 (Ditch `parse_in_attr`) - #67071 (Do not ICE on closure typeck) - #67078 (accept union inside enum if not followed by identifier) - #67090 (Change "either" to "any" in Layout::from_size_align's docs) - #67092 (Fix comment typos in src/libcore/alloc.rs) - #67094 (get rid of __ in field names) - #67102 (Add note to src/ci/docker/README.md about multiple docker images) Failed merges: - #67101 (use `#[allow(unused_attributes)]` to paper over incr.comp problem) r? @ghost
As discussed in #10184
Currently, casting a floating point number to an integer with
as
is Undefined Behavior if the value is out of range.-Z saturating-float-casts
fixes this soundness hole by makingas
“saturate” to the maximum or minimum value of the integer type (or zero forNaN
), but has measurable negative performance impact in some benchmarks. There is some consensus in that thread for enabling saturation by default anyway, but provide anunsafe fn
alternative for users who know through some other mean that their values are in range.The “fit” wording is copied from https://llvm.org/docs/LangRef.html#fptoui-to-instruction, but I’m not certain what it means exactly. Presumably this is after rounding towards zero, and the doc-test withClang presumably uses those LLVM intrinsics to implement C and C++ casts, whose respective standard specify that the value after truncating to keep its integral part must be representable in the target type.i8::MIN
seems to confirm this.