source: mainline/uspace/lib/math/generic/trig.c@ c0c38c7c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c0c38c7c was c0c38c7c, checked in by Martin Decky <martin@…>, 10 years ago

software floating point overhaul
use proper type mapping
fix cosine calculation

  • Property mode set to 100644
File size: 4.8 KB
Line 
1/*
2 * Copyright (c) 2014 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libmath
30 * @{
31 */
32/** @file
33 */
34
35#include <math.h>
36#include <trig.h>
37
38#define TAYLOR_DEGREE 13
39
40/** Precomputed values for factorial (starting from 1!) */
41static float64_t factorials[TAYLOR_DEGREE] = {
42 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800,
43 479001600, 6227020800
44};
45
46/** Sine approximation by Taylor series
47 *
48 * Compute the approximation of sine by a Taylor
49 * series (using the first TAYLOR_DEGREE terms).
50 * The approximation is reasonably accurate for
51 * arguments within the interval [-pi/4, pi/4].
52 *
53 * @param arg Sine argument.
54 *
55 * @return Sine value approximation.
56 *
57 */
58static float64_t taylor_sin(float64_t arg)
59{
60 float64_t ret = 0;
61 float64_t nom = 1;
62
63 for (unsigned int i = 0; i < TAYLOR_DEGREE; i++) {
64 nom *= arg;
65
66 if ((i % 4) == 0)
67 ret += nom / factorials[i];
68 else if ((i % 4) == 2)
69 ret -= nom / factorials[i];
70 }
71
72 return ret;
73}
74
75/** Cosine approximation by Taylor series
76 *
77 * Compute the approximation of cosine by a Taylor
78 * series (using the first TAYLOR_DEGREE terms).
79 * The approximation is reasonably accurate for
80 * arguments within the interval [-pi/4, pi/4].
81 *
82 * @param arg Cosine argument.
83 *
84 * @return Cosine value approximation.
85 *
86 */
87static float64_t taylor_cos(float64_t arg)
88{
89 float64_t ret = 1;
90 float64_t nom = 1;
91
92 for (unsigned int i = 0; i < TAYLOR_DEGREE; i++) {
93 nom *= arg;
94
95 if ((i % 4) == 1)
96 ret -= nom / factorials[i];
97 else if ((i % 4) == 3)
98 ret += nom / factorials[i];
99 }
100
101 return ret;
102}
103
104/** Sine value for values within base period
105 *
106 * Compute the value of sine for arguments within
107 * the base period [0, 2pi]. For arguments outside
108 * the base period the returned values can be
109 * very inaccurate or even completely wrong.
110 *
111 * @param arg Sine argument.
112 *
113 * @return Sine value.
114 *
115 */
116static float64_t base_sin(float64_t arg)
117{
118 unsigned int period = arg / (M_PI / 4);
119
120 switch (period) {
121 case 0:
122 return taylor_sin(arg);
123 case 1:
124 case 2:
125 return taylor_cos(arg - M_PI / 2);
126 case 3:
127 case 4:
128 return -taylor_sin(arg - M_PI);
129 case 5:
130 case 6:
131 return -taylor_cos(arg - 3 * M_PI / 2);
132 default:
133 return taylor_sin(arg - 2 * M_PI);
134 }
135}
136
137/** Cosine value for values within base period
138 *
139 * Compute the value of cosine for arguments within
140 * the base period [0, 2pi]. For arguments outside
141 * the base period the returned values can be
142 * very inaccurate or even completely wrong.
143 *
144 * @param arg Cosine argument.
145 *
146 * @return Cosine value.
147 *
148 */
149static float64_t base_cos(float64_t arg)
150{
151 unsigned int period = arg / (M_PI / 4);
152
153 switch (period) {
154 case 0:
155 return taylor_cos(arg);
156 case 1:
157 case 2:
158 return -taylor_sin(arg - M_PI / 2);
159 case 3:
160 case 4:
161 return -taylor_cos(arg - M_PI);
162 case 5:
163 case 6:
164 return taylor_sin(arg - 3 * M_PI / 2);
165 default:
166 return taylor_cos(arg - 2 * M_PI);
167 }
168}
169
170/** Double precision sine
171 *
172 * Compute sine value.
173 *
174 * @param arg Sine argument.
175 *
176 * @return Sine value.
177 *
178 */
179float64_t float64_sin(float64_t arg)
180{
181 float64_t base_arg = fmod(arg, 2 * M_PI);
182
183 if (base_arg < 0)
184 return -base_sin(-base_arg);
185
186 return base_sin(base_arg);
187}
188
189/** Double precision cosine
190 *
191 * Compute cosine value.
192 *
193 * @param arg Cosine argument.
194 *
195 * @return Cosine value.
196 *
197 */
198float64_t float64_cos(float64_t arg)
199{
200 float64_t base_arg = fmod(arg, 2 * M_PI);
201
202 if (base_arg < 0)
203 return base_cos(-base_arg);
204
205 return base_cos(base_arg);
206}
207
208/** @}
209 */
Note: See TracBrowser for help on using the repository browser.