The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
floating_point_emulation.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2016 by Mark de Wever <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Contains code for a floating point emulation.
18  *
19  * Depending on some compiler switches the code can use floating point code or
20  * fixed point code. The code is still work-in-progress.
21  *
22  * At the moment three emulation modi are supported:
23  * * A 32-bit signed integer, shifted 8 bits.
24  * * A @c double, not shifted.
25  * * A @c double, shifted 8 bits (for debugging).
26  *
27  * In the comments some conventions are used:
28  * - lowercase variables are unscaled values
29  * - UPPERCASE VARIABLES are scaled values
30  * - the variable `sf' is the scale factor
31  * - the variable `result' and `RESULT' are the result of a calculation
32  *
33  * There are several define's to control the compilation.
34  *
35  * FLOATING_POINT_EMULATION_USE_SCALED_INT
36  * When this macro is defined the @ref tfloat is defined as the 32-bit scaled
37  * integer. If not the @ref tfloat is defined as a @c double, whether or not the
38  * value is shifted depends on @c FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK.
39  *
40  * FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK
41  * This macro can only be defined if @c FLOATING_POINT_EMULATION_USE_SCALED_INT
42  * is not defined. This macro shifts the @c doubles so it can be checked
43  * against the range of the scaled int. (It would have been possible to scale
44  * the validation range as well, but this feels easier to check.)
45  *
46  * FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK_THROW
47  * This macro can only be defined if
48  * @c FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK is defined. Instead of
49  * printing a warning and then go on it throws an exception if the range check
50  * fails. This is intended to aid debugging and should not be enabled in
51  * production code.
52  *
53  * FLOATING_POINT_EMULATION_TRACER_ENABLE
54  * This macro allows to place trace markers in the code. When using the markers
55  * it's possible to gather statistics regarding the code paths being executed.
56  * This can be used to analyze execution and add branch prediction markers.
57  */
58 
59 #ifndef FLOATING_POINT_EMULATION_HPP_INCLUDED
60 #define FLOATING_POINT_EMULATION_HPP_INCLUDED
61 
62 #include "global.hpp"
63 #include "util.hpp"
64 
65 #include <SDL_types.h>
66 
67 #include <boost/utility/enable_if.hpp>
68 
69 #include <cassert>
70 #include <cmath>
71 
72 //#define FLOATING_POINT_EMULATION_USE_SCALED_INT
73 
74 //#define FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK
75 //#define FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK_THROW
76 
77 //#define FLOATING_POINT_EMULATION_TRACER_ENABLE
78 
79 #ifdef FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK_THROW
80 #ifndef FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK
81 #error FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK_THROW requires \
82  FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK
83 #endif
84 #include <stdexcept>
85 #define FLOATING_POINT_EMULATION_RANGE_CHECK_THROW \
86  do { \
87  throw std::range_error(""); \
88  } while(0)
89 #else
90 #define FLOATING_POINT_EMULATION_RANGE_CHECK_THROW \
91  do { \
92  } while(0)
93 #endif
94 
95 #ifdef FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK
96 #ifdef FLOATING_POINT_EMULATION_USE_SCALED_INT
97 #error FLOATING_POINT_EMULATION_USE_SCALED_INT and \
98  FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK are mutually exclusive.
99 #endif
100 #include <iostream>
101 #define FLOATING_POINT_EMULATION_RANGE_CHECK \
102  FLOATING_POINT_EMULATION_RANGE_CHECK_OBJECT((*this))
103 
104 #define FLOATING_POINT_EMULATION_RANGE_CHECK_OBJECT(object) \
105  do { \
106  if(object.value_ >= 2147483648.0) { \
107  std::cerr << "Positive overflow »" << object.value_ \
108  << "« as double »" << object.to_double() <<"« .\n"; \
109  FLOATING_POINT_EMULATION_RANGE_CHECK_THROW; \
110  } \
111  if(object.value_ < -2147483648.0) { \
112  std::cerr << "Negative overflow »" << object.value_ \
113  << "« as double »" << object.to_double() <<"« .\n"; \
114  FLOATING_POINT_EMULATION_RANGE_CHECK_THROW; \
115  } \
116  } while(0)
117 #else
118 #define FLOATING_POINT_EMULATION_RANGE_CHECK \
119  do { \
120  } while(0)
121 #define FLOATING_POINT_EMULATION_RANGE_CHECK_OBJECT(object) \
122  do { \
123  } while(0)
124 #endif
125 
126 #ifdef FLOATING_POINT_EMULATION_TRACER_ENABLE
127 #include "tracer.hpp"
128 #define FLOATING_POINT_EMULATION_TRACER_ENTRY(interval) TRACER_ENTRY(interval)
129 #define FLOATING_POINT_EMULATION_TRACER_COUNT(marker) TRACER_COUNT(marker)
130 #else
131 #define FLOATING_POINT_EMULATION_TRACER_ENTRY(interval) \
132  do { \
133  } while(0)
134 
135 #define FLOATING_POINT_EMULATION_TRACER_COUNT(marker) \
136  do { \
137  } while(0)
138 #endif
139 
141 
142 template<class T, unsigned S>
143 class tfloat;
144 
145 namespace detail {
146 
147 /***** ***** Internal conversion functions. ***** *****/
148 
149 template<class T, unsigned S, class E = void>
150 struct tscale
151 {
152 };
153 
154 template<class T>
155 struct tscale<T, 0>
156 {
157  /**
158  * Scales the internal value up.
159  *
160  * Upscaling is used for:
161  * - Returning the value to external code; the internal representation
162  * needs to be adjusted for the external representation.
163  * - After multiplying a tfloat, then both values were scaled so the value
164  * is a factor @p tfloat::scale_factor too big.
165  */
166  static T
168  {
169  return value;
170  }
171 
172  /**
173  * Scales the value up.
174  *
175  * Upscaling is used for:
176  * - Loading the value it needs to be scaled to the internal value.
177  * - After dividing a tfloat, then both values were scaled so the value
178  * is a factor @p tfloat::scale_factor too small.
179  */
180  static T
181  up(T& value)
182  {
183  return value;
184  }
185 };
186 
187 template<unsigned S>
188 struct tscale<double, S, typename boost::enable_if_c<S != 0>::type>
189 {
190  static double
191  down(double& value)
192  {
193  value /= (1 << S);
194  return value;
195  }
196 
197  static double
198  up(double& value)
199  {
200  value *= (1 << S);
201  return value;
202  }
203 };
204 
205 template<unsigned S>
206 struct tscale<Sint32, S, typename boost::enable_if_c<S != 0>::type>
207 {
208  static Sint32
209  down(Sint32& value)
210  {
211  if(value > 0) {
212  value >>= S;
213  } else {
214  value = -((-value) >> S);
215  }
216  return value;
217  }
218 
219  static Sint32
220  up(Sint32& value)
221  {
222  value <<= S;
223  return value;
224  }
225 };
226 
227 template<class T, unsigned S>
228 inline T
230 {
231  T result(value);
232  return tscale<T, S>::up(result);
233 }
234 
235 template<class T, unsigned S>
236 inline T
237 load(double value)
238 {
239  return tscale<double, S>::up(value);
240 }
241 
242 template<class R, class T, unsigned S>
243 inline R
245 {
246  R result(value);
247  return tscale<R, S>::down(result);
248 }
249 
250 template<class T, unsigned S>
251 struct tfloor
252 {
253 };
254 
255 template<unsigned S>
256 struct tfloor<double, S>
257 {
258  static int
259  floor(double value)
260  {
261  return std::floor(tscale<double, S>::down(value));
262  }
263 };
264 
265 template<unsigned S>
266 struct tfloor<Sint32, S>
267 {
268  static int
269  floor(Sint32 value)
270  {
271  value >>= S;
272  return value;
273  }
274 };
275 
276 /**
277  * Shift arithmetically left.
278  *
279  * Shifting of floating point values doesn't exist so it's emulated by a
280  * multiplication. This function allows @ref tidiv::idiv() to contain generic
281  * code.
282  *
283  * @param lhs The value to `shift'.
284  * @param rhs The number of bits to `shift'.
285  */
286 inline void
287 sal(double& lhs, unsigned rhs)
288 {
289  lhs *= (1 << rhs);
290 }
291 
292 /**
293  * Shift arithmetically left.
294  *
295  * @param lhs The value to shift.
296  * @param rhs The number of bits to shift.
297  */
298 inline void
299 sal(Sint32& lhs, unsigned rhs)
300 {
301  lhs <<= rhs;
302 }
303 
304 /**
305  * Shift arithmetically right.
306  *
307  * Shifting of floating point values doesn't exist so it's emulated by a
308  * division. This function allows @ref tidiv::idiv() to contain generic
309  * code.
310  *
311  * @param lhs The value to `shift'.
312  * @param rhs The number of bits to `shift'.
313  */
314 inline void
315 sar(double& lhs, unsigned rhs)
316 {
317  lhs /= (1 << rhs);
318 }
319 
320 /**
321  * Shift arithmetically right.
322  *
323  * @param lhs The value to shift.
324  * @param rhs The number of bits to shift.
325  */
326 inline void
327 sar(Sint32& lhs, unsigned rhs)
328 {
329  lhs >>= rhs;
330 }
331 
332 template<class T, unsigned S>
333 struct tidiv
334 {
335  static tfloat<T, S>&
337  {
340  lhs.value_ /= rhs.value_;
342  return lhs;
343  }
344 };
345 
346 template<class T>
347 struct tidiv<T, 8>
348 {
349  static tfloat<T, 8>&
350  idiv(tfloat<T, 8>& lhs, tfloat<T, 8> rhs);
351 };
352 
353 /**
354  * An optimized version of the division operator.
355  *
356  * This version is optimized to maintain the highest numeric stability when
357  * dividing.
358  *
359  * As documented at operator/():
360  * THIS * RHS = this * sf * rhs * sf = result * sf * sf = RESULT * sf
361  *
362  * THIS this * sf this
363  * ---- = --------- = ---- = result
364  * RHS rhs * sf rhs
365  *
366  * Thus in order to get RESULT there needs to be multiplied by sf:
367  *
368  * THIS
369  * RESULT = ---- * sf
370  * RHS
371  *
372  * Since multiplication is associative this can also be written as:
373  *
374  * sf THIS
375  * RESULT = -- * ---- * 2
376  * 2 RHS
377  *
378  * And as
379  *
380  * (sf / 2) * THIS
381  * RESULT = --------------- * 2
382  * RHS
383  *
384  * Thus it is possible to try to get the dividend as large as possible before
385  * the division and thus loose less precision.
386  *
387  * Another option to get the proper result is:
388  *
389  * THIS
390  * RESULT = ----------
391  * (RHS / sf)
392  *
393  * Obviously dumping the last bits of the divisor will loose a lot of
394  * precision, except if these bits contain zeros.
395  *
396  * It's also possible to do a combination of these ways and thus generating an
397  * algorithm like:
398  * * Try to shift the dividend up by as many bits as possible without overflow.
399  * * Try to shift the divisor down by as many bits as possible without loosing
400  * resolution.
401  * * divide.
402  * * shift the result up by the required number of bits.
403  *
404  * The code has some other optimizations as well. On a 2-complement system
405  * there are additional tests required for negative and positive values, to
406  * remove these branches, the code uses a temporary value which contains the
407  * positive value.
408  *
409  * @note The shifted double also uses this version in order to test overflows.
410  *
411  * @todo The function needs more branch-prediction markers.
412  *
413  * @todo The function is too large to inline and needs to be separated in more
414  * functions, where the unlikely cases are not inlined but a function call.
415  */
416 template<class T>
417 inline tfloat<T, 8>&
419 {
420  /* The interval has been determined empirically. */
422 
423  /* Division of zero is a NOP, so bail out directly. */
424  if(lhs.value_ == 0) {
425  FLOATING_POINT_EMULATION_TRACER_COUNT("lhs.value_ == 0");
426  return lhs;
427  }
428 
429  /*
430  * Test whether any high bit of the dividend is set.
431  *
432  * If the original value is smaller than 1 << 15 then the shifted
433  * value is smaller than 1 << 31, which can be done without any risk. This
434  * value is also quite likely to happen, so the case is optimized.
435  */
436 
437  Uint32 lhs_value = std::abs(lhs.value_);
438  if(LIKELY(lhs_value <= 0x007FFFFFu)) {
439  FLOATING_POINT_EMULATION_TRACER_COUNT("lhs_value <= 0x007FFFFFu");
440  sal(lhs.value_, 8);
442 
443  lhs.value_ /= rhs.value_;
445  return lhs;
446  }
447 
448  /***********************************************************************/
449 
450  /*
451  * Shift the dividend up.
452  *
453  * The code is based upon the Linux kernel
454  * http://lxr.linux.no/#linux+v3.2.6/include/asm-generic/bitops/fls.h
455  */
456 
457  /*
458  * Will contain the offset from the MSB to the MSB set.
459  *
460  * The range returned should be [0, 8), the values outside this range
461  * should have been handled before. We don't look at the MSB since it
462  * `contains' the sign, except for the maximum negative value, where we
463  * can't shift at all).
464  */
465  int dividend_high_bit = 0;
466 
467  if(UNLIKELY(lhs.value_ == static_cast<int>(0x80000000))) {
468  /*
469  * Do nothing dividend_high_bit is already 0.
470  *
471  * The reason for this way of the if is to allow for a trace marker.
472  */
473  FLOATING_POINT_EMULATION_TRACER_COUNT("lhs.value_ == 0x80000000");
474  } else {
475  if(!(lhs_value & 0x78000000u)) {
476  FLOATING_POINT_EMULATION_TRACER_COUNT("!(lhs_value & 0x78000000u)");
477  lhs_value <<= 4;
478  dividend_high_bit += 4;
479  }
480  if(!(lhs_value & 0x60000000u)) {
481  FLOATING_POINT_EMULATION_TRACER_COUNT("!(lhs_value & 0x60000000u)");
482  lhs_value <<= 2;
483  dividend_high_bit += 2;
484  }
485  if(!(lhs_value & 0x40000000u)) {
486  FLOATING_POINT_EMULATION_TRACER_COUNT("!(lhs_value & 0x40000000u)");
487  dividend_high_bit += 1;
488  }
489  }
490 
491  assert(dividend_high_bit >= 0);
492  assert(dividend_high_bit < 8);
493 
494  sal(lhs.value_, dividend_high_bit);
496 
497  int shifted = dividend_high_bit;
498 
499  /***********************************************************************/
500 
501  if(shifted < 8) {
502  /*
503  * Shift the divisor down.
504  *
505  * Code adapted from the algorithm used above.
506  *
507  * This test is only required if we didn't already shift the wanted
508  * number of positions.
509  */
510 
511  Uint32 rhs_value = std::abs(rhs.value_);
512 
513  /*
514  * Will contain the offset from bit 0 of the LSB set. Since we're only
515  * interested in values in the range [0-8] the value is saturated at 8.
516  */
517  int divisor_low_bit = 0;
518 
519  if(!(rhs_value & 0xffu)) {
520  FLOATING_POINT_EMULATION_TRACER_COUNT("!(rhs_value & 0xffu)");
521  divisor_low_bit = 8;
522  } else {
523  if(!(rhs_value & 0xfu)) {
524  FLOATING_POINT_EMULATION_TRACER_COUNT("!(rhs_value & 0xfu)");
525  divisor_low_bit += 4;
526  rhs_value >>= 4;
527  }
528  if(!(rhs_value & 0x3u)) {
529  FLOATING_POINT_EMULATION_TRACER_COUNT("!(rhs_value & 0x3u)");
530  divisor_low_bit += 2;
531  rhs_value >>= 2;
532  }
533  if(!(rhs_value & 0x1u)) {
534  FLOATING_POINT_EMULATION_TRACER_COUNT("!(rhs_value & 0x1u)");
535  divisor_low_bit += 1;
536  }
537  }
538  assert(divisor_low_bit >= 0);
539  assert(divisor_low_bit <= 8);
540 
541  divisor_low_bit = std::min(8 - shifted, divisor_low_bit);
542 
543  sar(rhs.value_, divisor_low_bit);
545 
546  shifted += divisor_low_bit;
547  }
548 
549  /***********************************************************************/
550 
551  lhs.value_ /= rhs.value_;
553 
554  /* Make the final shift adjustment. */
555  sal(lhs.value_, 8 - shifted);
557 
558  return lhs;
559 }
560 
561 } // namespace detail
562 
563 /**
564  * Template class for the emulation.
565  *
566  * @note Operators that are not documented do the expected thing.
567  *
568  * @note For conversions it would be nice to use the `operator int()' instead
569  * of @ref to_int(). Unfortunately C++98 doesn't support the @c explicit for
570  * conversion operators and the implicit conversion is evil.
571  *
572  * @tparam T The type used for the emulation. At the
573  * moment the following types are supported:
574  * * @c double
575  */
576 template<class T, unsigned S>
577 class tfloat
578 {
579  template<class TT, unsigned SS> friend struct detail::tidiv;
580 public:
581 
582  /***** ***** Types. ***** *****/
583 
584  typedef T value_type;
585 
586  enum { shift = S };
587  enum { factor = 1 << S };
588 
589  /***** ***** Constructor, destructor, assignment. ***** *****/
590 
592  : value_(0)
593  {
594  }
595 
596  explicit tfloat(const int value)
597  : value_(detail::load<T, S>(value))
598  {
600  }
601 
602  explicit tfloat(const double value)
603  : value_(detail::load<T, S>(value))
604  {
606  }
607 
608 
609  tfloat&
610  operator=(const tfloat rhs)
611  {
612  value_ = rhs.value_;
614  return *this;
615  }
616 
617  tfloat&
618  operator=(const int rhs)
619  {
620  return operator=(tfloat(rhs));
621  }
622 
623  tfloat&
624  operator=(const double rhs)
625  {
626  return operator=(tfloat(rhs));
627  }
628 
629 
630  /***** ***** Relational operators. ***** *****/
631 
632  bool operator<(const tfloat rhs) const
633  {
634  return value_ < rhs.value_;
635  }
636 
637 
638  bool operator<=(const tfloat rhs) const
639  {
640  return !(rhs.value_ < value_);
641  }
642 
643 
644  bool operator>(const tfloat rhs) const
645  {
646  return rhs.value_ < value_;
647  }
648 
649 
650  bool operator>=(const tfloat rhs) const
651  {
652  return !(value_ < rhs.value_);
653  }
654 
655 
656  bool
657  operator==(const tfloat rhs) const
658  {
659  return value_ == rhs.value_;
660  }
661 
662  bool
663  operator==(const int rhs) const
664  {
665  return operator==(tfloat(rhs));
666  }
667 
668  bool
669  operator==(const double rhs) const
670  {
671  return operator==(tfloat(rhs));
672  }
673 
674 
675  bool
676  operator!=(const tfloat rhs) const
677  {
678  return !operator==(rhs);
679  }
680 
681  bool
682  operator!=(const int rhs) const
683  {
684  return !operator==(rhs);
685  }
686 
687  bool
688  operator!=(const double rhs) const
689  {
690  return !operator==(rhs);
691  }
692 
693 
694  /***** ***** Unary operators. ***** *****/
695 
696  /*
697  * This set are normally non-members, but this is easier to code.
698  */
699 
700  bool
701  operator!() const
702  {
703  return value_ == 0;
704  }
705 
706  tfloat
707  operator-() const
708  {
709  return tfloat(*this).negative();
710  }
711 
712  tfloat
713  operator+() const
714  {
715  return *this;
716  }
717 
718 
719  /***** ***** Assignment operators. ***** *****/
720 
721  /***** Mul *****/
722 
723  /**
724  * Multiply
725  *
726  * Keep in mind that:
727  *
728  * THIS * RHS = this * sf * rhs * sf = result * sf * sf = RESULT * sf
729  *
730  * Thus in order to get RESULT there needs to be divided by sf:
731  *
732  * RESULT = THIS * RHS / sf
733  */
734  tfloat&
735  operator*=(const tfloat rhs)
736  {
737  value_ *= rhs.value_;
738 
739  /*
740  * There is no need to check the range at this point. The specialized
741  * version makes a short trip to 64-bit value, so overflowing is not
742  * possible.
743  */
744 
747  return *this;
748  }
749 
750  /**
751  * Multiply
752  *
753  * No extra adjustment needed since:
754  *
755  * RESULT = THIS * rhs
756  */
757  tfloat&
758  operator*=(const int rhs)
759  {
760  value_ *= rhs;
762  return *this;
763  }
764 
765  /**
766  * Multiply
767  *
768  * No extra adjustment needed since:
769  *
770  * RESULT = THIS * rhs
771  */
772  tfloat&
773  operator*=(const double rhs)
774  {
775  value_ *= rhs;
777  return *this;
778  }
779 
780  /***** Div *****/
781 
782  /**
783  * Divide
784  *
785  * Keep in mind that:
786  *
787  * THIS * RHS = this * sf * rhs * sf = result * sf * sf = RESULT * sf
788  *
789  * THIS this * sf this
790  * ---- = --------- = ---- = result
791  * RHS rhs * sf rhs
792  *
793  * Thus in order to get RESULT there needs to be multiplied by sf:
794  *
795  * THIS
796  * RESULT = ---- * sf
797  * RHS
798  */
799  tfloat&
800  operator/=(const tfloat rhs)
801  {
802  return detail::tidiv<T, S>::idiv(*this, rhs);
803  }
804 
805  /**
806  * Divide
807  *
808  * No extra adjustment needed since:
809  *
810  * RESULT = THIS / rhs
811  */
812  tfloat&
813  operator/=(const int rhs)
814  {
815  value_ /= rhs;
817  return *this;
818  }
819 
820  /**
821  * Divide
822  *
823  * No extra adjustment needed since:
824  *
825  * RESULT = THIS / rhs
826  */
827  tfloat&
828  operator/=(const double rhs)
829  {
830  value_ /= rhs;
832  return *this;
833  }
834 
835 
836  /***** Add *****/
837 
838  tfloat&
839  operator+=(const tfloat rhs)
840  {
841  value_ += rhs.value_;
843  return *this;
844  }
845 
846  tfloat&
847  operator+=(const int rhs)
848  {
849  return operator+=(tfloat(rhs));
850  }
851 
852  tfloat&
853  operator+=(const double rhs)
854  {
855  return operator+=(tfloat(rhs));
856  }
857 
858  /***** Sub *****/
859 
860  tfloat&
861  operator-=(const tfloat rhs)
862  {
863  value_ -= rhs.value_;
865  return *this;
866  }
867 
868  tfloat&
869  operator-=(const int rhs)
870  {
871  return operator-=(tfloat(rhs));
872  }
873 
874  tfloat&
875  operator-=(const double rhs)
876  {
877  return operator-=(tfloat(rhs));
878  }
879 
880  /***** ***** Conversion functions. ***** *****/
881 
882  int
883  to_int() const
884  {
885  return detail::store<int, T, S>(value_);
886  }
887 
888  double
889  to_double() const
890  {
891  return detail::store<double, T, S>(value_);
892  }
893 
894  /***** ***** Math functions. ***** *****/
895 
896  int
898  {
900  }
901 
902  /***** ***** Setters, getters. ***** *****/
903 
904  T
905  get_value() const
906  {
907  return value_;
908  }
909 
910 private:
911 
912  /***** ***** Members. ***** *****/
913 
914  /**
915  * The value of the emulation.
916  *
917  * What the value represents is not really defined for the user.
918  */
920 
921  /**
922  * Changes the object to its negative value.
923  *
924  * There is an issue with @ref operator-(). There is an constructor that
925  * takes @ref value_type as parameter. When @ref shift != 0 the issue
926  * occurs. Implementing @ref operator-() as return tfloat(-value_) returns
927  * a scaled value. Scaling twice might loose resolution and cause some
928  * overhead. So just add this function to solve the issue.
929  *
930  * @returns @c *this, but it's value is negated.
931  */
932  tfloat&
934  {
935  value_ = -value_;
936  return *this;
937  }
938 };
939 
940 /***** ***** Relational operators. ***** *****/
941 
942 template<class T, unsigned S>
943 inline bool
944 operator==(const int lhs, const tfloat<T, S> rhs)
945 {
946  return rhs.operator==(lhs);
947 }
948 
949 template<class T, unsigned S>
950 inline bool
951 operator==(const double lhs, const tfloat<T, S> rhs)
952 {
953  return rhs.operator==(lhs);
954 }
955 
956 template<class T, unsigned S>
957 inline bool
958 operator!=(const int lhs, const tfloat<T, S> rhs)
959 {
960  return rhs.operator!=(lhs);
961 }
962 
963 template<class T, unsigned S>
964 inline bool
965 operator!=(const double lhs, const tfloat<T, S> rhs)
966 {
967  return rhs.operator!=(lhs);
968 }
969 
970 
971 /***** ***** Math operators. ***** *****/
972 
973 /***** Mul *****/
974 
975 /**
976  * Multiply
977  *
978  * Specialized for the Sint32 with a shift of 8.
979  *
980  * Instead of figuring out the optimal shift before multiplying simply multiply
981  * as a 64-bit value and then perform the shift. This is rather cheap on the
982  * Pandora and also keeps the code short on that platform (only two extra
983  * instructions on the ARM v7; a `logical shift right' instruction followed by
984  * a `logical left shifted or' instruction.)
985  */
986 template<>
987 inline tfloat<Sint32, 8>&
989 {
990  value_ = (static_cast<Sint64>(value_) * rhs.value_) >> 8;
991  return *this;
992 }
993 
994 template<class T, unsigned S>
995 inline tfloat<T, S>
997 {
998  return lhs.operator*=(rhs);
999 }
1000 
1001 template<class T, unsigned S>
1002 inline tfloat<T, S>
1003 operator*(tfloat<T, S> lhs, const int rhs)
1004 {
1005  return lhs.operator*=(rhs);
1006 }
1007 
1008 template<class T, unsigned S>
1009 inline tfloat<T, S>
1010 operator*(tfloat<T, S> lhs, const double rhs)
1011 {
1012  return lhs.operator*=(rhs);
1013 }
1014 
1015 template<class T, unsigned S>
1016 inline tfloat<T, S>
1017 operator*(const int lhs, tfloat<T, S> rhs)
1018 {
1019  return rhs.operator*=(lhs);
1020 }
1021 
1022 template<class T, unsigned S>
1023 inline tfloat<T, S>
1024 operator*(const double lhs, tfloat<T, S> rhs)
1025 {
1026  return rhs.operator*=(lhs);
1027 }
1028 
1029 /***** Div *****/
1030 
1031 template<class T, unsigned S>
1032 inline tfloat<T, S>
1034 {
1035  return lhs.operator/=(rhs);
1036 }
1037 
1038 template<class T, unsigned S>
1039 inline tfloat<T, S>
1040 operator/(tfloat<T, S> lhs, const int rhs)
1041 {
1042  return lhs.operator/=(rhs);
1043 }
1044 
1045 template<class T, unsigned S>
1046 inline tfloat<T, S>
1047 operator/(tfloat<T, S> lhs, const double rhs)
1048 {
1049  return lhs.operator/=(rhs);
1050 }
1051 
1052 template<class T, unsigned S>
1053 inline tfloat<T, S>
1054 operator/(const int lhs, tfloat<T, S> rhs)
1055 {
1056  return tfloat<T, S>(lhs).operator/=(rhs);
1057 }
1058 
1059 template<class T, unsigned S>
1060 inline tfloat<T, S>
1061 operator/(const double lhs, tfloat<T, S> rhs)
1062 {
1063  return tfloat<T, S>(lhs).operator/=(rhs);
1064 }
1065 
1066 /***** Add *****/
1067 
1068 template<class T, unsigned S>
1069 inline tfloat<T, S>
1071 {
1072  return lhs.operator+=(rhs);
1073 }
1074 
1075 template<class T, unsigned S>
1076 inline tfloat<T, S>
1077 operator+(tfloat<T, S> lhs, const int rhs)
1078 {
1079  return lhs.operator+=(rhs);
1080 }
1081 
1082 template<class T, unsigned S>
1083 inline tfloat<T, S>
1084 operator+(tfloat<T, S> lhs, const double rhs)
1085 {
1086  return lhs.operator+=(rhs);
1087 }
1088 
1089 template<class T, unsigned S>
1090 inline tfloat<T, S>
1091 operator+(const int lhs, const tfloat<T, S> rhs)
1092 {
1093  return rhs.operator+=(lhs);
1094 }
1095 
1096 template<class T, unsigned S>
1097 inline tfloat<T, S>
1098 operator+(const double lhs, const tfloat<T, S> rhs)
1099 {
1100  return rhs.operator+=(lhs);
1101 }
1102 
1103 /***** Sub *****/
1104 
1105 template<class T, unsigned S>
1106 inline tfloat<T, S>
1108 {
1109  return lhs.operator-=(rhs);
1110 }
1111 
1112 template<class T, unsigned S>
1113 inline tfloat<T, S>
1114 operator-(tfloat<T, S> lhs, const int rhs)
1115 {
1116  return lhs.operator-=(rhs);
1117 }
1118 
1119 template<class T, unsigned S>
1120 inline tfloat<T, S>
1121 operator-(tfloat<T, S> lhs, const double rhs)
1122 {
1123  return lhs.operator-=(rhs);
1124 }
1125 
1126 template<class T, unsigned S>
1127 inline tfloat<T, S>
1128 operator-(const int lhs, tfloat<T, S> rhs)
1129 {
1130  return tfloat<T, S>(lhs).operator-=(rhs);
1131 }
1132 
1133 template<class T, unsigned S>
1134 inline tfloat<T, S>
1135 operator-(const double lhs, tfloat<T, S> rhs)
1136 {
1137  return tfloat<T, S>(lhs).operator-=(rhs);
1138 }
1139 
1140 
1141 /***** ***** Math functions. ***** *****/
1142 
1143 template<class T, unsigned S>
1144 inline int
1146 {
1147  return lhs.floor();
1148 }
1149 
1150 } // namespace floating_point_emulation
1151 
1152 #ifdef FLOATING_POINT_EMULATION_USE_SCALED_INT
1154 #else
1155 #ifdef FLOATING_POINT_EMULATION_ENABLE_RANGE_CHECK
1157 #else
1159 #endif
1160 #endif
1161 
1162 #endif
T value_
The value of the emulation.
tfloat< T, S > operator+(tfloat< T, S > lhs, const tfloat< T, S > rhs)
tfloat & negative()
Changes the object to its negative value.
#define UNLIKELY(a)
Definition: util.hpp:426
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
bool operator==(const double rhs) const
static T down(T &value)
Scales the internal value up.
bool operator!=(const int lhs, const tfloat< T, S > rhs)
bool operator==(const tfloat rhs) const
tfloat & operator*=(const tfloat rhs)
Multiply.
tfloat & operator/=(const int rhs)
Divide.
#define FLOATING_POINT_EMULATION_RANGE_CHECK
tfloat & operator*=(const double rhs)
Multiply.
GLuint64EXT * result
Definition: glew.h:10727
bool operator==(const int lhs, const tfloat< T, S > rhs)
#define FLOATING_POINT_EMULATION_RANGE_CHECK_OBJECT(object)
GLsizei const GLfloat * value
Definition: glew.h:1817
static tfloat< T, S > & idiv(tfloat< T, S > &lhs, tfloat< T, S > rhs)
Contains code for tracing the code.
Templates and utility-routines for strings and numbers.
bool operator<=(const tfloat rhs) const
tfloat & operator/=(const double rhs)
Divide.
tfloat< T, S > operator-(tfloat< T, S > lhs, const tfloat< T, S > rhs)
tfloat< T, S > operator/(tfloat< T, S > lhs, const tfloat< T, S > rhs)
Template class for the emulation.
bool operator>=(const tfloat rhs) const
#define FLOATING_POINT_EMULATION_TRACER_ENTRY(interval)
bool operator!=(const double rhs) const
tfloat & operator*=(const int rhs)
Multiply.
floating_point_emulation::tfloat< double, 0 > tfloat
tfloat< T, S > operator*(tfloat< T, S > lhs, const tfloat< T, S > rhs)
bool operator<(const tfloat rhs) const
#define FLOATING_POINT_EMULATION_TRACER_COUNT(marker)
bool operator!=(const tfloat rhs) const
void sal(double &lhs, unsigned rhs)
Shift arithmetically left.
bool operator>(const tfloat rhs) const
tfloat & operator/=(const tfloat rhs)
Divide.
#define LIKELY(a)
Definition: util.hpp:425
#define S(x)
Definition: luac.cpp:374
void sar(double &lhs, unsigned rhs)
Shift arithmetically right.