The current implementation of num_digits() uses a loop with repeated
multiplication, which is inefficient. Furthermore, the negation of
the input value "val = -val" causes undefined behavior when val is
INT_MIN, as its absolute value cannot be represented as a 32-bit integer.
Replace the loop with a linear chain of comparisons. This allows the
compiler to generate optimized branch sequences, providing better
performance than the original loop and more efficient assembly than a
switch statement on compilers like Clang. By using an internal unsigned
int to handle the magnitude, we safely handle the INT_MIN case without
relying on 64-bit types or triggering undefined signed overflow.
Removed the outdated comment.
Signed-off-by: David Desobry <david.desobry@formalgen.com>
---
v3:
- Replaced switch statement with a linear if-chain for better compiler
optimization.
- Simplified sign handling logic to a single if/else block.
- (v2) Fixed INT_MIN overflow using unsigned magnitude and removed
outdated comment.
arch/x86/lib/misc.c | 38 +++++++++++++++++++++++++++-----------
1 file changed, 27 insertions(+), 11 deletions(-)
diff --git a/arch/x86/lib/misc.c b/arch/x86/lib/misc.c
index 40b81c338ae5..3d56583411cf 100644
--- a/arch/x86/lib/misc.c
+++ b/arch/x86/lib/misc.c
@@ -3,22 +3,38 @@
/*
* Count the digits of @val including a possible sign.
- *
- * (Typed on and submitted from hpa's mobile phone.)
*/
int num_digits(int val)
{
- long long m = 10;
- int d = 1;
+ unsigned int v;
+ int d;
if (val < 0) {
- d++;
- val = -val;
+ d = 1;
+ v = -val;
+ } else {
+ d = 0;
+ v = val;
}
- while (val >= m) {
- m *= 10;
- d++;
- }
- return d;
+ if (v <= 9)
+ return d + 1;
+ if (v <= 99)
+ return d + 2;
+ if (v <= 999)
+ return d + 3;
+ if (v <= 9999)
+ return d + 4;
+ if (v <= 99999)
+ return d + 5;
+ if (v <= 999999)
+ return d + 6;
+ if (v <= 9999999)
+ return d + 7;
+ if (v <= 99999999)
+ return d + 8;
+ if (v <= 999999999)
+ return d + 9;
+
+ return d + 10;
}
--
2.43.0