PScalar.h
1 /* Distributed under the Apache License, Version 2.0.
2  See accompanying NOTICE file for details.*/
3 
4 //----------------------------------------------------------------------------
13 //----------------------------------------------------------------------------
14 
15 #pragma once
16 
17 class CPScalar
18 {
19 public:
20  // Default ctor
22  :m_dValue(0.0)
23  {
24  // Do nothing
25  }
26 
27  // Construct from value and string unit spec
28  CPScalar(double val, const std::string &unitSpec)
29  :m_dValue(val), m_CCU(unitSpec)
30  {
31  // Do nothing
32  }
33 
34  // Construct from value. No units.
35  explicit CPScalar(double val)
36  :m_dValue(val)
37  {
38  // Do nothing
39  }
40 
41  // Construct from string unit. Initial value is 1.0 so that we can multiply by a pure
42  // unit specification.
43  CPScalar(const std::string &unitSpec)
44  :m_dValue(1.0), m_CCU(unitSpec)
45  {
46  // Do nothing
47  }
48 
49  // Copy ctor
50  CPScalar(const CPScalar &src)
51  :m_dValue(src.m_dValue), m_CCU(src.m_CCU)
52  {
53  // Do nothing
54  }
55 
56  // Overload arithmetic operators in the proper fashion.
57  CPScalar & operator=(const CPScalar &rhs)
58  {
59  if (this != &rhs)
60  {
61  m_dValue = rhs.m_dValue;
62  m_CCU = rhs.m_CCU;
63  }
64  return *this;
65  }
66 
68  {
69  m_dValue *= rhs.m_dValue;
70  m_CCU *= rhs.m_CCU;
71  return *this;
72  }
73 
75  {
76  m_dValue /= rhs.m_dValue;
77  m_CCU /= rhs.m_CCU;
78  return *this;
79  }
80 
81  CPScalar operator*(const CPScalar &rhs) const
82  {
83  return CPScalar(*this)*= rhs;
84  }
85 
86  CPScalar operator/(const CPScalar &rhs) const
87  {
88  return CPScalar(*this)/= rhs;
89  }
90 
91  // Addition and subtraction require a little care. Adding values requires
92  // they be in the same units, so we will convert the right hand side operand
93  // to the units of the left hand side. We use the interval conversion function
94  // so that we don't get thrown off by biases in the conversion process
95 
97  {
99  double newVal = uce.ConvertValueInterval(rhs.m_dValue,rhs.m_CCU,m_CCU);
100  m_dValue += newVal;
101  return *this;
102  }
103 
105  {
107  double newVal = uce.ConvertValueInterval(rhs.m_dValue,rhs.m_CCU,m_CCU);
108  m_dValue -= newVal;
109  return *this;
110  }
111 
112  // Use ConvertValue here rather than ConvertValueInterval so that we can
113  // correctly determine that 0 degC == 32 degF
114  bool operator==(const CPScalar &rhs)const
115  {
117  double newVal = uce.ConvertValue(rhs.m_dValue,rhs.m_CCU,m_CCU);
118  return m_dValue == newVal;
119  }
120 
121  // We can implement this in terms of overloaded == because in case of type mismatch, NaN is
122  // returned by the conversion, which "==" will treat as false, and we want "!=" to
123  // yield true in that circumstance
124  bool operator!=(const CPScalar &rhs)const
125  {
126  return !(*this == rhs);
127  }
128 
129  // Instead of implementing < in terms of !(>=), and > in terms of !(<=) (or vice versa),
130  // we provide separate implementations for them all, because we don't want anything
131  // to return true in case of NaN (see above), since NAN is always supposed to have an
132  // unordered result.
133  bool operator<(const CPScalar &rhs)const
134  {
136  double newVal = uce.ConvertValue(rhs.m_dValue,rhs.m_CCU,m_CCU);
137  return m_dValue < newVal;
138  }
139 
140  bool operator>(const CPScalar &rhs)const
141  {
143  double newVal = uce.ConvertValue(rhs.m_dValue,rhs.m_CCU,m_CCU);
144  return m_dValue > newVal;
145  }
146 
147  bool operator<=(const CPScalar &rhs)const
148  {
150  double newVal = uce.ConvertValue(rhs.m_dValue,rhs.m_CCU,m_CCU);
151  return m_dValue <= newVal;
152  }
153 
154  bool operator>=(const CPScalar &rhs)const
155  {
157  double newVal = uce.ConvertValue(rhs.m_dValue,rhs.m_CCU,m_CCU);
158  return m_dValue >= newVal;
159  }
160 
161 
162  CPScalar operator+(const CPScalar &rhs) const
163  {
164  return CPScalar(*this)+= rhs;
165  }
166 
167  CPScalar operator-(const CPScalar &rhs) const
168  {
169  return CPScalar(*this)-= rhs;
170  }
171 
172  CPScalar operator+() const // unary +
173  {
174  return CPScalar(*this); // make a copy anyway!
175  }
176 
177  CPScalar & Negate(void)
178  {
179  m_dValue *= -1.0;
180  return *this;
181  }
182 
183  CPScalar operator-() const // unary -
184  {
185  return CPScalar(*this).Negate();
186  }
187 
188  // conversion operators. Casting to the designated type invokes these functions.
189  operator bool() const
190  {
191  return m_dValue != 0.0;
192  }
193 
194  operator int() const
195  {
196  return static_cast<int>(static_cast<double>(*this));
197  }
198 
199  operator float() const
200  {
201  return static_cast<float>(static_cast<double>(*this));
202  }
203 
204  operator double() const
205  {
206  double newval;
208  static CCompoundUnit unitless(""); // dimensionless unitless CompoundUnit
209  if (*unitless.GetDimension() == *m_CCU.GetDimension())
210  {
211  // We are dimensionless, but we potentially have a scale factor
212  // due to quantity-type cancellation, such as knots/mph. So
213  // convert to *unitless* to incorporate that bigness difference
214  // into the value.
215 
216  newval = uce.ConvertValue(m_dValue, m_CCU, unitless);
217  }
218  else
219  {
220  throw "PScalar value can't be cast to numeric unless already dimensionless!";
221  }
222  return newval;
223  }
224 
225  double GetValue() const
226  {
227  return m_dValue;
228  }
229 
230  // Function call operator! Overload to take a string unit spec and return a new
231  // value equal to the conversion of the current instance to the specified unit.
232  // Usage: myPScalar("newUnit").
233  // This creates a new CPScalar value and does not change the state of the object
234  // upon which it is invoked (unlike the method it calls: ConvertTo)
235  CPScalar operator()(const std::string &unitSpec) const
236  {
237  return CPScalar(*this).ConvertTo(unitSpec);
238  }
239 
240  // Raise myself to a given power
241  // Return reference to self so it can be applied to the temporary created
242  // in implementation of pow(). Same thing below for SQRoot() and sqrt()
243  CPScalar & Raise(double pwr)
244  {
245  m_dValue = pow(m_dValue, pwr);
246  m_CCU.Raise(pwr);
247  return *this;
248  }
249 
250  // Compute square root of myself
251  // This method modifies the current object
253  {
254  // Rather than just invoking Raise(0.5) on ourselves, use sqrt(double) on the
255  // value so that we can take advantage of intrinsic implementations on the X86
256  m_dValue = sqrt(m_dValue);
257  m_CCU.Raise(0.5);
258  return *this;
259  }
260 
261  // Compute absolute value of myself
262  // This method modified the current object
264  {
265  m_dValue = std::abs(m_dValue);
266  return *this;
267  }
268 
269  // Convert this object to a new set of units
270  CPScalar & ConvertTo(const std::string &unitSpec)
271  {
273  CCompoundUnit newUnit(unitSpec);
274  double newval = uce.ConvertValue(m_dValue, m_CCU, newUnit);
275  m_CCU = newUnit;
276  m_dValue = newval;
277  return *this;
278  }
279 
280  // Convert this object to a new set of units
281  CPScalar & ConvertTo(const CCompoundUnit &newUnit)
282  {
284  double newval = uce.ConvertValue(m_dValue, m_CCU, newUnit);
285  m_CCU = newUnit;
286  m_dValue = newval;
287  return *this;
288  }
289 
290  // Convert this object to the units of another object
291  CPScalar & ConvertTo(const CPScalar &target)
292  {
293  return ConvertTo(target.m_CCU);
294  }
295 
296  std::ostream & PrintSelf(std::ostream &output) const
297  {
298  return output << m_dValue << " " << m_CCU;
299  }
300 
301  bool IsSameType(const CPScalar &target) const
302  {
303  return (*m_CCU.GetDimension() == *target.m_CCU.GetDimension());
304  }
305 
306  bool IsDimensionless() const
307  {
308  return m_CCU.IsDimensionless();
309  }
310 
311  // Is this CompoundUnit in "decibel" mode
312  bool IsDecible() const
313  {
314  return m_CCU.IsDecibel();
315  }
316 
317  template <class T>
318  friend CPScalar & operator *=( CPScalar &lhs, const T &rhs);
319  template <class T>
320  friend CPScalar & operator /=( CPScalar &lhs, const T &rhs);
321 
322 private:
323  double m_dValue;
325 };
326 
327 inline CPScalar pow(const CPScalar &baseref, double pwr)
328 {
329  return (CPScalar(baseref)).Raise(pwr);
330 }
331 
332 inline CPScalar pow(const CPScalar &baseref, int pwr)
333 {
334  return (CPScalar(baseref)).Raise(static_cast<double>(pwr));
335 }
336 
337 inline CPScalar sqrt(const CPScalar &argref)
338 {
339  return (CPScalar(argref)).SQRoot();
340 }
341 
342 inline CPScalar abs(const CPScalar &argref)
343 {
344  return (CPScalar(argref)).Abs();
345 }
346 
347 inline std::ostream & operator<<(std::ostream &output, const CPScalar &self)
348 {
349  return self.PrintSelf(output);
350 }
351 
352 // Due to the fact that we have casts to double, etc defined, we can't
353 // rely on the CPScalar(double) constructor to promote non-CPScalar
354 // operands, since the conversion in the other direction is just as
355 // valid, according to the compiler, and therefore ambiguous.
356 // In these templates, "T" can be bool, int, float, double
357 // Each operator has two signatures, one in which the CPScalar
358 // value comes first, and one in which it comes second. In each case,
359 // we construct a CPScalar out of the templated arg and add it to the
360 // existing CPScalar object using the overloaded *member* form of the
361 // operator.
362 // Note that the assignment versions return a reference to the LHS operand
363 
364 // Multiply
365 template <class T>
366 CPScalar operator*(const CPScalar &lhs, const T &rhs)
367 {
368  return lhs * CPScalar(rhs);
369 }
370 
371 template <class T>
372 CPScalar operator*(const T &lhs, const CPScalar &rhs)
373 {
374  return CPScalar(lhs) * rhs;
375 }
376 
377 template <class T>
378 CPScalar & operator *=(CPScalar &lhs, const T &rhs)
379 {
380  lhs.m_dValue *= rhs;
381  return lhs;
382 }
383 
384 // Divide
385 template <class T>
386 CPScalar operator/(const CPScalar &lhs, const T &rhs)
387 {
388  return lhs / CPScalar(rhs);
389 }
390 
391 template <class T>
392 CPScalar operator/(const T &lhs, const CPScalar &rhs)
393 {
394  return CPScalar(lhs) / rhs;
395 }
396 
397 template <class T>
398 CPScalar & operator/=(CPScalar &lhs, const T &rhs)
399 {
400  lhs.m_dValue /= rhs;
401  return lhs;
402 }
403 
404 // Add
405 template <class T>
406 CPScalar operator+(const CPScalar &lhs, const T &rhs)
407 {
408  return lhs + CPScalar(rhs);
409 }
410 
411 template <class T>
412 CPScalar operator+(const T &lhs, const CPScalar &rhs)
413 {
414  return CPScalar(lhs) + rhs;
415 }
416 
417 // Subtract
418 template <class T>
419 CPScalar operator-(const CPScalar &lhs, const T &rhs)
420 {
421  return lhs - CPScalar(rhs);
422 }
423 
424 template <class T>
425 CPScalar operator-(const T &lhs, const CPScalar &rhs)
426 {
427  return CPScalar(lhs) - rhs;
428 }
429 
430 // Less than
431 template <class T>
432 bool operator<(const CPScalar &lhs, const T &rhs)
433 {
434  return lhs < CPScalar(rhs);
435 }
436 
437 template <class T>
438 bool operator<(const T &lhs, const CPScalar &rhs)
439 {
440  return CPScalar(lhs) < rhs;
441 }
442 
443 // Less than or equal to
444 template <class T>
445 bool operator<=(const CPScalar &lhs, const T &rhs)
446 {
447  return lhs <= CPScalar(rhs);
448 }
449 
450 template <class T>
451 bool operator<=(const T &lhs, const CPScalar &rhs)
452 {
453  return CPScalar(lhs) <= rhs;
454 }
455 
456 // Greater than
457 template <class T>
458 bool operator>(const CPScalar &lhs, const T &rhs)
459 {
460  return lhs > CPScalar(rhs);
461 }
462 
463 template <class T>
464 bool operator>(const T &lhs, const CPScalar &rhs)
465 {
466  return CPScalar(lhs) > rhs;
467 }
468 
469 // Greater than or equal to
470 template <class T>
471 bool operator>=(const CPScalar &lhs, const T &rhs)
472 {
473  return lhs >= CPScalar(rhs);
474 }
475 
476 template <class T>
477 bool operator>=(const T &lhs, const CPScalar &rhs)
478 {
479  return CPScalar(lhs) >= rhs;
480 }
481 
482 // Equal
483 template <class T>
484 bool operator==(const CPScalar &lhs, const T &rhs)
485 {
486  return lhs == CPScalar(rhs);
487 }
488 
489 template <class T>
490 bool operator==(const T &lhs, const CPScalar &rhs)
491 {
492  return CPScalar(lhs) == rhs;
493 }
494 
495 // Not equal
496 template <class T>
497 bool operator!=(const CPScalar &lhs, const T &rhs)
498 {
499  return lhs != CPScalar(rhs);
500 }
501 
502 template <class T>
503 bool operator!=(const T &lhs, const CPScalar &rhs)
504 {
505  return CPScalar(lhs) != rhs;
506 }
507 
508 
bool operator<=(const CPScalar &rhs) const
Definition: PScalar.h:147
CPScalar & ConvertTo(const CPScalar &target)
Definition: PScalar.h:291
CPScalar(double val, const std::string &unitSpec)
Definition: PScalar.h:28
CPScalar operator()(const std::string &unitSpec) const
Definition: PScalar.h:235
CPScalar & ConvertTo(const std::string &unitSpec)
Definition: PScalar.h:270
double ConvertValueInterval(const double &value, const CCompoundUnit &fromUnit, const CCompoundUnit &toUnit) const
Definition: UnitConversionEngine.cpp:467
double GetValue() const
Definition: PScalar.h:225
CCompoundUnit & Raise(CCompoundUnitElement::ExponentType)
Definition: CompoundUnit.cpp:594
double ConvertValue(const double &value, const CCompoundUnit &fromUnit, const CCompoundUnit &toUnit) const
Definition: UnitConversionEngine.cpp:362
CPScalar & operator*=(const CPScalar &rhs)
Definition: PScalar.h:67
CPScalar operator-() const
Definition: PScalar.h:183
CPScalar & ConvertTo(const CCompoundUnit &newUnit)
Definition: PScalar.h:281
bool IsDimensionless() const
Definition: CompoundUnit.h:190
std::ostream & PrintSelf(std::ostream &output) const
Definition: PScalar.h:296
bool IsDimensionless() const
Definition: PScalar.h:306
CPScalar & Negate(void)
Definition: PScalar.h:177
CPScalar operator+(const CPScalar &rhs) const
Definition: PScalar.h:162
const CUnitDimension * GetDimension() const
Definition: CompoundUnit.cpp:235
CPScalar operator-(const CPScalar &rhs) const
Definition: PScalar.h:167
CPScalar operator+() const
Definition: PScalar.h:172
CPScalar & operator=(const CPScalar &rhs)
Definition: PScalar.h:57
CPScalar & Raise(double pwr)
Definition: PScalar.h:243
CPScalar(const std::string &unitSpec)
Definition: PScalar.h:43
bool operator>=(const CPScalar &rhs) const
Definition: PScalar.h:154
CPScalar & SQRoot()
Definition: PScalar.h:252
CPScalar & operator-=(const CPScalar &rhs)
Definition: PScalar.h:104
double m_dValue
Definition: PScalar.h:323
CPScalar & operator+=(const CPScalar &rhs)
Definition: PScalar.h:96
static CUnitConversionEngine & GetEngine(void)
Definition: UnitConversionEngine.h:41
bool IsDecibel() const
Definition: CompoundUnit.cpp:261
CPScalar operator*(const CPScalar &rhs) const
Definition: PScalar.h:81
bool operator<(const CPScalar &rhs) const
Definition: PScalar.h:133
CPScalar & operator/=(const CPScalar &rhs)
Definition: PScalar.h:74
CPScalar operator/(const CPScalar &rhs) const
Definition: PScalar.h:86
CPScalar()
Definition: PScalar.h:21
CPScalar & Abs()
Definition: PScalar.h:263
bool IsSameType(const CPScalar &target) const
Definition: PScalar.h:301
bool IsDecible() const
Definition: PScalar.h:312
CPScalar(const CPScalar &src)
Definition: PScalar.h:50
Definition: UnitConversionEngine.h:23
bool operator>(const CPScalar &rhs) const
Definition: PScalar.h:140
Definition: CompoundUnit.h:39
Definition: PScalar.h:17
bool operator==(const CPScalar &rhs) const
Definition: PScalar.h:114
CPScalar(double val)
Definition: PScalar.h:35
CCompoundUnit m_CCU
Definition: PScalar.h:324
bool operator!=(const CPScalar &rhs) const
Definition: PScalar.h:124