Changeset 1251 for cpp/common


Ignore:
Timestamp:
06/22/23 03:21:19 (17 months ago)
Author:
Maciej Komosinski
Message:
  • unified Visual C++ and Borland setting of floating point exception flags
  • more flags for *nixes to really catch division by zero (FE_DIVBYZERO was not sufficient) and overflow
File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/common/nonstd_math.cpp

    r1026 r1251  
    11// This file is a part of Framsticks SDK.  http://www.framsticks.com/
    2 // Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
     2// Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
    33// See LICENSE.txt for details.
    44
     
    3030                (char*)
    3131#endif
    32                 str.data(); //now we will be operating directly on the internal std::string buffer
    33                 for (int i = str.length() - 1, end = str.length(); i >= 0; i--) //remove trailing zeros, and maybe also '.'
     32                        str.data(); //now we will be operating directly on the internal std::string buffer
     33                for (int i = int(str.length()) - 1, end = int(str.length()); i >= 0; i--) //remove trailing zeros, and maybe also '.'
    3434                {
    3535                        if (s[i] == '0')
     
    7676                strncpy(buffer, s.c_str(), std::min(bufferlen, (int)s.length() + 1));
    7777                buffer[bufferlen - 1] = 0; //ensure the string is truncated
    78                 return s.length();
     78                return int(s.length());
    7979        }
    8080}
     
    9191
    9292
     93// Idea: enable selected floating point exceptions when the app starts and disable them temporarily when dividing values in ExtValue, so that we can directly handle problematic cases there.
     94// This allows to catch problematic situations when the program performs calculations using NaN, INF etc.
     95
    9396#ifdef IPHONE
    9497//TODO! -> ? http://stackoverflow.com/questions/12762418/how-to-enable-sigfpe-signal-on-division-by-zero-in-ios-app
     
    121124#include <fenv.h>
    122125
    123 void fpExceptInit()
    124 {}
    125 
    126 void fpExceptEnable()
    127 {
    128         feclearexcept(FE_DIVBYZERO);
    129         feenableexcept(FE_DIVBYZERO);
    130 }
    131 
    132 void fpExceptDisable()
    133 {
    134         fedisableexcept(FE_DIVBYZERO);
    135 }
    136 
    137 #endif
    138 
    139 
    140 
    141 #ifdef __BORLANDC__
    142 // there was once a problem like this:
     126static constexpr int WANTED_FP_EXCEPTIONS = FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW;
     127
     128void fpExceptInit()
     129{}
     130
     131void fpExceptEnable()
     132{
     133        feclearexcept(WANTED_FP_EXCEPTIONS);
     134        feenableexcept(WANTED_FP_EXCEPTIONS);
     135}
     136
     137void fpExceptDisable()
     138{
     139        fedisableexcept(WANTED_FP_EXCEPTIONS);
     140}
     141
     142#endif
     143
     144
     145
     146#if defined(__BORLANDC__) || defined(_MSC_VER)
     147
     148// in Borland, there was once a problem like this:
    143149// http://qc.embarcadero.com/wc/qcmain.aspx?d=5128
    144150// http://www.delorie.com/djgpp/doc/libc/libc_112.html
     
    150156// 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)
    151157
    152 #include "log.h"
     158
     159#if defined(__BORLANDC__) // adding a missing constant and a function
     160#define _MCW_EM         0x0008001f              // Interrupt Exception Masks - from Visual C++'s float.h
     161
     162void _controlfp_s(unsigned int* _CurrentState, unsigned int  _NewValue, unsigned int  _Mask) //pretends to be the real _controlfp_s() function
     163{
     164        *_CurrentState = _control87(_NewValue, _Mask);
     165}
     166#endif
     167
     168#if defined(_MSC_VER)
     169#pragma fenv_access (on)
     170#endif
     171
     172// http://stackoverflow.com/questions/2769814/how-do-i-use-try-catch-to-catch-floating-point-errors
     173
     174//#include "log.h"
    153175
    154176unsigned int fp_control_word_std;
    155177unsigned int fp_control_word_muted;
    156178
    157 void fpExceptInit()
    158 {
    159         //unsigned int was=_clear87();
    160         //logPrintf("","fpExceptInit",LOG_INFO,"control87 status before clear was %08x", was);
    161         fp_control_word_std = _control87(0, 0);             //4978 = 1001101110010
     179
     180void fpExceptInit()
     181{
     182        _controlfp_s(&fp_control_word_std, 0, 0); //in Visual C++, the default value is exactly the masks listed below, and we have to turn them off to enable exceptions
    162183        // Make the new fp env same as the old one, except for the changes we're going to make
    163         fp_control_word_muted = fp_control_word_std | EM_INVALID | EM_DENORMAL | EM_ZERODIVIDE | EM_OVERFLOW | EM_UNDERFLOW | EM_INEXACT;  //4991 = 1001101111111
    164 }
    165 
    166 void fpExceptEnable()
    167 {
    168         unsigned int was = _clear87(); //trzeba czyscic zeby nie bylo exception...
    169         //logPrintf("","fpExceptEnable ",LOG_INFO,"control87 status before clear was %08x", was);
    170         _control87(fp_control_word_std, 0xffffffff);
    171         //logPrintf("","fpExceptEnable ",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
    172 }
    173 
    174 void fpExceptDisable()
    175 {
    176         unsigned int was = _clear87(); //trzeba czyscic zeby nie bylo exception...
     184        fp_control_word_muted = fp_control_word_std & ~(EM_INVALID | /*EM_DENORMAL |*/ EM_ZERODIVIDE | EM_OVERFLOW /* | EM_UNDERFLOW | EM_INEXACT */); //commented out exceptions that occur during proper operation
     185}
     186
     187void fpExceptEnable()
     188{
     189        //_fpreset(); //not needed since we just _clearfp()... mentioned in https://stackoverflow.com/questions/4282217/visual-c-weird-behavior-after-enabling-floating-point-exceptions-compiler-b
     190        unsigned int was = _clearfp(); //need to clean so that there is no exception...
     191        //logPrintf("","fpExceptEnable",LOG_INFO,"control87 status before clear was %08x", was);
     192        _controlfp_s(&was, fp_control_word_muted, _MCW_EM);
     193}
     194
     195void fpExceptDisable()
     196{
     197        //_fpreset(); //not needed since we just _clearfp()... mentioned in https://stackoverflow.com/questions/4282217/visual-c-weird-behavior-after-enabling-floating-point-exceptions-compiler-b
     198        unsigned int was = _clearfp(); //need to clean so that there is no exception...
    177199        //logPrintf("","fpExceptDisable",LOG_INFO,"control87 status before clear was %08x", was);
    178         _control87(fp_control_word_muted, 0xffffffff);
    179         //logPrintf("","fpExceptDisable",LOG_INFO,"control87 flags are %08x", _control87(0, 0)); //kontrola co sie ustawilo
    180 }
    181 
    182 #endif
    183 
    184 
    185 
    186 #ifdef _MSC_VER
    187 //Moznaby zrobic tak jak pod linuxem czyli wlaczyc exceptiony na poczatku i wylaczac na chwile przy dzieleniu w extvalue.
    188 //To by pozwoli³o na wy³apanie pod visualem z³ych sytuacji kiedy framsy licz¹ na NaN, INF itp.
    189 //http://stackoverflow.com/questions/2769814/how-do-i-use-try-catch-to-catch-floating-point-errors
    190 void fpExceptInit() {}
    191 void fpExceptEnable() {}
    192 void fpExceptDisable() {}
    193 #endif
     200        _controlfp_s(&was, fp_control_word_std, _MCW_EM);
     201}
     202#endif
Note: See TracChangeset for help on using the changeset viewer.