Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 #ifndef _FIXP_ARITH_H
0003 #define _FIXP_ARITH_H
0004 
0005 #include <linux/math64.h>
0006 
0007 /*
0008  * Simplistic fixed-point arithmetics.
0009  * Hmm, I'm probably duplicating some code :(
0010  *
0011  * Copyright (c) 2002 Johann Deneux
0012  */
0013 
0014 /*
0015  *
0016  * Should you need to contact me, the author, you can do so by
0017  * e-mail - mail your message to <johann.deneux@gmail.com>
0018  */
0019 
0020 #include <linux/types.h>
0021 
0022 static const s32 sin_table[] = {
0023     0x00000000, 0x023be165, 0x04779632, 0x06b2f1d2, 0x08edc7b6, 0x0b27eb5c,
0024     0x0d61304d, 0x0f996a26, 0x11d06c96, 0x14060b67, 0x163a1a7d, 0x186c6ddd,
0025     0x1a9cd9ac, 0x1ccb3236, 0x1ef74bf2, 0x2120fb82, 0x234815ba, 0x256c6f9e,
0026     0x278dde6e, 0x29ac379f, 0x2bc750e8, 0x2ddf003f, 0x2ff31bdd, 0x32037a44,
0027     0x340ff241, 0x36185aee, 0x381c8bb5, 0x3a1c5c56, 0x3c17a4e7, 0x3e0e3ddb,
0028     0x3fffffff, 0x41ecc483, 0x43d464fa, 0x45b6bb5d, 0x4793a20f, 0x496af3e1,
0029     0x4b3c8c11, 0x4d084650, 0x4ecdfec6, 0x508d9210, 0x5246dd48, 0x53f9be04,
0030     0x55a6125a, 0x574bb8e5, 0x58ea90c2, 0x5a827999, 0x5c135399, 0x5d9cff82,
0031     0x5f1f5ea0, 0x609a52d1, 0x620dbe8a, 0x637984d3, 0x64dd894f, 0x6639b039,
0032     0x678dde6d, 0x68d9f963, 0x6a1de735, 0x6b598ea1, 0x6c8cd70a, 0x6db7a879,
0033     0x6ed9eba0, 0x6ff389de, 0x71046d3c, 0x720c8074, 0x730baeec, 0x7401e4bf,
0034     0x74ef0ebb, 0x75d31a5f, 0x76adf5e5, 0x777f903b, 0x7847d908, 0x7906c0af,
0035     0x79bc384c, 0x7a6831b8, 0x7b0a9f8c, 0x7ba3751c, 0x7c32a67c, 0x7cb82884,
0036     0x7d33f0c8, 0x7da5f5a3, 0x7e0e2e31, 0x7e6c924f, 0x7ec11aa3, 0x7f0bc095,
0037     0x7f4c7e52, 0x7f834ecf, 0x7fb02dc4, 0x7fd317b3, 0x7fec09e1, 0x7ffb025e,
0038     0x7fffffff
0039 };
0040 
0041 /**
0042  * __fixp_sin32() returns the sin of an angle in degrees
0043  *
0044  * @degrees: angle, in degrees, from 0 to 360.
0045  *
0046  * The returned value ranges from -0x7fffffff to +0x7fffffff.
0047  */
0048 static inline s32 __fixp_sin32(int degrees)
0049 {
0050     s32 ret;
0051     bool negative = false;
0052 
0053     if (degrees > 180) {
0054         negative = true;
0055         degrees -= 180;
0056     }
0057     if (degrees > 90)
0058         degrees = 180 - degrees;
0059 
0060     ret = sin_table[degrees];
0061 
0062     return negative ? -ret : ret;
0063 }
0064 
0065 /**
0066  * fixp_sin32() returns the sin of an angle in degrees
0067  *
0068  * @degrees: angle, in degrees. The angle can be positive or negative
0069  *
0070  * The returned value ranges from -0x7fffffff to +0x7fffffff.
0071  */
0072 static inline s32 fixp_sin32(int degrees)
0073 {
0074     degrees = (degrees % 360 + 360) % 360;
0075 
0076     return __fixp_sin32(degrees);
0077 }
0078 
0079 /* cos(x) = sin(x + 90 degrees) */
0080 #define fixp_cos32(v) fixp_sin32((v) + 90)
0081 
0082 /*
0083  * 16 bits variants
0084  *
0085  * The returned value ranges from -0x7fff to 0x7fff
0086  */
0087 
0088 #define fixp_sin16(v) (fixp_sin32(v) >> 16)
0089 #define fixp_cos16(v) (fixp_cos32(v) >> 16)
0090 
0091 /**
0092  * fixp_sin32_rad() - calculates the sin of an angle in radians
0093  *
0094  * @radians: angle, in radians
0095  * @twopi: value to be used for 2*pi
0096  *
0097  * Provides a variant for the cases where just 360
0098  * values is not enough. This function uses linear
0099  * interpolation to a wider range of values given by
0100  * twopi var.
0101  *
0102  * Experimental tests gave a maximum difference of
0103  * 0.000038 between the value calculated by sin() and
0104  * the one produced by this function, when twopi is
0105  * equal to 360000. That seems to be enough precision
0106  * for practical purposes.
0107  *
0108  * Please notice that two high numbers for twopi could cause
0109  * overflows, so the routine will not allow values of twopi
0110  * bigger than 1^18.
0111  */
0112 static inline s32 fixp_sin32_rad(u32 radians, u32 twopi)
0113 {
0114     int degrees;
0115     s32 v1, v2, dx, dy;
0116     s64 tmp;
0117 
0118     /*
0119      * Avoid too large values for twopi, as we don't want overflows.
0120      */
0121     BUG_ON(twopi > 1 << 18);
0122 
0123     degrees = (radians * 360) / twopi;
0124     tmp = radians - (degrees * twopi) / 360;
0125 
0126     degrees = (degrees % 360 + 360) % 360;
0127     v1 = __fixp_sin32(degrees);
0128 
0129     v2 = fixp_sin32(degrees + 1);
0130 
0131     dx = twopi / 360;
0132     dy = v2 - v1;
0133 
0134     tmp *= dy;
0135 
0136     return v1 +  div_s64(tmp, dx);
0137 }
0138 
0139 /* cos(x) = sin(x + pi/2 radians) */
0140 
0141 #define fixp_cos32_rad(rad, twopi)  \
0142     fixp_sin32_rad(rad + twopi / 4, twopi)
0143 
0144 /**
0145  * fixp_linear_interpolate() - interpolates a value from two known points
0146  *
0147  * @x0: x value of point 0
0148  * @y0: y value of point 0
0149  * @x1: x value of point 1
0150  * @y1: y value of point 1
0151  * @x: the linear interpolant
0152  */
0153 static inline int fixp_linear_interpolate(int x0, int y0, int x1, int y1, int x)
0154 {
0155     if (y0 == y1 || x == x0)
0156         return y0;
0157     if (x1 == x0 || x == x1)
0158         return y1;
0159 
0160     return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
0161 }
0162 
0163 #endif