Suggest usage of powi method when applicable

This commit is contained in:
Krishna Veera Reddy 2019-12-15 19:26:44 -08:00 committed by Krishna Sai Veera Reddy
parent 1f4f357bf5
commit 9520d3dfa4
3 changed files with 85 additions and 10 deletions

View File

@ -1,5 +1,5 @@
use crate::consts::{
constant,
constant, Constant,
Constant::{F32, F64},
};
use crate::utils::*;
@ -37,6 +37,7 @@ declare_clippy_lint! {
/// let _ = a.log(E);
/// let _ = (1.0 + a).ln();
/// let _ = a.exp() - 1.0;
/// let _ = a.powf(2.0);
/// ```
///
/// is better expressed as
@ -54,6 +55,7 @@ declare_clippy_lint! {
/// let _ = a.ln();
/// let _ = a.ln_1p();
/// let _ = a.exp_m1();
/// let _ = a.powi(2);
/// ```
pub FLOATING_POINT_IMPROVEMENTS,
nursery,
@ -114,6 +116,31 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
}
}
// Returns an integer if the float constant is a whole number and it
// can be converted to an integer without loss
// TODO: Add a better check to determine whether the float can be
// casted without loss
#[allow(clippy::cast_possible_truncation)]
fn get_integer_from_float_constant(value: &Constant) -> Option<i64> {
match value {
F32(num) if (num.trunc() - num).abs() <= std::f32::EPSILON => {
if *num > -16_777_217.0 && *num < 16_777_217.0 {
Some(num.round() as i64)
} else {
None
}
},
F64(num) if (num.trunc() - num).abs() <= std::f64::EPSILON => {
if *num > -9_007_199_254_740_993.0 && *num < 9_007_199_254_740_993.0 {
Some(num.round() as i64)
} else {
None
}
},
_ => None,
}
}
fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
// Check receiver
if let Some((value, _)) = constant(cx, cx.tables, &args[0]) {
@ -149,6 +176,18 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
help = "cube-root of a number can be computed more accurately";
method = "cbrt";
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
span_lint_and_sugg(
cx,
FLOATING_POINT_IMPROVEMENTS,
expr.span,
"exponentiation with integer powers can be computed more efficiently",
"consider using",
format!("{}.powi({})", sugg::Sugg::hir(cx, &args[0], ".."), exponent),
Applicability::MachineApplicable,
);
return;
} else {
return;
}

View File

@ -46,12 +46,24 @@ fn check_powf() {
let _ = std::f32::consts::E.powf(x);
let _ = x.powf(1.0 / 2.0);
let _ = x.powf(1.0 / 3.0);
let _ = x.powf(2.0);
let _ = x.powf(-2.0);
let _ = x.powf(2.1);
let _ = x.powf(-2.1);
let _ = x.powf(16_777_217.0);
let _ = x.powf(-16_777_217.0);
let x = 3f64;
let _ = 2f64.powf(x);
let _ = std::f64::consts::E.powf(x);
let _ = x.powf(1.0 / 2.0);
let _ = x.powf(1.0 / 3.0);
let _ = x.powf(2.0);
let _ = x.powf(-2.0);
let _ = x.powf(2.1);
let _ = x.powf(-2.1);
let _ = x.powf(9_007_199_254_740_993.0);
let _ = x.powf(-9_007_199_254_740_993.0);
}
fn check_expm1() {

View File

@ -120,53 +120,77 @@ error: cube-root of a number can be computed more accurately
LL | let _ = x.powf(1.0 / 3.0);
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_arithmetic.rs:49:13
|
LL | let _ = x.powf(2.0);
| ^^^^^^^^^^^ help: consider using: `x.powi(2)`
error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_arithmetic.rs:50:13
|
LL | let _ = x.powf(-2.0);
| ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
error: exponent for bases 2 and e can be computed more accurately
--> $DIR/floating_point_arithmetic.rs:51:13
--> $DIR/floating_point_arithmetic.rs:57:13
|
LL | let _ = 2f64.powf(x);
| ^^^^^^^^^^^^ help: consider using: `x.exp2()`
error: exponent for bases 2 and e can be computed more accurately
--> $DIR/floating_point_arithmetic.rs:52:13
--> $DIR/floating_point_arithmetic.rs:58:13
|
LL | let _ = std::f64::consts::E.powf(x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
error: square-root of a number can be computed more efficiently and accurately
--> $DIR/floating_point_arithmetic.rs:53:13
--> $DIR/floating_point_arithmetic.rs:59:13
|
LL | let _ = x.powf(1.0 / 2.0);
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
error: cube-root of a number can be computed more accurately
--> $DIR/floating_point_arithmetic.rs:54:13
--> $DIR/floating_point_arithmetic.rs:60:13
|
LL | let _ = x.powf(1.0 / 3.0);
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_arithmetic.rs:61:13
|
LL | let _ = x.powf(2.0);
| ^^^^^^^^^^^ help: consider using: `x.powi(2)`
error: exponentiation with integer powers can be computed more efficiently
--> $DIR/floating_point_arithmetic.rs:62:13
|
LL | let _ = x.powf(-2.0);
| ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
error: (e.pow(x) - 1) can be computed more accurately
--> $DIR/floating_point_arithmetic.rs:59:13
--> $DIR/floating_point_arithmetic.rs:71:13
|
LL | let _ = x.exp() - 1.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
error: (e.pow(x) - 1) can be computed more accurately
--> $DIR/floating_point_arithmetic.rs:60:13
--> $DIR/floating_point_arithmetic.rs:72:13
|
LL | let _ = x.exp() - 1.0 + 2.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
error: (e.pow(x) - 1) can be computed more accurately
--> $DIR/floating_point_arithmetic.rs:66:13
--> $DIR/floating_point_arithmetic.rs:78:13
|
LL | let _ = x.exp() - 1.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
error: (e.pow(x) - 1) can be computed more accurately
--> $DIR/floating_point_arithmetic.rs:67:13
--> $DIR/floating_point_arithmetic.rs:79:13
|
LL | let _ = x.exp() - 1.0 + 2.0;
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
error: aborting due to 28 previous errors
error: aborting due to 32 previous errors