Kstars

cachingdms.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Akarsh Simha <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 /* Project Includes */
8 #include "cachingdms.h"
9 
10 /* KDE Includes */
11 
12 /* Qt Includes */
13 #include <QString>
14 
15 /* STL Includes */
16 #include <cmath>
17 
18 #ifdef COUNT_DMS_SINCOS_CALLS
19 unsigned long CachingDms::cachingdms_constructor_calls = 0;
20 long CachingDms::cachingdms_delta = 0; // difference of ( trig function calls ) - ( trig computations )
21 unsigned long CachingDms::cachingdms_bad_uses = 0;
22 #endif
23 
24 CachingDms::CachingDms(const double &x) : dms(x)
25 {
26  dms::SinCos(m_sin, m_cos);
27 #ifdef COUNT_DMS_SINCOS_CALLS
28  ++cachingdms_constructor_calls;
29  cachingdms_delta -= 2;
30  m_cacheUsed = false;
31 #endif
32 }
33 
34 #ifdef COUNT_DMS_SINCOS_CALLS
35 CachingDms::~CachingDms()
36 {
37  if (!m_cacheUsed)
38  ++cachingdms_bad_uses;
39 }
40 #endif
41 
42 CachingDms::CachingDms(const QString &s, bool isDeg) : dms(s, isDeg)
43 {
44  dms::SinCos(m_sin, m_cos);
45 #ifdef COUNT_DMS_SINCOS_CALLS
46  ++cachingdms_constructor_calls;
47  cachingdms_delta -= 2;
48  m_cacheUsed = false;
49 #endif
50 }
51 
52 CachingDms::CachingDms(const int &d, const int &m, const int &s, const int &ms) : dms(d, m, s, ms)
53 {
54  dms::SinCos(m_sin, m_cos);
55 #ifdef COUNT_DMS_SINCOS_CALLS
56  ++cachingdms_constructor_calls;
57  cachingdms_delta -= 2;
58  m_cacheUsed = false;
59 #endif
60 }
61 
62 void CachingDms::setUsing_atan2(const double &y, const double &x)
63 {
64  /*
65  * NOTE: A bit of independent profiling shows that on my machine
66  * (Intel Core i5, x86_64, glibc 2.24-2) the square-root based
67  * computation below has some advantage, running ~ 70% faster on
68  * average for some range of values.
69  *
70  */
71  dms::setRadians(atan2(y, x));
72  double r = sqrt(y * y + x * x);
73  m_cos = x / r;
74  m_sin = y / r;
75 
76 #ifdef COUNT_DMS_SINCOS_CALLS
77  if (!m_cacheUsed)
78  ++cachingdms_bad_uses;
79  m_cacheUsed = false;
80 #endif
81  // One may be tempted to do the following:
82  // dms::setRadians( atan2( y, x ) );
83  // m_cos = dms::cos();
84  // m_sin = (y/x) * m_cos;
85  // However, this has a problem when x = 0. The result for m_sin
86  // must be 1, but instead the above code will result in NaN.
87  // So we will need a conditional:
88  // m_sin = (x == 0) ? 1. : (y/x) * m_cos;
89  // The conditional makes the performance worse than just setting
90  // the angle and using sincos()
91 }
92 
93 void CachingDms::setUsing_asin(const double &sine)
94 {
95  dms::setRadians(asin(sine));
96  m_sin = sine;
97  // Note: The below is valid because in the range of asin, which is
98  // [-pi/2, pi/2], cosine is always non-negative
99  m_cos = std::sqrt(1 - sine * sine);
100 #ifdef COUNT_DMS_SINCOS_CALLS
101  if (!m_cacheUsed)
102  ++cachingdms_bad_uses;
103  m_cacheUsed = false;
104 #endif
105 }
106 
107 void CachingDms::setUsing_acos(const double &cosine)
108 {
109  dms::setRadians(acos(cosine));
110  m_cos = cosine;
111  // Note: The below is valid because in the range of acos, which is
112  // [0, pi], sine is always non-negative
113  m_sin = std::sqrt(1 - cosine * cosine);
114 #ifdef COUNT_DMS_SINCOS_CALLS
115  if (!m_cacheUsed)
116  ++cachingdms_bad_uses;
117  m_cacheUsed = false;
118 #endif
119 }
120 
122 {
123  CachingDms result;
124  result.setFromString(s, deg);
125  return result;
126 }
127 
129 {
130  return CachingDms(-D, -m_sin, m_cos);
131 }
132 
134 {
135  D = angle.Degrees();
136  dms::SinCos(m_sin, m_cos);
137 #ifdef COUNT_DMS_SINCOS_CALLS
138  ++cachingdms_constructor_calls;
139  cachingdms_delta -= 2;
140  m_cacheUsed = false;
141 #endif
142 }
143 
144 #ifdef COUNT_DMS_SINCOS_CALLS
146 {
147  m_sin = o.sin();
148  m_cos = o.cos();
149  D = o.D;
150  m_cacheUsed = false;
151 }
152 CachingDms &CachingDms::operator=(const CachingDms &o)
153 {
154  if (!m_cacheUsed)
155  ++cachingdms_bad_uses;
156  m_sin = o.sin();
157  m_cos = o.cos();
158  D = o.D;
159  m_cacheUsed = false;
160  return (*this);
161 }
162 #endif
163 
164 // Makes trig identities more readable:
165 #define sinA a.sin()
166 #define cosA a.cos()
167 #define sinB b.sin()
168 #define cosB b.cos()
169 
170 // We use trigonometric addition / subtraction formulae to speed up
171 // computation. This way, we have no trigonometric function calls at
172 // all, but only floating point multiplications and
173 // addition/subtraction instead.
174 // The only caveat is that error can accumulate if used repeatedly!
175 
177 {
178  return CachingDms(a.Degrees() + b.Degrees(), sinA * cosB + cosA * sinB, cosA * cosB - sinA * sinB);
179 }
180 
181 CachingDms operator-(const CachingDms &a, const CachingDms &b)
182 {
183  return CachingDms(a.Degrees() - b.Degrees(), sinA * cosB - cosA * sinB, cosA * cosB + sinA * sinB);
184 }
185 
186 CachingDms operator+(const dms &a, const CachingDms &b)
187 {
188  return CachingDms(a + dms(b));
189 }
190 
191 CachingDms operator-(const dms &a, const CachingDms &b)
192 {
193  return CachingDms(a - dms(b));
194 }
195 
196 CachingDms operator+(const CachingDms &a, const dms &b)
197 {
198  return CachingDms(dms(a) + b);
199 }
200 
201 CachingDms operator-(const CachingDms &a, const dms &b)
202 {
203  return CachingDms(dms(a) - b);
204 }
205 
206 #undef sinA
207 #undef cosA
208 #undef sinB
209 #undef cosB
double sin() const
Get the sine of this angle.
Definition: cachingdms.h:190
void setUsing_atan2(const double &y, const double &x)
Sets the angle using atan2()
Definition: cachingdms.cpp:62
a dms subclass that caches its sine and cosine values every time the angle is changed.
Definition: cachingdms.h:18
void SinCos(double &s, double &c) const
Compute Sine and Cosine of the angle simultaneously.
Definition: dms.h:444
CachingDms()
Default Constructor.
Definition: cachingdms.h:24
const QCA_EXPORT SecureArray operator+(const SecureArray &a, const SecureArray &b)
double cos() const
Get the cosine of this angle.
Definition: cachingdms.h:204
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
virtual void setRadians(const double &Rad)
Set angle according to the argument, in radians.
Definition: dms.h:333
static CachingDms fromString(const QString &s, bool deg)
Construct an angle from the given string.
Definition: cachingdms.cpp:121
CachingDms operator-()
operator -
Definition: cachingdms.cpp:128
const double & Degrees() const
Definition: dms.h:141
void setUsing_acos(const double &cosine)
Sets the angle using acos()
Definition: cachingdms.cpp:107
bool setFromString(const QString &s, bool isDeg=true) override
Sets the angle from string.
Definition: cachingdms.h:120
void setUsing_asin(const double &sine)
Sets the angle using asin()
Definition: cachingdms.cpp:93
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Sep 26 2023 03:55:44 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.