source: cpp/common/nonstd_math.h @ 1288

Last change on this file since 1288 was 1275, checked in by Maciej Komosinski, 15 months ago

More unification of floating point exception handling across platforms

  • Property svn:eol-style set to native
File size: 4.9 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[979]2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[122]4
[109]5#ifndef _NONSTD_MATH_H_
6#define _NONSTD_MATH_H_
7
8
9#ifdef _MSC_VER
10 #define _USE_MATH_DEFINES //after this is defined, the next #include <math.h> or <cmath> will define M_PI etc.
[1275]11 #include <math.h> //w vc2008 dzia�a�o tu <cmath>, ale w vc2010 juz nie bo "co�" (jaki� inny .h stl'a?) includuje wcze�niej <cmath> bez _USE_MATH_DEFINES, a <cmath> includuje <math.h> (ale tylko raz bo ma "include guards" jak kazdy .h)
[109]12 #include <float.h>
[251]13 //#define isnan(x) _isnan(x) //since 2014 we use std::isnan()
[109]14 #define finite(x) _finite(x)
15#else //m.in. __BORLANDC__
16 #include <math.h>
17#endif
18
19
20
21//random number generator:
22#include "random.h"
[896]23RandomGenerator &rndGetInstance();
[109]24
[896]25inline double rndDouble(double limit_exclusive) { return rndGetInstance().getDouble() * limit_exclusive; }
26inline unsigned int rndUint(unsigned int limit_exclusive) { return (unsigned int)(rndGetInstance().getDouble() * limit_exclusive); } //returns random from 0..limit_exclusive-1
27inline void rndSetSeed(unsigned int seed) { rndGetInstance().setSeed(seed); }
28inline unsigned int rndRandomizeSeed() { return rndGetInstance().randomize(); }
[109]29
[970]30
31
32// precision==-1 for full precision, or positive values for the number of digits to print past the decimal point.
33// Allocated buffer with bufferlen=30 is OK.
34// Returns the number of chars actually used (not including the ending 0).
35int doubleToString(double x, int precision, char *buffer, int bufferlen);
36
[979]37#include <string>
38std::string doubleToString(double x, int precision);
[970]39double round(const double x, const int precision);
[1253]40static inline void clipNegativeZeroIfNeeded(double& value, const double range_low)
41{
42        if (value == 0.0 && range_low == 0.0) // if we have range_low==0.0 and we get value==-0.0 (which is ==0.0)
43                value = 0.0; //turn -0.0 to 0.0 so that it does not look like exceeding the allowed range (even though -0.0==0.0). This code unnecessarily also "overwrites" value==0.0 with 0.0, but it is faster and simpler than additionally checking std::signbit(value) just to distinguish -0.0 from 0.0.
44        //these conditions are not intended for range_low==-0.0, as we assume nobody would define allowed ranges using -0.0.
45}
[970]46
47
48
49
50
[109]51//floating point specific numbers
52#include "stdlib.h"
53
54#ifdef __BORLANDC__
55        #include <float.h>
56        #define isnan(x) _isnan(x) //http://stackoverflow.com/questions/570669/checking-if-a-double-or-float-is-nan-in-c
57        #define finite(x) _finite(x)
58#endif
59
[122]60#ifdef LINUX
61  #define _isnan(a) isnan(a)
62#endif
63
[109]64#ifdef IPHONE
65        #define finite(x) (!isinf(x))
[122]66  #define _isnan(a) isnan(a)
[109]67#endif
68
69
[122]70#if defined SHP
[1275]71 //#define __assert_func(a,b,c,d) 0 //Currently, we are sorry to inform you that assert() is not yet supported. We have considered your request for internal discussion. Na szcz�cie jest w�asna (byle by by�a, bo i tak zak�adamy ze assert ktore przeciez dziala tylko w trybie debug nie jest potrzebne na bada) implementacja w "bada-assert.cpp"
[109]72 #define isnan(x) false //isnan() sie nie linkuje
73 #define finite(x) true //j.w.
74 //#include <cstdlib> //RAND_MAX defined incorrectly
75 //#ifdef BADA_SIMULATOR //...but only in simulator libs
76 // #undef RAND_MAX
77 // #define RAND_MAX 32768 //...this is the actual value used by rand()
78 //#endif
79#endif
80
[1275]81#if defined LINUX || defined TIZEN || defined __ANDROID__
82#include <fenv.h>
83#endif
84
85namespace fpExcept
86{
[109]87//handling floating point exceptions
[1275]88#if defined LINUX || defined TIZEN || defined __ANDROID__
89        //fenv.h values
90        static constexpr unsigned int FPEX_DIV0 = FE_DIVBYZERO;
91        static constexpr unsigned int FPEX_INVALID = FE_INVALID;
92        static constexpr unsigned int FPEX_OVERFLOW = FE_OVERFLOW;
93#elif defined IPHONE
94        // (not implemented but these constants are still needed)
95        static constexpr unsigned int FPEX_DIV0 = 0;
96        static constexpr unsigned int FPEX_INVALID = 0;
97        static constexpr unsigned int FPEX_OVERFLOW = 0;
98#else
99        //_control87() values
100        static constexpr unsigned int FPEX_DIV0 = EM_ZERODIVIDE;
101        static constexpr unsigned int FPEX_INVALID = EM_INVALID;
102        static constexpr unsigned int FPEX_OVERFLOW = EM_OVERFLOW;
103#endif
104        extern int wanted_exceptions;
105       
106        void init(); //call once, before ...Enable/Disable
107        void enable();
108        void disable();
109};
[109]110
[1053]111// std::lerp can be used since C++20 (and has some guaranteed properties probably better than this basic formula) but apparently it is not a template
[896]112template <typename Value, typename Linear> Value universal_lerp(Value a,Value b,Linear t) {return a*(1-t)+b*t;}
113
[913]114template <typename T> T linearTransform(T value, T min_in, T max_in, T min_out, T max_out)
115{
116        return min_out + (value-min_in)*(max_out-min_out)/(max_in-min_in);
117}
118
[1053]119//in C++20, related: https://en.cppreference.com/w/cpp/numeric/countl_zero
120#ifdef _WIN32 //visual studio is missing ffs()
121static inline unsigned ffs(int x)
122{
123        if (x == 0) return 0u;
124        unsigned r = 1;
125        while ((x & 1) == 0)
126                x >>= 1, ++r;
127        return r;
128}
[109]129#endif
[1053]130
131
132#endif
Note: See TracBrowser for help on using the repository browser.