1 /*-
2  * Copyright (c) 2014-2018 Carsten Sonne Larsen <cs@innolan.net>
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  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * Project homepage:
26  * https://amath.innolan.net
27  *
28  */
29 
30 #include "prim.h"
31 
32 #define REAL_PART(z) ((z).parts[0])
33 #define IMAG_PART(z) ((z).parts[1])
34 
35 /**
36  * @brief Real part of complex number
37  */
creal(complex z)38 double creal(complex z)
39 {
40     return (REAL_PART(z));
41 }
42 
43 /**
44  * @brief Imaginary part of complex number
45  */
cimag(complex z)46 double cimag(complex z)
47 {
48     return (IMAG_PART(z));
49 }
50 
51 /**
52  * @brief Absolute value of complex number
53  */
cabs(complex z)54 double cabs(complex z)
55 {
56     return hypot(creal(z), cimag(z));
57 }
58 
conj(complex z)59 complex conj(complex z)
60 {
61     IMAG_PART(z) = -IMAG_PART(z);
62     return cpack(REAL_PART(z), IMAG_PART(z));
63 }
64 
65 /**
66  * @brief Pack two real numbers into a complex number
67  */
cpack(double x,double y)68 complex cpack(double x, double y)
69 {
70     complex z;
71 
72     REAL_PART(z) = x;
73     IMAG_PART(z) = y;
74     return (z);
75 }
76 
77 /**
78  * @brief Truncated value of complex number
79  */
ctrunc(complex z)80 complex ctrunc(complex z)
81 {
82     complex w;
83     w = cpack(trunc(creal(z)), trunc(cimag(z)));
84     return w;
85 }
86 
87 /**
88  * @brief Floor value of complex number
89  */
cfloor(complex z)90 complex cfloor(complex z)
91 {
92     complex w;
93     w = cpack(floor(creal(z)), floor(cimag(z)));
94     return w;
95 }
96 
97 /**
98  * @brief Ceiling value of complex number
99  */
cceil(complex z)100 complex cceil(complex z)
101 {
102     complex w;
103     w = cpack(ceil(creal(z)), ceil(cimag(z)));
104     return w;
105 }
106 
107 /**
108  * @brief Division of two complex numbers
109  */
cround(complex z)110 complex cround(complex z)
111 {
112     complex w;
113     w = cpack(round(creal(z)), round(cimag(z)));
114     return w;
115 }
116 
117 /**
118  * @brief Addition of two complex numbers
119  */
cadd(complex y,complex z)120 complex cadd(complex y, complex z)
121 {
122     complex w;
123     w = cpack(creal(y) + creal(z), cimag(y) + cimag(z));
124     return w;
125 }
126 
127 /**
128  * @brief Subtraction of two complex numbers
129  */
csub(complex y,complex z)130 complex csub(complex y, complex z)
131 {
132     complex w;
133     w = cpack(creal(y) - creal(z), cimag(y) - cimag(z));
134     return w;
135 }
136 
137 /**
138  * @brief Multiplication of two complex numbers
139  */
cmul(complex y,complex z)140 complex cmul(complex y, complex z)
141 {
142     complex w;
143     double a, b, c, d;
144 
145     // (a+bi)(c+di)
146     a = creal(y);
147     b = cimag(y);
148     c = creal(z);
149     d = cimag(z);
150 
151     // (ac -bd) + (ad + bc)i
152     w = cpack(a * c - b * d, a * d + b * c);
153     return w;
154 }
155 
156 /**
157  * @brief Division of two complex numbers
158  */
cdiv(complex y,complex z)159 complex cdiv(complex y, complex z)
160 {
161     complex w;
162     double a, b, c, d;
163     double q, v, x;
164 
165     a = creal(y);
166     b = cimag(y);
167     c = creal(z);
168     d = cimag(z);
169 
170     q = c * c + d * d;
171     v = a * c + b * d;
172     x = b * c - a * d;
173 
174     w = cpack(v / q, x / q);
175     return w;
176 }
177 
178 /**
179  * @brief Reciprocal value of complex number
180  */
creci(complex z)181 complex creci(complex z)
182 {
183     complex w;
184     double q, a, b;
185 
186     a = creal(z);
187     b = cimag(conj(z));
188     q = a * a + b * b;
189     w = cpack(a / q, b / q);
190 
191     return w;
192 }
193 
194 /**
195  * @brief Calculate cosh and sinh
196  */
cchsh(double x,double * c,double * s)197 void cchsh(double x, double* c, double* s)
198 {
199     double e, ei;
200 
201     if (fabs(x) <= 0.5)
202     {
203         *c = cosh(x);
204         *s = sinh(x);
205     }
206     else
207     {
208         e = exp(x);
209         ei = 0.5 / e;
210         e = 0.5 * e;
211         *s = e - ei;
212         *c = e + ei;
213     }
214 }
215 
216 /**
217  * @brief Calculate cosh and cos
218  */
cchc(double x,double * ch,double * c)219 void cchc(double x, double* ch, double* c)
220 {
221     *ch = cosh(2.0 * x);
222     *c = cos(2.0 * x);
223 }
224