source: cpp/common/nonstd_math.cpp @ 980

Last change on this file since 980 was 980, checked in by Maciej Komosinski, 2 months ago

Added missing #include for *nix

  • Property svn:eol-style set to native
File size: 4.8 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "nonstd_math.h"
6#include <PrintFloat/PrintFloat.h>
7#include <string.h> // strncpy()
8#include <sstream>
9#include <algorithm> // std::min()
10
11RandomGenerator &rndGetInstance()
12{
13        static RandomGenerator rnd(0);
14        return rnd;
15}
16
17std::string doubleToString(double x, int precision)
18{
19        std::stringstream ss;
20        ss << std::fixed;
21        ss.precision(precision); //set the number of places after decimal
22        ss << x;
23        return ss.str();
24}
25
26int doubleToString(double x, int precision, char *buffer, int bufferlen)
27{
28        // C++ in 2020 and the impossible challenge https://stackoverflow.com/questions/277772/avoid-trailing-zeroes-in-printf
29        if (precision < 0)
30        {
31                // The "g" format does not allow to use the number of decimal places after the decimal point. Dragon4 on the other hand fills in unnecessary trailinig zeros... so both are good only for "full precision".
32#ifdef USE_PRINTFLOAT_DRAGON4
33                return PrintFloat64(buffer, bufferlen, x,
34                        ((x < -1e17) || (x > 1e17) || ((x < 1e-4) && (x > -1e-4) && (x != 0.0)))
35                        ? PrintFloatFormat_Scientific : PrintFloatFormat_Positional,
36                        precision); //http://www.ryanjuckett.com/programming/printing-floating-point-numbers/
37#else
38                return sprintf(buffer, "%.17g", x);
39#endif
40        }
41        else
42        {
43                std::string s = doubleToString(x, precision);
44                strncpy(buffer, s.c_str(), std::min(bufferlen, (int)s.length() + 1));
45                buffer[bufferlen - 1] = 0; //ensure the string is truncated
46                return s.length();
47        }
48}
49
50
51double round(const double x, const int precision)
52{
53        double rounded = std::stod(doubleToString(x, precision));
54        //printf("%d  %20g \t %20g\n", precision, x, rounded); //for debugging
55        return rounded;
56}
57
58
59
60
61#ifdef IPHONE
62//TODO! -> ? http://stackoverflow.com/questions/12762418/how-to-enable-sigfpe-signal-on-division-by-zero-in-ios-app
63void fpExceptInit()
64{}
65
66void fpExceptEnable()
67{}
68
69void fpExceptDisable()
70{}
71#endif
72
73#ifdef MACOS
74//TODO...?
75
76void fpExceptInit()
77{}
78
79void fpExceptEnable()
80{}
81
82void fpExceptDisable()
83{}
84#endif
85
86
87#if defined LINUX || defined TIZEN || defined __ANDROID__
88
89#include <fenv.h>
90
91void fpExceptInit()
92{}
93
94void fpExceptEnable()
95{
96        feclearexcept(FE_DIVBYZERO);
97        feenableexcept(FE_DIVBYZERO);
98}
99
100void fpExceptDisable()
101{
102        fedisableexcept(FE_DIVBYZERO);
103}
104
105#endif
106
107
108
109#ifdef __BORLANDC__
110// there was once a problem like this:
111// http://qc.embarcadero.com/wc/qcmain.aspx?d=5128
112// http://www.delorie.com/djgpp/doc/libc/libc_112.html
113// ? http://www.c-jump.com/CIS77/reference/Intel/CIS77_24319002/pg_0211.htm
114// ? http://www.jaist.ac.jp/iscenter-new/mpc/altix/altixdata/opt/intel/vtune/doc/users_guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/mergedProjects/instructions/instruct32_hh/vc100.htm
115// ? http://www.plantation-productions.com/Webster/www.artofasm.com/Linux/HTML/RealArithmetica2.html
116// http://blogs.msdn.com/b/oldnewthing/archive/2008/07/03/8682463.aspx
117// where each cast of a double into an int would cause an exception.
118// But it was resolved by restarting windows and cleaning all intermediate compilation files :o (restarting windows was the key element! restarting BC++Builder and deleting files would not help)
119
120#include "log.h"
121
122unsigned int fp_control_word_std;
123unsigned int fp_control_word_muted;
124
125void fpExceptInit()
126{
127        //unsigned int was=_clear87();
128        //logPrintf("","fpExceptInit",LOG_INFO,"control87 status before clear was %08x", was);
129        fp_control_word_std = _control87(0, 0);             //4978 = 1001101110010
130        // Make the new fp env same as the old one, except for the changes we're going to make
131        fp_control_word_muted = fp_control_word_std | EM_INVALID | EM_DENORMAL | EM_ZERODIVIDE | EM_OVERFLOW | EM_UNDERFLOW | EM_INEXACT;  //4991 = 1001101111111
132}
133
134void fpExceptEnable()
135{
136        unsigned int was = _clear87(); //trzeba czyscic zeby nie bylo exception...
137        //logPrintf("","fpExceptEnable ",LOG_INFO,"control87 status before clear was %08x", was);
138        _control87(fp_control_word_std, 0xffffffff);
139        //logPrintf("","fpExceptEnable ",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
140}
141
142void fpExceptDisable()
143{
144        unsigned int was = _clear87(); //trzeba czyscic zeby nie bylo exception...
145        //logPrintf("","fpExceptDisable",LOG_INFO,"control87 status before clear was %08x", was);
146        _control87(fp_control_word_muted, 0xffffffff);
147        //logPrintf("","fpExceptDisable",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
148}
149
150#endif
151
152
153
154#ifdef _MSC_VER
155//Moznaby zrobic tak jak pod linuxem czyli wlaczyc exceptiony na poczatku i wylaczac na chwile przy dzieleniu w extvalue.
156//To by pozwoli³o na wy³apanie pod visualem z³ych sytuacji kiedy framsy licz¹ na NaN, INF itp.
157//http://stackoverflow.com/questions/2769814/how-do-i-use-try-catch-to-catch-floating-point-errors
158void fpExceptInit() {}
159void fpExceptEnable() {}
160void fpExceptDisable() {}
161#endif
Note: See TracBrowser for help on using the repository browser.