1 | /* +++Date last modified: 05-Jul-1997 */ |
---|
2 | |
---|
3 | #include <string.h> |
---|
4 | #include "basicmath-snipmath.h" |
---|
5 | |
---|
6 | #define BITSPERLONG 32 |
---|
7 | |
---|
8 | #define TOP2BITS(x) ((x & (3L << (BITSPERLONG-2))) >> (BITSPERLONG-2)) |
---|
9 | |
---|
10 | |
---|
11 | /* usqrt: |
---|
12 | ENTRY x: unsigned long |
---|
13 | EXIT returns floor(sqrt(x) * pow(2, BITSPERLONG/2)) |
---|
14 | |
---|
15 | Since the square root never uses more than half the bits |
---|
16 | of the input, we use the other half of the bits to contain |
---|
17 | extra bits of precision after the binary point. |
---|
18 | |
---|
19 | EXAMPLE |
---|
20 | suppose BITSPERLONG = 32 |
---|
21 | then usqrt(144) = 786432 = 12 * 65536 |
---|
22 | usqrt(32) = 370727 = 5.66 * 65536 |
---|
23 | |
---|
24 | NOTES |
---|
25 | (1) change BITSPERLONG to BITSPERLONG/2 if you do not want |
---|
26 | the answer scaled. Indeed, if you want n bits of |
---|
27 | precision after the binary point, use BITSPERLONG/2+n. |
---|
28 | The code assumes that BITSPERLONG is even. |
---|
29 | (2) This is really better off being written in assembly. |
---|
30 | The line marked below is really a "arithmetic shift left" |
---|
31 | on the double-long value with r in the upper half |
---|
32 | and x in the lower half. This operation is typically |
---|
33 | expressible in only one or two assembly instructions. |
---|
34 | (3) Unrolling this loop is probably not a bad idea. |
---|
35 | |
---|
36 | ALGORITHM |
---|
37 | The calculations are the base-two analogue of the square |
---|
38 | root algorithm we all learned in grammar school. Since we're |
---|
39 | in base 2, there is only one nontrivial trial multiplier. |
---|
40 | |
---|
41 | Notice that absolutely no multiplications or divisions are performed. |
---|
42 | This means it'll be fast on a wide range of processors. |
---|
43 | */ |
---|
44 | |
---|
45 | void usqrt(unsigned long x, struct int_sqrt *q) |
---|
46 | { |
---|
47 | unsigned long a = 0L; /* accumulator */ |
---|
48 | unsigned long r = 0L; /* remainder */ |
---|
49 | unsigned long e = 0L; /* trial product */ |
---|
50 | |
---|
51 | int i; |
---|
52 | |
---|
53 | for (i = 0; i < BITSPERLONG; i++) /* NOTE 1 */ |
---|
54 | { |
---|
55 | r = (r << 2) + TOP2BITS(x); x <<= 2; /* NOTE 2 */ |
---|
56 | a <<= 1; |
---|
57 | e = (a << 1) + 1; |
---|
58 | if (r >= e) |
---|
59 | { |
---|
60 | r -= e; |
---|
61 | a++; |
---|
62 | } |
---|
63 | } |
---|
64 | memcpy(q, &a, sizeof(long)); |
---|
65 | } |
---|
66 | |
---|
67 | #ifdef TEST |
---|
68 | |
---|
69 | #include <stdio.h> |
---|
70 | #include <stdlib.h> |
---|
71 | |
---|
72 | main(void) |
---|
73 | { |
---|
74 | int i; |
---|
75 | unsigned long l = 0x3fed0169L; |
---|
76 | struct int_sqrt q; |
---|
77 | |
---|
78 | for (i = 0; i < 101; ++i) |
---|
79 | { |
---|
80 | usqrt(i, &q); |
---|
81 | printf("sqrt(%3d) = %2d, remainder = %2d\n", |
---|
82 | i, q.sqrt, q.frac); |
---|
83 | } |
---|
84 | usqrt(l, &q); |
---|
85 | printf("\nsqrt(%lX) = %X, remainder = %X\n", l, q.sqrt, q.frac); |
---|
86 | return 0; |
---|
87 | } |
---|
88 | |
---|
89 | #endif /* TEST */ |
---|