Skip to content

Commit 4979668

Browse files
committed
Optimize __str_base10() using bitwise operations
Replace the loop-based method for converting integers to base-10 with a more efficient approach using bitwise operations. The new method simulates division and modulus operations by 10 without using multiplication, division, or modulus instructions, leading to improved performance. This optimization reduces the number of branches compared to the original loop-based approach, resulting in fewer conditional checks and a more streamlined execution path. Experimental results demonstrate significant performance improvements with the new method. For each test range, values within the range were used as inputs, and __str_base10() was called 10,000,000 times with these inputs distributed uniformly. Execution time was measured using the time command. The results show the following reductions in execution time: | Range | Old | New | |-----------------|--------|--------| | [0, 10) | 0.473s | 0.293s | | [0, 100) | 0.619s | 0.434s | | [0, 1000) | 0.818s | 0.646s | | [0, 10000) | 1.715s | 0.902s | | [0, 100000) | 2.166s | 1.169s | | [0, 1000000) | 2.239s | 1.453s | | [0, 10000000) | 2.359s | 1.773s | | [0, 100000000) | 2.463s | 2.122s | Link: http://web.archive.org/web/20180517023231/http://www.hackersdelight.org/divcMore.pdf
1 parent 13b828d commit 4979668

File tree

3 files changed

+32
-42
lines changed

3 files changed

+32
-42
lines changed

lib/c.c

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,25 @@ char *memcpy(char *dest, char *src, int count)
113113
return dest;
114114
}
115115

116-
/* set 10 digits (32bit) without div */
116+
/*
117+
* set 10 digits (32bit) without div
118+
*
119+
* This function converts a given integer value to its string representation
120+
* in base-10 without using division operations. The method involves calculating
121+
* the approximate quotient and remainder using bitwise operations, which are
122+
* then used to derive each digit of the result.
123+
*
124+
* The logic is based on an efficient method of dividing by constants, as
125+
* detailed in the reference link:
126+
* http://web.archive.org/web/20180517023231/http://www.hackersdelight.org/divcMore.pdf.
127+
* This approach avoids expensive division instructions by using a series of
128+
* bitwise shifts and additions to calculate the quotient and remainder.
129+
*/
117130
void __str_base10(char *pb, int val)
118131
{
119132
int neg = 0;
133+
int q, r, t;
134+
int i = INT_BUF_LEN - 1;
120135

121136
if (val == -2147483648) {
122137
strncpy(pb + INT_BUF_LEN - 11, "-2147483648", 11);
@@ -127,45 +142,20 @@ void __str_base10(char *pb, int val)
127142
val = -val;
128143
}
129144

130-
while (val >= 1000000000) {
131-
val -= 1000000000;
132-
pb[INT_BUF_LEN - 10]++;
133-
}
134-
while (val >= 100000000) {
135-
val -= 100000000;
136-
pb[INT_BUF_LEN - 9]++;
137-
}
138-
while (val >= 10000000) {
139-
val -= 10000000;
140-
pb[INT_BUF_LEN - 8]++;
141-
}
142-
while (val >= 1000000) {
143-
val -= 1000000;
144-
pb[INT_BUF_LEN - 7]++;
145-
}
146-
while (val >= 100000) {
147-
val -= 100000;
148-
pb[INT_BUF_LEN - 6]++;
149-
}
150-
while (val >= 10000) {
151-
val -= 10000;
152-
pb[INT_BUF_LEN - 5]++;
153-
}
154-
while (val >= 1000) {
155-
val -= 1000;
156-
pb[INT_BUF_LEN - 4]++;
157-
}
158-
while (val >= 100) {
159-
val -= 100;
160-
pb[INT_BUF_LEN - 3]++;
161-
}
162-
while (val >= 10) {
163-
val -= 10;
164-
pb[INT_BUF_LEN - 2]++;
165-
}
166-
while (val >= 1) {
167-
val -= 1;
168-
pb[INT_BUF_LEN - 1]++;
145+
while (val) {
146+
q = (val >> 1) + (val >> 2);
147+
q += (q >> 4);
148+
q += (q >> 8);
149+
q += (q >> 16);
150+
q = q >> 3;
151+
r = val - (((q << 2) + q) << 1);
152+
t = ((r + 6) >> 4);
153+
q += t;
154+
r = r - (((t << 2) + t) << 1);
155+
156+
pb[i] += r;
157+
val = q;
158+
i--;
169159
}
170160

171161
if (neg == 1) {

tests/snapshots/fib.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)