162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Provides fixed-point logarithm operations. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitops.h> 962306a36Sopenharmony_ci#include <linux/export.h> 1062306a36Sopenharmony_ci#include <linux/int_log.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <asm/bug.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic const unsigned short logtable[256] = { 1762306a36Sopenharmony_ci 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, 1862306a36Sopenharmony_ci 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, 1962306a36Sopenharmony_ci 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, 2062306a36Sopenharmony_ci 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, 2162306a36Sopenharmony_ci 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, 2262306a36Sopenharmony_ci 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, 2362306a36Sopenharmony_ci 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, 2462306a36Sopenharmony_ci 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, 2562306a36Sopenharmony_ci 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, 2662306a36Sopenharmony_ci 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, 2762306a36Sopenharmony_ci 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, 2862306a36Sopenharmony_ci 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, 2962306a36Sopenharmony_ci 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, 3062306a36Sopenharmony_ci 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, 3162306a36Sopenharmony_ci 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, 3262306a36Sopenharmony_ci 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, 3362306a36Sopenharmony_ci 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, 3462306a36Sopenharmony_ci 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, 3562306a36Sopenharmony_ci 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, 3662306a36Sopenharmony_ci 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, 3762306a36Sopenharmony_ci 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, 3862306a36Sopenharmony_ci 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, 3962306a36Sopenharmony_ci 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, 4062306a36Sopenharmony_ci 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, 4162306a36Sopenharmony_ci 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, 4262306a36Sopenharmony_ci 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, 4362306a36Sopenharmony_ci 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, 4462306a36Sopenharmony_ci 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, 4562306a36Sopenharmony_ci 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, 4662306a36Sopenharmony_ci 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, 4762306a36Sopenharmony_ci 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, 4862306a36Sopenharmony_ci 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47, 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciunsigned int intlog2(u32 value) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci /** 5462306a36Sopenharmony_ci * returns: log2(value) * 2^24 5562306a36Sopenharmony_ci * wrong result if value = 0 (log2(0) is undefined) 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci unsigned int msb; 5862306a36Sopenharmony_ci unsigned int logentry; 5962306a36Sopenharmony_ci unsigned int significand; 6062306a36Sopenharmony_ci unsigned int interpolation; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (unlikely(value == 0)) { 6362306a36Sopenharmony_ci WARN_ON(1); 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* first detect the msb (count begins at 0) */ 6862306a36Sopenharmony_ci msb = fls(value) - 1; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /** 7162306a36Sopenharmony_ci * now we use a logtable after the following method: 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 7462306a36Sopenharmony_ci * where x = msb and therefore 1 <= y < 2 7562306a36Sopenharmony_ci * first y is determined by shifting the value left 7662306a36Sopenharmony_ci * so that msb is bit 31 7762306a36Sopenharmony_ci * 0x00231f56 -> 0x8C7D5800 7862306a36Sopenharmony_ci * the result is y * 2^31 -> "significand" 7962306a36Sopenharmony_ci * then the highest 9 bits are used for a table lookup 8062306a36Sopenharmony_ci * the highest bit is discarded because it's always set 8162306a36Sopenharmony_ci * the highest nine bits in our example are 100011000 8262306a36Sopenharmony_ci * so we would use the entry 0x18 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci significand = value << (31 - msb); 8562306a36Sopenharmony_ci logentry = (significand >> 23) % ARRAY_SIZE(logtable); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /** 8862306a36Sopenharmony_ci * last step we do is interpolation because of the 8962306a36Sopenharmony_ci * limitations of the log table the error is that part of 9062306a36Sopenharmony_ci * the significand which isn't used for lookup then we 9162306a36Sopenharmony_ci * compute the ratio between the error and the next table entry 9262306a36Sopenharmony_ci * and interpolate it between the log table entry used and the 9362306a36Sopenharmony_ci * next one the biggest error possible is 0x7fffff 9462306a36Sopenharmony_ci * (in our example it's 0x7D5800) 9562306a36Sopenharmony_ci * needed value for next table entry is 0x800000 9662306a36Sopenharmony_ci * so the interpolation is 9762306a36Sopenharmony_ci * (error / 0x800000) * (logtable_next - logtable_current) 9862306a36Sopenharmony_ci * in the implementation the division is moved to the end for 9962306a36Sopenharmony_ci * better accuracy there is also an overflow correction if 10062306a36Sopenharmony_ci * logtable_next is 256 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci interpolation = ((significand & 0x7fffff) * 10362306a36Sopenharmony_ci ((logtable[(logentry + 1) % ARRAY_SIZE(logtable)] - 10462306a36Sopenharmony_ci logtable[logentry]) & 0xffff)) >> 15; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* now we return the result */ 10762306a36Sopenharmony_ci return ((msb << 24) + (logtable[logentry] << 8) + interpolation); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ciEXPORT_SYMBOL(intlog2); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciunsigned int intlog10(u32 value) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci /** 11462306a36Sopenharmony_ci * returns: log10(value) * 2^24 11562306a36Sopenharmony_ci * wrong result if value = 0 (log10(0) is undefined) 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci u64 log; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (unlikely(value == 0)) { 12062306a36Sopenharmony_ci WARN_ON(1); 12162306a36Sopenharmony_ci return 0; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci log = intlog2(value); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /** 12762306a36Sopenharmony_ci * we use the following method: 12862306a36Sopenharmony_ci * log10(x) = log2(x) * log10(2) 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return (log * 646456993) >> 31; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ciEXPORT_SYMBOL(intlog10); 134