...
Operating System | How to handle floating point errors | |||
|---|---|---|---|---|
Linux | Use the C99 floating-point exception functions. | |||
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="a708a3d8774b2481-057353f0-4c82404e-a5148629-8980ebe2d7f79ff38bf06f07"><ac:plain-text-body><![CDATA[ | Windows | Either use the C99 floating-point exception function or structured exception handling through | AA. Bibliography#MSDN]] | ]]></ac:plain-text-body></ac:structured-macro> |
...
In this noncompliant code example, floating-point operations are performed without checking for errors. Note that range checking has been intentionally omitted because the intent is to detect errors following the floating-point operation.
| Code Block | ||||
|---|---|---|---|---|
| ||||
void fpOper_noErrorChecking(void) {
/* ... */
double a = 1e-40, b, c = 0.1;
float x = 0, y;
/* inexact and underflows */
y = a;
/* divide by zero operation */
b = y / x;
/* inexact (loss of precision) */
c = sin(30) * a;
/* ... */
}
|
...
This compliant solution uses C99 standard functions to handle floating-point errors.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
void fpOper_fenv(void) {
double a = 1e-40, b, c = 0.1;
float x = 0, y;
int fpeRaised;
/* ... */
feclearexcept(FE_ALL_EXCEPT);
/* Store a into y is inexact and underflows: */
y = a;
fpeRaised = fetestexcept(FE_ALL_EXCEPT);
/* fpeRaised has FE_INEXACT and FE_UNDERFLOW */
feclearexcept(FE_ALL_EXCEPT);
/* divide by zero operation */
b = y / x;
fpeRaised = fetestexcept(FE_ALL_EXCEPT);
/* fpeRaised has FE_DIVBYZERO */
feclearexcept(FE_ALL_EXCEPT);
c = sin(30) * a;
fpeRaised = fetestexcept(FE_ALL_EXCEPT);
/* fpeRaised has FE_INEXACT */
feclearexcept(FE_ALL_EXCEPT);
/* ... */
}
|
...
Microsoft Visual Studio 2008 and earlier versions do not support C99 functions to handle floating-point errors. Windows provides an alternative method for handling floating-point errors using _statusfp(), _statusfp2(), and _clearfp().
| Code Block | ||||
|---|---|---|---|---|
| ||||
void fpOper_usingStatus(void) {
/* ... */
double a = 1e-40, b, c;
float x = 0, y;
unsigned int rv = _clearfp();
/* Store into y is inexact and underflows: */
y = a;
rv = _clearfp(); /* rv has _SW_INEXACT and _SW_UNDERFLOW */
/* zero-divide */
b = y / x; rv = _clearfp(); /* rv has _SW_ZERODIVIDE */
/* inexact */
c = sin(30) * a; rv = _clearfp(); /* rv has _SW_INEXACT */
/* ... */
}
|
...
Microsoft Visual Studio 2008 also uses structured exception handling (SEH) to handle floating-point operation. SEH provides more information about the error and allows the programmer to change the results of the floating-point operation that caused the error condition.
| Code Block | ||||
|---|---|---|---|---|
| ||||
void fp_usingSEH(void) {
/* ... */
double a = 1e-40, b, c = 0.1;
float x = 0, y;
unsigned int rv ;
unmask_fpsr();
_try {
/* Store into y is inexact and underflows */
y = a;
/* divide by zero operation */
b = y / x;
/* inexact */
c = sin(30) * a;
}
_except (_fpieee_flt(
GetExceptionCode(),
GetExceptionInformation(),
fpieee_handler)) {
{
printf ("fpieee_handler: EXCEPTION_EXECUTE_HANDLER");
}
/* ... */
}
void unmask_fpsr(void) {
unsigned int u;
unsigned int control_word;
_controlfp_s(&control_word, 0, 0);
u = control_word & ~(_EM_INVALID
| _EM_DENORMAL
| _EM_ZERODIVIDE
| _EM_OVERFLOW
| _EM_UNDERFLOW
| _EM_INEXACT);
_controlfp_s( &control_word, u, _MCW_EM);
return ;
}
int fpieee_handler(_FPIEEE_RECORD *ieee) {
/* ... */
switch (ieee->RoundingMode) {
case _FpRoundNearest:
/* ... */
break;
/* Other RMs include _FpRoundMinusInfinity,
* _FpRoundPlusInfinity, _FpRoundChopped */
/* ... */
}
switch (ieee->Precision) {
case _FpPrecision24:
/* ... */
break;
/* Other Ps include _FpPrecision53*/
/* ... */
}
switch (ieee->Operation) {
case _FpCodeAdd:
/* ... */
break;
/* Other Ops include _FpCodeSubtract, _FpCodeMultiply,
* _FpCodeDivide, _FpCodeSquareRoot, _FpCodeCompare,
* _FpCodeConvert, _FpCodeConvertTrunc */
/* ... */
}
/*
* process the bitmap ieee->Cause.
* process the bitmap ieee->Enable.
* process the bitmap ieee->Status.
* process the Operand ieee->Operand1,
* evaluate format and Value.
* process the Operand ieee->Operand2,
* evaluate format and Value.
* process the Result ieee->Result,
* evaluate format and Value .
* The result should be set according to the operation
* specified in ieee->Cause and the result format as
* specified in ieee->Result.
*/
/* ... */
}
|
...