|
| 1 | +;; Integer Logarithms for Various Bases |
| 2 | +;; by Kang Seonghoon (lifthrasiir, @senokay) |
| 3 | +;; licensed under WTFPL. feel free to use. |
| 4 | +;; |
| 5 | +;; declares: ilog2, ilog10, ilog10s |
| 6 | + |
| 7 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 8 | +;; ilog2 |
| 9 | + |
| 10 | +; calculates ilog2(A) where: |
| 11 | +; ilog2(x) = floor(log_2(x)) if x > 0 |
| 12 | +; = 0 if x = 0. |
| 13 | +; |
| 14 | +; cycles: 25 |
| 15 | +; receives: A |
| 16 | +; clobbers: A, B |
| 17 | +; returns: A |
| 18 | +:ilog2 |
| 19 | + SET B, A ; A = A | (A<<1) |
| 20 | + SHR B, 1 |
| 21 | + BOR A, B |
| 22 | + SET B, A ; A = A | (A<<2) |
| 23 | + SHR B, 2 |
| 24 | + BOR A, B |
| 25 | + SET B, A ; A = A | (A<<4) |
| 26 | + SHR B, 4 |
| 27 | + BOR A, B |
| 28 | + SET B, A ; A = A | (A<<8) |
| 29 | + SHR B, 8 |
| 30 | + BOR A, B |
| 31 | + MUL A, 0xf2d ; A = ilog2_debruijn[(A*0xf2d)>>12] |
| 32 | + SHR A, 12 |
| 33 | + SET A, [A+ilog2_debruijn] |
| 34 | + SET PC, POP |
| 35 | +:ilog2_debruijn |
| 36 | + DAT 0, 7, 1, 13, 8, 10, 2, 14 |
| 37 | + DAT 6, 12, 9, 5, 11, 4, 3, 15 |
| 38 | + |
| 39 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 40 | +;; ilog10 (in two variants) |
| 41 | + |
| 42 | +; calculates ilog10(A) where: |
| 43 | +; ilog10(x) = floor(log_10(x)) if x > 0 |
| 44 | +; = 0 if x = 0. |
| 45 | +; |
| 46 | +; takes 13 cycles when 0 <= A < 100, |
| 47 | +; 16 cycles when 100 <= A < 10000, |
| 48 | +; 8 cycles when 10000 <= A < 65536. |
| 49 | +; use this if your input is uniformly distributed. |
| 50 | +; |
| 51 | +; cycles: <= 16, 9.2 average |
| 52 | +; receives: A |
| 53 | +; clobbers: A |
| 54 | +; returns: A |
| 55 | +:ilog10 |
| 56 | + IFG A, 9999 |
| 57 | + ADD PC, 7 ; jumps to ilog10_above9999 |
| 58 | + IFG A, 99 |
| 59 | + ADD PC, 6 ; jumps to ilog10_above99 |
| 60 | + ADD 0xfff6, A ; 0xfff6 = 0x10000 - 10 |
| 61 | + SET A, O ; now O = (A >= 10) |
| 62 | + SET PC, POP |
| 63 | +:ilog10_above9999 |
| 64 | + SET A, 4 |
| 65 | + SET PC, POP |
| 66 | +:ilog10_above99 |
| 67 | + ADD 0xfc18, A ; 0xfc18 = 0x10000 - 1000 |
| 68 | + SET A, 2 ; now O = (A >= 1000) |
| 69 | + BOR A, O |
| 70 | + SET PC, POP |
| 71 | + |
| 72 | +; same as ilog10 but optimized for smaller inputs. |
| 73 | +; |
| 74 | +; takes 10 cycles when 0 <= A < 100, |
| 75 | +; 16 cycles when 100 <= A < 10000, |
| 76 | +; 11 cycles when 10000 <= A < 65536. |
| 77 | +; |
| 78 | +; cycles: <= 16, 11.8 average |
| 79 | +; receives: A |
| 80 | +; clobbers: A |
| 81 | +; returns: A |
| 82 | +:ilog10s |
| 83 | + IFG 100, A |
| 84 | + ADD PC, 5 ; jumps to ilog10_below100 |
| 85 | + IFG 10000, A |
| 86 | + ADD PC, 6 ; jumps to ilog10_below10000 |
| 87 | + SET A, 4 |
| 88 | + SET PC, POP |
| 89 | +:ilog10_below100 |
| 90 | + ADD 0xfff6, A ; 0xfff6 = 0x10000 - 10 |
| 91 | + SET A, O ; now O = (A >= 10) |
| 92 | + SET PC, POP |
| 93 | +:ilog10_below10000 |
| 94 | + ADD 0xfc18, A ; 0xfc18 = 0x10000 - 1000 |
| 95 | + SET A, 2 ; now O = (A >= 1000) |
| 96 | + BOR A, O |
| 97 | + SET PC, POP |
| 98 | + |
0 commit comments