source: cpp/common/nonstd_math.cpp @ 970

Last change on this file since 970 was 970, checked in by Maciej Komosinski, 4 years ago

Added functions to properly round floating point values to specified precision

  • Property svn:eol-style set to native
File size: 4.5 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[970]2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[122]4
[109]5#include "nonstd_math.h"
[970]6#ifdef USE_PRINTFLOAT_DRAGON4
7#include <PrintFloat/PrintFloat.h>
8#else
9#include <sstream>
10#endif
[109]11
[896]12RandomGenerator &rndGetInstance()
[109]13{
[867]14        static RandomGenerator rnd(0);
15        return rnd;
[109]16}
17
[970]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}
[109]31
32
[970]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}
[109]49
50
[970]51
52
[247]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{}
[109]57
[247]58void fpExceptEnable()
59{}
[109]60
[247]61void fpExceptDisable()
62{}
63#endif
[109]64
[285]65#ifdef MACOS
66//TODO...?
[247]67
[285]68void fpExceptInit()
69{}
70
71void fpExceptEnable()
72{}
73
74void fpExceptDisable()
75{}
76#endif
77
78
[247]79#if defined LINUX || defined TIZEN || defined __ANDROID__
80
[109]81#include <fenv.h>
82
83void fpExceptInit()
84{}
85
86void fpExceptEnable()
87{
[867]88        feclearexcept(FE_DIVBYZERO);
89        feenableexcept(FE_DIVBYZERO);
[109]90}
91
92void fpExceptDisable()
93{
[867]94        fedisableexcept(FE_DIVBYZERO);
[109]95}
96
97#endif
98
99
100
101#ifdef __BORLANDC__
[145]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)
[109]111
[375]112#include "log.h"
[109]113
114unsigned int fp_control_word_std;
115unsigned int fp_control_word_muted;
116
117void fpExceptInit()
118{
119        //unsigned int was=_clear87();
[375]120        //logPrintf("","fpExceptInit",LOG_INFO,"control87 status before clear was %08x", was);
[867]121        fp_control_word_std = _control87(0, 0);             //4978 = 1001101110010
[109]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{
[867]128        unsigned int was = _clear87(); //trzeba czyscic zeby nie bylo exception...
[375]129        //logPrintf("","fpExceptEnable ",LOG_INFO,"control87 status before clear was %08x", was);
[109]130        _control87(fp_control_word_std, 0xffffffff);
[375]131        //logPrintf("","fpExceptEnable ",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
[109]132}
133
134void fpExceptDisable()
135{
[867]136        unsigned int was = _clear87(); //trzeba czyscic zeby nie bylo exception...
[375]137        //logPrintf("","fpExceptDisable",LOG_INFO,"control87 status before clear was %08x", was);
[109]138        _control87(fp_control_word_muted, 0xffffffff);
[375]139        //logPrintf("","fpExceptDisable",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
[109]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.