Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9520d3d

Browse files
Suggest usage of powi method when applicable
1 parent 1f4f357 commit 9520d3d

File tree

3 files changed

+85
-10
lines changed

3 files changed

+85
-10
lines changed

clippy_lints/src/floating_point_arithmetic.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::consts::{
2-
constant,
2+
constant, Constant,
33
Constant::{F32, F64},
44
};
55
use crate::utils::*;
@@ -37,6 +37,7 @@ declare_clippy_lint! {
3737
/// let _ = a.log(E);
3838
/// let _ = (1.0 + a).ln();
3939
/// let _ = a.exp() - 1.0;
40+
/// let _ = a.powf(2.0);
4041
/// ```
4142
///
4243
/// is better expressed as
@@ -54,6 +55,7 @@ declare_clippy_lint! {
5455
/// let _ = a.ln();
5556
/// let _ = a.ln_1p();
5657
/// let _ = a.exp_m1();
58+
/// let _ = a.powi(2);
5759
/// ```
5860
pub FLOATING_POINT_IMPROVEMENTS,
5961
nursery,
@@ -114,6 +116,31 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
114116
}
115117
}
116118

119+
// Returns an integer if the float constant is a whole number and it
120+
// can be converted to an integer without loss
121+
// TODO: Add a better check to determine whether the float can be
122+
// casted without loss
123+
#[allow(clippy::cast_possible_truncation)]
124+
fn get_integer_from_float_constant(value: &Constant) -> Option<i64> {
125+
match value {
126+
F32(num) if (num.trunc() - num).abs() <= std::f32::EPSILON => {
127+
if *num > -16_777_217.0 && *num < 16_777_217.0 {
128+
Some(num.round() as i64)
129+
} else {
130+
None
131+
}
132+
},
133+
F64(num) if (num.trunc() - num).abs() <= std::f64::EPSILON => {
134+
if *num > -9_007_199_254_740_993.0 && *num < 9_007_199_254_740_993.0 {
135+
Some(num.round() as i64)
136+
} else {
137+
None
138+
}
139+
},
140+
_ => None,
141+
}
142+
}
143+
117144
fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
118145
// Check receiver
119146
if let Some((value, _)) = constant(cx, cx.tables, &args[0]) {
@@ -149,6 +176,18 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
149176
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
150177
help = "cube-root of a number can be computed more accurately";
151178
method = "cbrt";
179+
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
180+
span_lint_and_sugg(
181+
cx,
182+
FLOATING_POINT_IMPROVEMENTS,
183+
expr.span,
184+
"exponentiation with integer powers can be computed more efficiently",
185+
"consider using",
186+
format!("{}.powi({})", sugg::Sugg::hir(cx, &args[0], ".."), exponent),
187+
Applicability::MachineApplicable,
188+
);
189+
190+
return;
152191
} else {
153192
return;
154193
}

tests/ui/floating_point_arithmetic.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,24 @@ fn check_powf() {
4646
let _ = std::f32::consts::E.powf(x);
4747
let _ = x.powf(1.0 / 2.0);
4848
let _ = x.powf(1.0 / 3.0);
49+
let _ = x.powf(2.0);
50+
let _ = x.powf(-2.0);
51+
let _ = x.powf(2.1);
52+
let _ = x.powf(-2.1);
53+
let _ = x.powf(16_777_217.0);
54+
let _ = x.powf(-16_777_217.0);
4955

5056
let x = 3f64;
5157
let _ = 2f64.powf(x);
5258
let _ = std::f64::consts::E.powf(x);
5359
let _ = x.powf(1.0 / 2.0);
5460
let _ = x.powf(1.0 / 3.0);
61+
let _ = x.powf(2.0);
62+
let _ = x.powf(-2.0);
63+
let _ = x.powf(2.1);
64+
let _ = x.powf(-2.1);
65+
let _ = x.powf(9_007_199_254_740_993.0);
66+
let _ = x.powf(-9_007_199_254_740_993.0);
5567
}
5668

5769
fn check_expm1() {

tests/ui/floating_point_arithmetic.stderr

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,53 +120,77 @@ error: cube-root of a number can be computed more accurately
120120
LL | let _ = x.powf(1.0 / 3.0);
121121
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
122122

123+
error: exponentiation with integer powers can be computed more efficiently
124+
--> $DIR/floating_point_arithmetic.rs:49:13
125+
|
126+
LL | let _ = x.powf(2.0);
127+
| ^^^^^^^^^^^ help: consider using: `x.powi(2)`
128+
129+
error: exponentiation with integer powers can be computed more efficiently
130+
--> $DIR/floating_point_arithmetic.rs:50:13
131+
|
132+
LL | let _ = x.powf(-2.0);
133+
| ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
134+
123135
error: exponent for bases 2 and e can be computed more accurately
124-
--> $DIR/floating_point_arithmetic.rs:51:13
136+
--> $DIR/floating_point_arithmetic.rs:57:13
125137
|
126138
LL | let _ = 2f64.powf(x);
127139
| ^^^^^^^^^^^^ help: consider using: `x.exp2()`
128140

129141
error: exponent for bases 2 and e can be computed more accurately
130-
--> $DIR/floating_point_arithmetic.rs:52:13
142+
--> $DIR/floating_point_arithmetic.rs:58:13
131143
|
132144
LL | let _ = std::f64::consts::E.powf(x);
133145
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
134146

135147
error: square-root of a number can be computed more efficiently and accurately
136-
--> $DIR/floating_point_arithmetic.rs:53:13
148+
--> $DIR/floating_point_arithmetic.rs:59:13
137149
|
138150
LL | let _ = x.powf(1.0 / 2.0);
139151
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
140152

141153
error: cube-root of a number can be computed more accurately
142-
--> $DIR/floating_point_arithmetic.rs:54:13
154+
--> $DIR/floating_point_arithmetic.rs:60:13
143155
|
144156
LL | let _ = x.powf(1.0 / 3.0);
145157
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
146158

159+
error: exponentiation with integer powers can be computed more efficiently
160+
--> $DIR/floating_point_arithmetic.rs:61:13
161+
|
162+
LL | let _ = x.powf(2.0);
163+
| ^^^^^^^^^^^ help: consider using: `x.powi(2)`
164+
165+
error: exponentiation with integer powers can be computed more efficiently
166+
--> $DIR/floating_point_arithmetic.rs:62:13
167+
|
168+
LL | let _ = x.powf(-2.0);
169+
| ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
170+
147171
error: (e.pow(x) - 1) can be computed more accurately
148-
--> $DIR/floating_point_arithmetic.rs:59:13
172+
--> $DIR/floating_point_arithmetic.rs:71:13
149173
|
150174
LL | let _ = x.exp() - 1.0;
151175
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
152176

153177
error: (e.pow(x) - 1) can be computed more accurately
154-
--> $DIR/floating_point_arithmetic.rs:60:13
178+
--> $DIR/floating_point_arithmetic.rs:72:13
155179
|
156180
LL | let _ = x.exp() - 1.0 + 2.0;
157181
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
158182

159183
error: (e.pow(x) - 1) can be computed more accurately
160-
--> $DIR/floating_point_arithmetic.rs:66:13
184+
--> $DIR/floating_point_arithmetic.rs:78:13
161185
|
162186
LL | let _ = x.exp() - 1.0;
163187
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
164188

165189
error: (e.pow(x) - 1) can be computed more accurately
166-
--> $DIR/floating_point_arithmetic.rs:67:13
190+
--> $DIR/floating_point_arithmetic.rs:79:13
167191
|
168192
LL | let _ = x.exp() - 1.0 + 2.0;
169193
| ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
170194

171-
error: aborting due to 28 previous errors
195+
error: aborting due to 32 previous errors
172196

0 commit comments

Comments
 (0)