Skip to content

Commit

Permalink
Add imprecise_flops lint
Browse files Browse the repository at this point in the history
Add lint to detect floating point operations that can be computed more
accurately at the cost of performance. `cbrt`, `ln_1p` and `exp_m1`
library functions call their equivalent cmath implementations which is
slower but more accurate so moving checks for these under this new lint.
  • Loading branch information
krishna-veerareddy committed Feb 24, 2020
1 parent e94a167 commit 29c49d6
Show file tree
Hide file tree
Showing 14 changed files with 67 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,7 @@ Released 2018-09-13
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.

[There are 357 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
[There are 358 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)

We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:

Expand Down
55 changes: 44 additions & 11 deletions clippy_lints/src/floating_point_arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,39 @@ use std::f64::consts as f64_consts;
use sugg::{format_numeric_literal, Sugg};
use syntax::ast;

declare_clippy_lint! {
/// **What it does:** Looks for floating-point expressions that
/// can be expressed using built-in methods to improve accuracy
/// at the cost of performance.
///
/// **Why is this bad?** Negatively impacts accuracy.
///
/// **Known problems:** None
///
/// **Example:**
///
/// ```rust
///
/// let a = 3f32;
/// let _ = a.powf(1.0 / 3.0);
/// let _ = (1.0 + a).ln();
/// let _ = a.exp() - 1.0;
/// ```
///
/// is better expressed as
///
/// ```rust
///
/// let a = 3f32;
/// let _ = a.cbrt();
/// let _ = a.ln_1p();
/// let _ = a.exp_m1();
/// ```
pub IMPRECISE_FLOPS,
nursery,
"usage of imprecise floating point operations"
}

declare_clippy_lint! {
/// **What it does:** Looks for floating-point expressions that
/// can be expressed using built-in methods to improve both
Expand All @@ -34,12 +67,9 @@ declare_clippy_lint! {
/// let _ = (2f32).powf(a);
/// let _ = E.powf(a);
/// let _ = a.powf(1.0 / 2.0);
/// let _ = a.powf(1.0 / 3.0);
/// let _ = a.log(2.0);
/// let _ = a.log(10.0);
/// let _ = a.log(E);
/// let _ = (1.0 + a).ln();
/// let _ = a.exp() - 1.0;
/// let _ = a.powf(2.0);
/// let _ = a * 2.0 + 4.0;
/// ```
Expand All @@ -53,12 +83,9 @@ declare_clippy_lint! {
/// let _ = a.exp2();
/// let _ = a.exp();
/// let _ = a.sqrt();
/// let _ = a.cbrt();
/// let _ = a.log2();
/// let _ = a.log10();
/// let _ = a.ln();
/// let _ = a.ln_1p();
/// let _ = a.exp_m1();
/// let _ = a.powi(2);
/// let _ = a.mul_add(2.0, 4.0);
/// ```
Expand All @@ -67,7 +94,10 @@ declare_clippy_lint! {
"usage of sub-optimal floating point operations"
}

declare_lint_pass!(FloatingPointArithmetic => [SUBOPTIMAL_FLOPS]);
declare_lint_pass!(FloatingPointArithmetic => [
IMPRECISE_FLOPS,
SUBOPTIMAL_FLOPS
]);

// Returns the specialized log method for a given base if base is constant
// and is one of 2, 10 and e
Expand Down Expand Up @@ -156,7 +186,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {

span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
IMPRECISE_FLOPS,
expr.span,
"ln(1 + x) can be computed more accurately",
"consider using",
Expand Down Expand Up @@ -215,18 +245,21 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {

// Check argument
if let Some((value, _)) = constant(cx, cx.tables, &args[1]) {
let (help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
(
SUBOPTIMAL_FLOPS,
"square-root of a number can be computed more efficiently and accurately",
format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")),
)
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
(
IMPRECISE_FLOPS,
"cube-root of a number can be computed more accurately",
format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")),
)
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
(
SUBOPTIMAL_FLOPS,
"exponentiation with integer powers can be computed more efficiently",
format!(
"{}.powi({})",
Expand All @@ -240,7 +273,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {

span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
lint,
expr.span,
help,
"consider using",
Expand All @@ -264,7 +297,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
then {
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
IMPRECISE_FLOPS,
expr.span,
"(e.pow(x) - 1) can be computed more accurately",
"consider using",
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&fallible_impl_from::FALLIBLE_IMPL_FROM,
&float_literal::EXCESSIVE_PRECISION,
&float_literal::LOSSY_FLOAT_LITERAL,
&floating_point_arithmetic::IMPRECISE_FLOPS,
&floating_point_arithmetic::SUBOPTIMAL_FLOPS,
&format::USELESS_FORMAT,
&formatting::POSSIBLE_MISSING_COMMA,
Expand Down Expand Up @@ -1648,6 +1649,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),
LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
Expand Down
9 changes: 8 additions & 1 deletion src/lintlist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use lint::Lint;
pub use lint::LINT_LEVELS;

// begin lint list, do not remove this comment, it’s used in `update_lints`
pub const ALL_LINTS: [Lint; 357] = [
pub const ALL_LINTS: [Lint; 358] = [
Lint {
name: "absurd_extreme_comparisons",
group: "correctness",
Expand Down Expand Up @@ -749,6 +749,13 @@ pub const ALL_LINTS: [Lint; 357] = [
deprecation: None,
module: "implicit_return",
},
Lint {
name: "imprecise_flops",
group: "nursery",
desc: "usage of imprecise floating point operations",
deprecation: None,
module: "floating_point_arithmetic",
},
Lint {
name: "inconsistent_digit_grouping",
group: "style",
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/floating_point_exp.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-rustfix
#![warn(clippy::suboptimal_flops)]
#![warn(clippy::imprecise_flops)]

fn main() {
let x = 2f32;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/floating_point_exp.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-rustfix
#![warn(clippy::suboptimal_flops)]
#![warn(clippy::imprecise_flops)]

fn main() {
let x = 2f32;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/floating_point_exp.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: (e.pow(x) - 1) can be computed more accurately
LL | let _ = x.exp() - 1.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
|
= note: `-D clippy::suboptimal-flops` implied by `-D warnings`
= note: `-D clippy::imprecise-flops` implied by `-D warnings`

error: (e.pow(x) - 1) can be computed more accurately
--> $DIR/floating_point_exp.rs:7:13
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/floating_point_log.fixed
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// run-rustfix
#![allow(dead_code, clippy::double_parens)]
#![warn(clippy::suboptimal_flops)]
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]

const TWO: f32 = 2.0;
const E: f32 = std::f32::consts::E;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/floating_point_log.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// run-rustfix
#![allow(dead_code, clippy::double_parens)]
#![warn(clippy::suboptimal_flops)]
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]

const TWO: f32 = 2.0;
const E: f32 = std::f32::consts::E;
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/floating_point_log.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ error: ln(1 + x) can be computed more accurately
|
LL | let _ = (1f32 + 2.).ln();
| ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
|
= note: `-D clippy::imprecise-flops` implied by `-D warnings`

error: ln(1 + x) can be computed more accurately
--> $DIR/floating_point_log.rs:25:13
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/floating_point_powf.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-rustfix
#![warn(clippy::suboptimal_flops)]
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]

fn main() {
let x = 3f32;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/floating_point_powf.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-rustfix
#![warn(clippy::suboptimal_flops)]
#![warn(clippy::suboptimal_flops, clippy::imprecise_flops)]

fn main() {
let x = 3f32;
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/floating_point_powf.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ error: cube-root of a number can be computed more accurately
|
LL | let _ = x.powf(1.0 / 3.0);
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
|
= note: `-D clippy::imprecise-flops` implied by `-D warnings`

error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_powf.rs:14:13
Expand Down

0 comments on commit 29c49d6

Please sign in to comment.