Question:
How can I force calculations to be executed before a certain point in C?
Nobody
2011-08-19 04:46:33 UTC
If for example I want to test for a floating point exception with fetestexcept() I would want to make sure that all relevant floating point operations are executed before the call to fetestexcept.

When optimizing the compiler may choose to delay some operations up to the point when the result is first used. Is there a standard way to communicate to the compiler, that at a certain point in code all calculations should be finished or, if not, is there a gcc extension to care for that?
Three answers:
?
2011-08-19 07:28:14 UTC
Floating point exceptions ARE defined by the language, they are not "hidden". The program behavior with regards to floating point status flags is explicitly defined, in detail



Here's what ISO 9899:1999 has to say



F.8.1 Global transformations

1. Floating-point arithmetic operations and external function calls may entail side effects which optimization shall honor, at least where the state of the FENV_ACCESS pragma is ‘‘on’’. The flags and modes in the floating-point environment may be regarded as global variables; floating-point operations (+, *, etc.) implicitly read the modes and write the flags.



2. Concern about side effects may inhibit code motion and removal of seemingly useless code. For example, in

#include

#pragma STDC FENV_ACCESS ON

void f(double x)

{

     /* ... */

     for (i = 0; i < n; i++) x + 1;

     /* ... */

}

x + 1 might raise floating-point exceptions, so cannot be removed. And since the loop body might not execute (maybe 0 >= n), x + 1 cannot be moved out of the loop.



3. This specification does not require support for trap handlers that maintain information about the order or count of floating-point exceptions. Therefore, between function calls, floating-point exceptions need not be precise: the actual order and number of occurrences of floating-point exceptions (> 1) may vary from what the source code expresses. Thus, the preceding loop could be treated as

     if (0 < n) x + 1;



(there are many more chapters about expression transformations, operators, etc. Even constant arithmetic raises exceptions at run-time, the compiler is prohibited from folding it in at translation time)



So, in short, don't worry about it if your compiler is conforming



However, you're using GCC, which is not conforming: it does not implement FENV_ACCESS (bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20785 ) and does in fact reorder floating-point operations in ways that affect the generations of floating-point exceptions (bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38960 and many others )





To "force calculations to be executed before a certain point", write the value obtained from that calculation in an object of any volatile type (such as volatile double) -- any volatile object access is visible side-effect, it cannot be skipped or reordered in any way. (per ISO 9899:1999 5.1.2.3/5, execution of a C program is defined in terms of volatile reads, volatile writes, file I/O and interactive I/O)



#include

#include

#include



void test(void)

{

     int set_excepts = fetestexcept(FE_INVALID | FE_DIVBYZERO);

     if (set_excepts & FE_DIVBYZERO)

         puts("Detected FE_DIVBYZERO");

     if (set_excepts & FE_INVALID)

         puts("Detected FE_INVALID");

     feclearexcept(FE_INVALID | FE_DIVBYZERO);

}



volatile double v;



int main(void)

{

     feclearexcept(FE_INVALID | FE_DIVBYZERO);

     test();

     double d = 1.0 / 0.0; // might even read 1.0 from some volatile double to be sure

     v = d; // necessary for GCC with optimizations enabled

     puts("Attempted to divide by zero: ");

     test();

     puts("Attempted sqrt(-1): ");

     d = sqrt(-1.0);

     v = d; // not necessary for gcc, but a bad compiler may need this

     test();

}



test: http://ideone.com/n4iUm
PleaseInsertACoin
2011-08-19 12:06:40 UTC
I *think* that

#pragma STDC FENV_ACCESS on



prevents optimizations that would interfere with side effects of floating point operations. But I don't know if gcc supports the pragma, you should look that up yourself.
gh0st Rider
2011-08-19 12:13:02 UTC
I'm not sure what you actually want to achieve but sounds like your solution is to use Comma "," operator to define order of evaluation of an expression. Note: It should not be confused with the comma in initialising lists (ie: int x, int y; ) nor with function call parameter separation comma (ie: func(x, y) ). So use comma operator judiciously .



for e.g:

void ba(){

std::cout<<"ba will be called first"<
}

void ca(){

std::cout<<"ca will be called second"<
}



int main(){

(ba(), ca()); // in this expression ca() will always be called before ca()

}



output:

ba will be called first

ca will be called second



Edit: @Nobody: I don't have solution for it but wait (i am also waiting ) for Mr.Cubbi , I can bet 100% he will have some solution for you)


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...