source: cpp/common/nonstd_math.cpp @ 970

Last change on this file since 970 was 970, checked in by Maciej Komosinski, 3 months ago

Added functions to properly round floating point values to specified precision

  • Property svn:eol-style set to native
File size: 4.5 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#ifdef USE_PRINTFLOAT_DRAGON4
7#include <PrintFloat/PrintFloat.h>
8#else
9#include <sstream>
10#endif
11
12RandomGenerator &rndGetInstance()
13{
14        static RandomGenerator rnd(0);
15        return rnd;
16}
17
18int doubleToString(double x, int precision, char *buffer, int bufferlen)
19{
20#ifdef USE_PRINTFLOAT_DRAGON4
21        return PrintFloat64(buffer, bufferlen, x,
22                ((x < -1e17) || (x > 1e17) || ((x < 1e-4) && (x > -1e-4) && (x != 0.0)))
23                ? PrintFloatFormat_Scientific : PrintFloatFormat_Positional,
24                precision); //http://www.ryanjuckett.com/programming/printing-floating-point-numbers/
25#else
26        char format[10];
27        sprintf(format, "%%.%dg", precision < 0 ? 17 : precision); //https://stackoverflow.com/questions/16839658/printf-width-specifier-to-maintain-precision-of-floating-point-value
28        return sprintf(buffer, format, x);
29#endif
30}
31
32
33double round(const double x, const int precision)
34{
35#ifdef USE_PRINTFLOAT_DRAGON4
36        char buffer[30];
37        doubleToString(x, precision, buffer, 30);
38        double rounded = strtod(buffer, NULL);
39#else
40        std::stringstream ss;
41        ss << std::fixed;
42        ss.precision(precision); // set the number of places after decimal
43        ss << x;
44        double rounded = stod(ss.str());
45#endif
46        //printf("%d  %20g \t %20g\n", precision, x, rounded); //for debugging
47        return rounded;
48}
49
50
51
52
53#ifdef IPHONE
54//TODO! -> ? http://stackoverflow.com/questions/12762418/how-to-enable-sigfpe-signal-on-division-by-zero-in-ios-app
55void fpExceptInit()
56{}
57
58void fpExceptEnable()
59{}
60
61void fpExceptDisable()
62{}
63#endif
64
65#ifdef MACOS
66//TODO...?
67
68void fpExceptInit()
69{}
70
71void fpExceptEnable()
72{}
73
74void fpExceptDisable()
75{}
76#endif
77
78
79#if defined LINUX || defined TIZEN || defined __ANDROID__
80
81#include <fenv.h>
82
83void fpExceptInit()
84{}
85
86void fpExceptEnable()
87{
88        feclearexcept(FE_DIVBYZERO);
89        feenableexcept(FE_DIVBYZERO);
90}
91
92void fpExceptDisable()
93{
94        fedisableexcept(FE_DIVBYZERO);
95}
96
97#endif
98
99
100
101#ifdef __BORLANDC__
102// there was once a problem like this:
103// http://qc.embarcadero.com/wc/qcmain.aspx?d=5128
104// http://www.delorie.com/djgpp/doc/libc/libc_112.html
105// ? http://www.c-jump.com/CIS77/reference/Intel/CIS77_24319002/pg_0211.htm
106// ? 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
107// ? http://www.plantation-productions.com/Webster/www.artofasm.com/Linux/HTML/RealArithmetica2.html
108// http://blogs.msdn.com/b/oldnewthing/archive/2008/07/03/8682463.aspx
109// where each cast of a double into an int would cause an exception.
110// 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)
111
112#include "log.h"
113
114unsigned int fp_control_word_std;
115unsigned int fp_control_word_muted;
116
117void fpExceptInit()
118{
119        //unsigned int was=_clear87();
120        //logPrintf("","fpExceptInit",LOG_INFO,"control87 status before clear was %08x", was);
121        fp_control_word_std = _control87(0, 0);             //4978 = 1001101110010
122        // Make the new fp env same as the old one, except for the changes we're going to make
123        fp_control_word_muted = fp_control_word_std | EM_INVALID | EM_DENORMAL | EM_ZERODIVIDE | EM_OVERFLOW | EM_UNDERFLOW | EM_INEXACT;  //4991 = 1001101111111
124}
125
126void fpExceptEnable()
127{
128        unsigned int was = _clear87(); //trzeba czyscic zeby nie bylo exception...
129        //logPrintf("","fpExceptEnable ",LOG_INFO,"control87 status before clear was %08x", was);
130        _control87(fp_control_word_std, 0xffffffff);
131        //logPrintf("","fpExceptEnable ",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
132}
133
134void fpExceptDisable()
135{
136        unsigned int was = _clear87(); //trzeba czyscic zeby nie bylo exception...
137        //logPrintf("","fpExceptDisable",LOG_INFO,"control87 status before clear was %08x", was);
138        _control87(fp_control_word_muted, 0xffffffff);
139        //logPrintf("","fpExceptDisable",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
140}
141
142#endif
143
144
145
146#ifdef _MSC_VER
147//Moznaby zrobic tak jak pod linuxem czyli wlaczyc exceptiony na poczatku i wylaczac na chwile przy dzieleniu w extvalue.
148//To by pozwoli³o na wy³apanie pod visualem z³ych sytuacji kiedy framsy licz¹ na NaN, INF itp.
149//http://stackoverflow.com/questions/2769814/how-do-i-use-try-catch-to-catch-floating-point-errors
150void fpExceptInit() {}
151void fpExceptEnable() {}
152void fpExceptDisable() {}
153#endif
Note: See TracBrowser for help on using the repository browser.