1 // GnashNumeric.h: vaguely useful mathematical functions.
2 //
3 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 //   Free Software Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 //
20 
21 #ifndef GNASH_NUMERIC_H
22 #define GNASH_NUMERIC_H
23 
24 #ifdef HAVE_CONFIG_H
25 # include "gnashconfig.h"
26 #endif
27 
28 #ifdef SOLARIS_HOST
29 # include <ieeefp.h> // for finite()
30 #endif
31 
32 #include <cassert>
33 #include <cmath>
34 #include <algorithm>
35 #include <cstdint>
36 #include <limits>
37 #include <type_traits>
38 
39 namespace gnash {
40 
41 // Using a possible built-in pi constant M_PI, which is not in
42 // the C++ standard, has no greate advantage, so we will use this
43 // one. Make it as accurate as you like.
44 static const double PI = 3.14159265358979323846;
45 
46 inline bool
isFinite(double d)47 isFinite(double d)
48 {
49 #if defined(HAVE_FINITE) && !defined(HAVE_ISFINITE)
50     return (finite(d));
51 #else
52     // Put using namespace std; here if you have to
53     // put it anywhere.
54     using namespace std;
55     return (isfinite(d));
56 #endif
57 }
58 
59 template <typename T>
60 inline
61 bool
isNaN(const T & num)62 isNaN(const T& num)
63 {
64     static_assert(std::is_floating_point<T>::value,
65         "isNaN() is only meaningful for floating point types.");
66     return num != num;
67 }
68 
69 inline double
infinite_to_zero(double x)70 infinite_to_zero(double x)
71 {
72     return isFinite(x) ? x : 0.0;
73 }
74 
75 template <typename T>
76 inline T
clamp(T i,T min,T max)77 clamp(T i, T min, T max)
78 {
79     assert(min <= max);
80     return std::max<T>(min, std::min<T>(i, max));
81 }
82 
83 template<typename T>
84 inline T
lerp(T a,T b,T f)85 lerp(T a, T b, T f)
86 {
87     return (b - a) * f + a;
88 }
89 
90 inline int
frnd(float f)91 frnd(float f)
92 {
93     return static_cast<int>(f + 0.5f);
94 }
95 
96 inline double
twipsToPixels(int i)97 twipsToPixels(int i)
98 {
99     return i / 20.0;
100 }
101 
102 template<size_t Factor>
103 std::int32_t
truncateWithFactor(double a)104 truncateWithFactor(double a)
105 {
106     // If a is NaN, then this function would return -NAN, which when cast to
107     // int32, converts to zero on x86*, but converts to -1 on ARM. The
108     // behaviour is undefined according to ISO-IEC 14882:2003 4.9.1.
109     if (isNaN(a)) {
110         return 0;
111     }
112 
113     const double factor = static_cast<double>(Factor);
114 
115     // This truncates large values without relying on undefined behaviour.
116     // For very large values of 'a' it is noticeably slower than the UB
117     // version (due to fmod), but should always be legal behaviour. For
118     // ordinary values (within ±1.07374e+08 pixels) it is comparable to
119     // the UB version for speed. Because values outside the limit are
120     // extremely rare, using this safe version has no implications for
121     // performance under normal circumstances.
122     static const double upperUnsignedLimit =
123                 std::numeric_limits<std::uint32_t>::max() + 1.0;
124     static const double upperSignedLimit =
125                 std::numeric_limits<std::int32_t>::max() / factor;
126     static const double lowerSignedLimit =
127                 std::numeric_limits<std::int32_t>::min() / factor;
128 
129     if (a >= lowerSignedLimit && a <= upperSignedLimit) {
130         return a * Factor;
131     }
132 
133     // This slow truncation happens only in very unlikely cases.
134     return a >= 0 ?
135         static_cast<std::uint32_t>(
136                 std::fmod(a * factor, upperUnsignedLimit))
137         :
138         -static_cast<std::uint32_t>(
139                 std::fmod(-a * factor, upperUnsignedLimit));
140 }
141 
142 // truncate when overflow occurs.
143 inline std::int32_t
pixelsToTwips(double a)144 pixelsToTwips(double a)
145 {
146     return truncateWithFactor<20>(a);
147 }
148 
149 } // namespace gnash
150 
151 #endif
152