1f97fa3dcSAndy Shevchenko /* 2f97fa3dcSAndy Shevchenko * Provides fixed-point logarithm operations. 3f97fa3dcSAndy Shevchenko * 4f97fa3dcSAndy Shevchenko * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) 5f97fa3dcSAndy Shevchenko * 6f97fa3dcSAndy Shevchenko * This library is free software; you can redistribute it and/or modify 7f97fa3dcSAndy Shevchenko * it under the terms of the GNU Lesser General Public License as 8f97fa3dcSAndy Shevchenko * published by the Free Software Foundation; either version 2.1 of 9f97fa3dcSAndy Shevchenko * the License, or (at your option) any later version. 10f97fa3dcSAndy Shevchenko * 11f97fa3dcSAndy Shevchenko * This program is distributed in the hope that it will be useful, 12f97fa3dcSAndy Shevchenko * but WITHOUT ANY WARRANTY; without even the implied warranty of 13f97fa3dcSAndy Shevchenko * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14f97fa3dcSAndy Shevchenko * GNU Lesser General Public License for more details. 15f97fa3dcSAndy Shevchenko */ 16f97fa3dcSAndy Shevchenko 17f97fa3dcSAndy Shevchenko #include <linux/bitops.h> 18f97fa3dcSAndy Shevchenko #include <linux/export.h> 19f97fa3dcSAndy Shevchenko #include <linux/int_log.h> 20f97fa3dcSAndy Shevchenko #include <linux/kernel.h> 21f97fa3dcSAndy Shevchenko #include <linux/types.h> 22f97fa3dcSAndy Shevchenko 23f97fa3dcSAndy Shevchenko #include <asm/bug.h> 24f97fa3dcSAndy Shevchenko 25f97fa3dcSAndy Shevchenko static const unsigned short logtable[256] = { 26f97fa3dcSAndy Shevchenko 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, 27f97fa3dcSAndy Shevchenko 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, 28f97fa3dcSAndy Shevchenko 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, 29f97fa3dcSAndy Shevchenko 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, 30f97fa3dcSAndy Shevchenko 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, 31f97fa3dcSAndy Shevchenko 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, 32f97fa3dcSAndy Shevchenko 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, 33f97fa3dcSAndy Shevchenko 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, 34f97fa3dcSAndy Shevchenko 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, 35f97fa3dcSAndy Shevchenko 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, 36f97fa3dcSAndy Shevchenko 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, 37f97fa3dcSAndy Shevchenko 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, 38f97fa3dcSAndy Shevchenko 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, 39f97fa3dcSAndy Shevchenko 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, 40f97fa3dcSAndy Shevchenko 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, 41f97fa3dcSAndy Shevchenko 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, 42f97fa3dcSAndy Shevchenko 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, 43f97fa3dcSAndy Shevchenko 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, 44f97fa3dcSAndy Shevchenko 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, 45f97fa3dcSAndy Shevchenko 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, 46f97fa3dcSAndy Shevchenko 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, 47f97fa3dcSAndy Shevchenko 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, 48f97fa3dcSAndy Shevchenko 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, 49f97fa3dcSAndy Shevchenko 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, 50f97fa3dcSAndy Shevchenko 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, 51f97fa3dcSAndy Shevchenko 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, 52f97fa3dcSAndy Shevchenko 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, 53f97fa3dcSAndy Shevchenko 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, 54f97fa3dcSAndy Shevchenko 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, 55f97fa3dcSAndy Shevchenko 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, 56f97fa3dcSAndy Shevchenko 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, 57f97fa3dcSAndy Shevchenko 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47, 58f97fa3dcSAndy Shevchenko }; 59f97fa3dcSAndy Shevchenko 60f97fa3dcSAndy Shevchenko unsigned int intlog2(u32 value) 61f97fa3dcSAndy Shevchenko { 62f97fa3dcSAndy Shevchenko /** 63f97fa3dcSAndy Shevchenko * returns: log2(value) * 2^24 64f97fa3dcSAndy Shevchenko * wrong result if value = 0 (log2(0) is undefined) 65f97fa3dcSAndy Shevchenko */ 66f97fa3dcSAndy Shevchenko unsigned int msb; 67f97fa3dcSAndy Shevchenko unsigned int logentry; 68f97fa3dcSAndy Shevchenko unsigned int significand; 69f97fa3dcSAndy Shevchenko unsigned int interpolation; 70f97fa3dcSAndy Shevchenko 71f97fa3dcSAndy Shevchenko if (unlikely(value == 0)) { 72f97fa3dcSAndy Shevchenko WARN_ON(1); 73f97fa3dcSAndy Shevchenko return 0; 74f97fa3dcSAndy Shevchenko } 75f97fa3dcSAndy Shevchenko 76f97fa3dcSAndy Shevchenko /* first detect the msb (count begins at 0) */ 77f97fa3dcSAndy Shevchenko msb = fls(value) - 1; 78f97fa3dcSAndy Shevchenko 79f97fa3dcSAndy Shevchenko /** 80f97fa3dcSAndy Shevchenko * now we use a logtable after the following method: 81f97fa3dcSAndy Shevchenko * 82f97fa3dcSAndy Shevchenko * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 83f97fa3dcSAndy Shevchenko * where x = msb and therefore 1 <= y < 2 84f97fa3dcSAndy Shevchenko * first y is determined by shifting the value left 85f97fa3dcSAndy Shevchenko * so that msb is bit 31 86f97fa3dcSAndy Shevchenko * 0x00231f56 -> 0x8C7D5800 87f97fa3dcSAndy Shevchenko * the result is y * 2^31 -> "significand" 88f97fa3dcSAndy Shevchenko * then the highest 9 bits are used for a table lookup 89f97fa3dcSAndy Shevchenko * the highest bit is discarded because it's always set 90f97fa3dcSAndy Shevchenko * the highest nine bits in our example are 100011000 91f97fa3dcSAndy Shevchenko * so we would use the entry 0x18 92f97fa3dcSAndy Shevchenko */ 93f97fa3dcSAndy Shevchenko significand = value << (31 - msb); 94*08f6a14bSAndy Shevchenko logentry = (significand >> 23) % ARRAY_SIZE(logtable); 95f97fa3dcSAndy Shevchenko 96f97fa3dcSAndy Shevchenko /** 97f97fa3dcSAndy Shevchenko * last step we do is interpolation because of the 98f97fa3dcSAndy Shevchenko * limitations of the log table the error is that part of 99f97fa3dcSAndy Shevchenko * the significand which isn't used for lookup then we 100f97fa3dcSAndy Shevchenko * compute the ratio between the error and the next table entry 101f97fa3dcSAndy Shevchenko * and interpolate it between the log table entry used and the 102f97fa3dcSAndy Shevchenko * next one the biggest error possible is 0x7fffff 103f97fa3dcSAndy Shevchenko * (in our example it's 0x7D5800) 104f97fa3dcSAndy Shevchenko * needed value for next table entry is 0x800000 105f97fa3dcSAndy Shevchenko * so the interpolation is 106f97fa3dcSAndy Shevchenko * (error / 0x800000) * (logtable_next - logtable_current) 107f97fa3dcSAndy Shevchenko * in the implementation the division is moved to the end for 108f97fa3dcSAndy Shevchenko * better accuracy there is also an overflow correction if 109f97fa3dcSAndy Shevchenko * logtable_next is 256 110f97fa3dcSAndy Shevchenko */ 111f97fa3dcSAndy Shevchenko interpolation = ((significand & 0x7fffff) * 112*08f6a14bSAndy Shevchenko ((logtable[(logentry + 1) % ARRAY_SIZE(logtable)] - 113f97fa3dcSAndy Shevchenko logtable[logentry]) & 0xffff)) >> 15; 114f97fa3dcSAndy Shevchenko 115f97fa3dcSAndy Shevchenko /* now we return the result */ 116f97fa3dcSAndy Shevchenko return ((msb << 24) + (logtable[logentry] << 8) + interpolation); 117f97fa3dcSAndy Shevchenko } 118f97fa3dcSAndy Shevchenko EXPORT_SYMBOL(intlog2); 119f97fa3dcSAndy Shevchenko 120f97fa3dcSAndy Shevchenko unsigned int intlog10(u32 value) 121f97fa3dcSAndy Shevchenko { 122f97fa3dcSAndy Shevchenko /** 123f97fa3dcSAndy Shevchenko * returns: log10(value) * 2^24 124f97fa3dcSAndy Shevchenko * wrong result if value = 0 (log10(0) is undefined) 125f97fa3dcSAndy Shevchenko */ 126f97fa3dcSAndy Shevchenko u64 log; 127f97fa3dcSAndy Shevchenko 128f97fa3dcSAndy Shevchenko if (unlikely(value == 0)) { 129f97fa3dcSAndy Shevchenko WARN_ON(1); 130f97fa3dcSAndy Shevchenko return 0; 131f97fa3dcSAndy Shevchenko } 132f97fa3dcSAndy Shevchenko 133f97fa3dcSAndy Shevchenko log = intlog2(value); 134f97fa3dcSAndy Shevchenko 135f97fa3dcSAndy Shevchenko /** 136f97fa3dcSAndy Shevchenko * we use the following method: 137f97fa3dcSAndy Shevchenko * log10(x) = log2(x) * log10(2) 138f97fa3dcSAndy Shevchenko */ 139f97fa3dcSAndy Shevchenko 140f97fa3dcSAndy Shevchenko return (log * 646456993) >> 31; 141f97fa3dcSAndy Shevchenko } 142f97fa3dcSAndy Shevchenko EXPORT_SYMBOL(intlog10); 143