-
Notifications
You must be signed in to change notification settings - Fork 4
/
icomplex.h
112 lines (93 loc) · 3.45 KB
/
icomplex.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#ifndef __icomplex_H
#define __icomplex_H
/*
* Copyright (c) 2019 Stephen Williams ([email protected])
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* The icomplex<> template implements fixed precision (integer)
* complex numbers. The template is parameterized by the base integer
* type to use (i.e. int16_t, int32_t, int64_t) and the number of
* bits of the base integer type to use as fraction bits.
*/
# include <complex>
# include <cassert>
# include <cmath>
template <class TYPE, unsigned FRAC> class icomplex {
public: // Various constructors.
inline icomplex()
: real_(0), imag_(0)
{ }
inline icomplex(const icomplex<TYPE,FRAC>&that)
: real_(that.real_), imag_(that.imag_)
{ }
inline icomplex(TYPE rv, TYPE iv)
: real_(rv), imag_(iv)
{ }
inline icomplex(double rv, double iv = 0.0)
: real_(rv * (1<<FRAC) + 0.5), imag_(iv * (1<<FRAC) + 0.5)
{ }
inline icomplex(const std::complex<double>&that)
: real_(that.real() * (1<<FRAC) + 0.5), imag_(that.imag() * (1<<FRAC) + 0.5)
{ }
public: // Assignment operators.
inline icomplex<TYPE,FRAC>& operator = (const icomplex<TYPE,FRAC>&that)
{
real_ = that.real_;
imag_ = that.imag_;
return *this;
}
inline icomplex<TYPE,FRAC>& operator += (const icomplex<TYPE,FRAC>&that)
{
real_ += that.real_;
imag_ += that.imag_;
return *this;
}
public:
// These methods return the raw bits of the real and imaginary
// components. It is up to the user to interpret the fraction bits.
inline TYPE real(void) const { return real_; }
inline TYPE imag(void) const { return imag_; }
// These methods access the real and imaginary parts as
// doubles. This properly interprets the fractional part.
inline double d_real(void) const { return (double)real_ / (1 << FRAC); }
inline double d_imag(void) const { return (double)imag_ / (1 << FRAC); }
private:
TYPE real_;
TYPE imag_;
};
template <class TYPE, unsigned FRAC>
inline class icomplex<TYPE,FRAC> operator + (icomplex<TYPE,FRAC>a, icomplex<TYPE,FRAC>b)
{
return icomplex<TYPE,FRAC> (a.real()+b.real(), a.imag()+b.imag());
}
template <class TYPE, unsigned FRAC>
inline class icomplex<TYPE,FRAC> operator * (icomplex<TYPE,FRAC>a, icomplex<TYPE,FRAC>b)
{
int64_t rtmp;
rtmp = (a.real() * b.real());
rtmp -= (a.imag() * b.imag());
rtmp /= 1<<FRAC;
assert(log2(abs(rtmp)) < (8*sizeof(TYPE)));
int64_t itmp;
itmp = (a.real() * b.imag());
itmp += (a.imag() * b.real());
itmp /= 1<<FRAC;
assert(log2(abs(itmp)) < (8*sizeof(TYPE)));
return icomplex<TYPE,FRAC> ((TYPE)rtmp, (TYPE)itmp);
}
#endif