source: mainline/uspace/lib/math/generic/atan.c@ c280d7e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c280d7e was b69786e, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Add all functions required by C89 plus their single-precision variants from C99.

  • Property mode set to 100644
File size: 3.7 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
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 <atan.h>
36#include <errno.h>
37#include <math.h>
38
39#define SERIES_DEGREE_32 13
40#define SERIES_DEGREE_64 33
41
42/** Inverse tangent approximation by Euler's series (32-bit floating point)
43 *
44 * Compute the approximation of inverse tangent by a
45 * series found by Leonhard Euler (using the first SERIES_DEGREE terms).
46 *
47 * @param arg Inverse tangent argument.
48 *
49 * @return Inverse tangent value approximation.
50 *
51 */
52static float32_t series_atan_32(float32_t arg)
53{
54 float32_t sum = 0;
55 float32_t a = arg / (1.0 + arg * arg);
56
57 /*
58 * atan(z) = sum(n=0, +inf) [ (2^2n) * (n!)^2 / (2n + 1)! *
59 * z^(2n+1) / (1 + z^2)^(n+1) ]
60 */
61
62 for (unsigned int n = 0; n < SERIES_DEGREE_32; n++) {
63 if (n > 0) {
64 a = a * n * n;
65 a = a / (2.0 * n + 1.0) / (2.0 * n);
66 }
67 sum += a;
68 a = a * 4.0 * arg * arg / (1.0 + arg * arg);
69 }
70
71 return sum;
72}
73
74/** Inverse tangent approximation by Euler's series (64-bit floating point)
75 *
76 * Compute the approximation of inverse tangent by a
77 * series found by Leonhard Euler (using the first SERIES_DEGREE terms).
78 *
79 * @param arg Inverse tangent argument.
80 *
81 * @return Inverse tangent value approximation.
82 *
83 */
84static float64_t series_atan_64(float64_t arg)
85{
86 float64_t sum = 0;
87 float64_t a = arg / (1.0 + arg * arg);
88
89 /*
90 * atan(z) = sum(n=0, +inf) [ (2^2n) * (n!)^2 / (2n + 1)! *
91 * z^(2n+1) / (1 + z^2)^(n+1) ]
92 */
93
94 for (unsigned int n = 0; n < SERIES_DEGREE_64; n++) {
95 if (n > 0) {
96 a = a * n * n;
97 a = a / (2.0 * n + 1.0) / (2.0 * n);
98 }
99 sum += a;
100 a = a * 4.0 * arg * arg / (1.0 + arg * arg);
101 }
102
103 return sum;
104}
105
106/** Inverse tangent (32-bit floating point)
107 *
108 * Compute inverse sine value.
109 *
110 * @param arg Inverse sine argument.
111 *
112 * @return Inverse sine value.
113 *
114 */
115float32_t float32_atan(float32_t arg)
116{
117 if (arg < -1.0 || arg > 1.0)
118 return 2.0 * series_atan_32(arg / (1.0 + sqrt_f32(1.0 + arg*arg)));
119 else
120 return series_atan_32(arg);
121}
122
123/** Inverse tangent (64-bit floating point)
124 *
125 * Compute inverse sine value.
126 *
127 * @param arg Inverse sine argument.
128 *
129 * @return Inverse sine value.
130 *
131 */
132float64_t float64_atan(float64_t arg)
133{
134 if (arg < -1.0 || arg > 1.0)
135 return 2.0 * series_atan_64(arg / (1.0 + sqrt_f64(1.0 + arg*arg)));
136 else
137 return series_atan_64(arg);
138}
139
140/** @}
141 */
Note: See TracBrowser for help on using the repository browser.