Repository navigation
add scalbn and ilogb methods on floats
#163187
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1356,6 +1356,45 @@ intrinsic_dispatch_on_type! { | |
| f128 => { libm::maybe_available::log2f128(x) } | ||
| } | ||
|
|
||
| intrinsic_dispatch_on_type! { | ||
| /// Calculates `x * 2.0^exp` efficiently. | ||
| /// | ||
| /// This intrinsic does not have a stable counterpart. | ||
| #[rustc_nounwind] | ||
| #[inline] | ||
| #[rustc_intrinsic] | ||
| // The fallback bodies call into `libm`, which is not available at compile time. This is fine | ||
| // because const-eval implements this intrinsic itself and never runs the fallback body. | ||
| #[rustc_do_not_const_check] | ||
| pub const fn scalbn<T: bounds::FloatPrimitive>(x: T, exp: i32) -> T; | ||
|
|
||
| f16 => { libm::scalbnf16(x, exp) } | ||
| f32 => { libm::scalbnf(x, exp) } | ||
| f64 => { libm::scalbn(x, exp) } | ||
| f128 => { libm::scalbnf128(x, exp) } | ||
| } | ||
|
|
||
| intrinsic_dispatch_on_type! { | ||
| /// Returns the order of magnitude of `x` (in base 2). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should probably clarify that this means it ignores the sign, even though it's technically correct.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have a concrete suggestion for how to rephrase this? When I try it just gets more confusing, leaning on the examples here seems fine to me. |
||
| /// | ||
| /// When `x` is NaN or `0.0`, the return value is implementation-defined, and may be different | ||
| /// between const eval and runtime. When `x` is an infinity, the return value is [`i32::MAX`]. | ||
| /// | ||
| /// This intrinsic does not have a stable counterpart. | ||
|
folkertdev marked this conversation as resolved.
|
||
| #[rustc_nounwind] | ||
| #[inline] | ||
| #[rustc_intrinsic] | ||
| // The fallback bodies call into `libm`, which is not available at compile time. This is fine | ||
| // because const-eval implements this intrinsic itself and never runs the fallback body. | ||
| #[rustc_do_not_const_check] | ||
| pub const fn ilogb<T: bounds::FloatPrimitive>(x: T) -> i32; | ||
|
|
||
| f16 => { libm::ilogbf16(x) } | ||
| f32 => { libm::ilogbf(x) } | ||
| f64 => { libm::ilogb(x) } | ||
| f128 => { libm::ilogbf128(x) } | ||
| } | ||
|
|
||
| /// Returns `a * b + c` without rounding the intermediate result for `f16` values. | ||
| /// | ||
| /// The stabilized version of this intrinsic is | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1682,6 +1682,30 @@ impl f128 { | |
| intrinsics::copysignf128(self, sign) | ||
| } | ||
|
|
||
| /// Placeholder. | ||
| #[inline] | ||
| #[unstable(feature = "float_exponent_methods", issue = "163184")] | ||
| #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] | ||
| #[must_use = "method returns a new number and does not mutate the original value"] | ||
| pub const fn scalbn(self, exponent: i32) -> f128 { | ||
| intrinsics::scalbn(self, exponent) | ||
| } | ||
|
|
||
| /// Placeholder. | ||
|
Comment on lines
+1685
to
+1694
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Placeholder docs. (I hate that we can't just use macros to define the float types.)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What could be nice nowadays is putting the docs into one of the |
||
| #[inline] | ||
| #[unstable(feature = "float_exponent_methods", issue = "163184")] | ||
| #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| pub const fn ilogb(self) -> Option<i32> { | ||
| if self.is_nan() { | ||
| None | ||
| } else if self == 0.0 { | ||
| Some(i32::MIN) | ||
| } else { | ||
| Some(intrinsics::ilogb(self)) | ||
| } | ||
| } | ||
|
|
||
| /// Float addition that allows optimizations based on algebraic rules. | ||
| /// | ||
| /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1668,6 +1668,30 @@ impl f16 { | |
| intrinsics::copysignf16(self, sign) | ||
| } | ||
|
|
||
| /// Placeholder. | ||
| #[inline] | ||
| #[unstable(feature = "float_exponent_methods", issue = "163184")] | ||
| #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] | ||
| #[must_use = "method returns a new number and does not mutate the original value"] | ||
| pub const fn scalbn(self, exponent: i32) -> f16 { | ||
| intrinsics::scalbn(self, exponent) | ||
| } | ||
|
|
||
| /// Placeholder. | ||
|
Comment on lines
+1671
to
+1680
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Placeholder docs. (I hate that we can't just use macros to define the float types.) |
||
| #[inline] | ||
| #[unstable(feature = "float_exponent_methods", issue = "163184")] | ||
| #[rustc_const_unstable(feature = "float_exponent_methods", issue = "163184")] | ||
| #[must_use = "this returns the result of the operation, without modifying the original"] | ||
| pub const fn ilogb(self) -> Option<i32> { | ||
| if self.is_nan() { | ||
| None | ||
| } else if self == 0.0 { | ||
| Some(i32::MIN) | ||
| } else { | ||
| Some(intrinsics::ilogb(self)) | ||
| } | ||
| } | ||
|
|
||
| /// Float addition that allows optimizations based on algebraic rules. | ||
| /// | ||
| /// See [algebraic operators](primitive@f32#algebraic-operators) for more info. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
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 isn't doing precision non-determinism. That seems wrong?
View changes since the review
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 is also a bitwise operation, so the result is exact.
Uh oh!
There was an error while loading. Please reload this page.
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.
There are three kinds of float operations:
What does scalbn guarantee about NaNs? If it's bitwise, it should preserve the exact NaN payload and sign. Your implementation calls
adjust_nanindicating that it is not bitwise.What's the best authoritative spec for scalbn (and ilogb)?
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.
I haven’t read what exactly the C spec does but most implementations prepare a scale based on
nthen multiplyxby it. So possible results are the same as multiplication between the input and a real, at least in practice.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.
Not exactly authoritative but a data point
https://en.cppreference.com/c/numeric/math/scalbn
My interpretation of that is that it's in this category
Nothing suggests it's in the
sinetc category. And modulo underflow it is an exact operation, except that it's not guaranteed that aNaNis returned unchanged, hence theadjust_nan.