xref: /openbmc/linux/lib/math/int_log.c (revision 08f6a14b2d376e96cb7166694193ec3c3a496d25)
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