....
Which is a bad thing, of course. (I mean returning gibberish.)
The proper thing to do in a real time "show must go on scenario"
(like radar tracking of a missile ms before impact) is to
catch the error and substitute a reasonable value, and hope for
the best. Not to send your defense missile astray.
Any error protocol requires coordination between the library writer
and the library user. People often will simply ignore error codes
no matter how many lectures you deliver on the "proper thing" to do.
My point was that by defalt GSL calls abort on error and provides
no information in the case of "natural form" calling. I'm open
to better solutions than the one I suggested.
In the context of mathematical functions I just want to know
that the programmer goofed. If you as a project leader deleted
the programmers assert's you would have a very bad time with me.
If your head of IT agrees with you, I would take my business
elsewhere.
You sound like the kind of guy I wouldn't hire in the first place.
FWIW, here is an implementation of my proposed error protocol. It is not
portable, but it gives the idea.
/******************************************************************************
FILE ensure.h
DATE 2002-10-1
AUTHOR Keith A. Lewis [
[email protected]]
SYNOPSIS
#include "ensure.h"
ensure (expr);
bool ensure_is_error(double);
const char* ensure_message(double);
DESCRIPTION
Simple error protocol using NaNs.
The macro ensure(expr) works much like assert(expr) but
it does not call abort and it can only be used in
functions that return a double. If expr is false, a NaN
is returned. Use ensure_is_error() to detect ensure()
failures and ensure_message() to extract the error
string.
The function ensure_make_nan() embeds a char* into a
NaN. It is your responsibility to make sure that the
argument to ensure_make_nan() exists until
ensure_message() is done using it.
Define USE_ENSURE or _DEBUG before including ensure.h
in order to make ensure does its job. Unlike assert, the
default behavior is to define ensure with an empty
body.
BUGS:
Only works on 32-bit machines.
******************************************************************************/
#ifndef ENSURE_H
#define ENSURE_H
#include <math.h>
#include <float.h>
#if defined(_WIN32) && !defined(isnan)
#define isnan _isnan
#endif
#define D_(x) #x
#define S_(x) D_(x)
#if defined(USE_ENSURE) || defined(_DEBUG)
// TODO: offer more flexibility. (no return???)
#define ensure(e) { if (!(e)) \
return ensure_make_nan( \
"file: " __FILE__ \
" line: " S_(__LINE__) \
" error: " #e); }
#else
#define ensure(x)
#endif
// Typedefs and constants
typedef double ensure_error;
const ensure_error ensure_ok = 0;
typedef union {
long l[2];
double d;
} ensure_union;
/* Endian tests */
inline int ensure_lo() { static int i = 1; return *(char*)&i != 1; }
inline int ensure_hi() { static int i = 1; return *(char*)&i == 1; }
/* Equivalent to isnan() function. */
inline bool
ensure_is_error(double x)
{
ensure_union u;
u.d = x;
return u.l[ensure_lo()] == 0x7FFFFFFF || 0 != isnan(x);
}
/* Convert NaN to error message string. */
inline const char*
ensure_message(double x)
{
ensure_union u;
u.d = x;
#pragma warning(push)
#pragma warning(disable: 4312)
return u.l[ensure_lo()] == 0x7FFFFFFF ? (const
char*)u.l[ensure_hi()]
: isnan(x) ? "NaN" : "ensure_message: argument is not a NaN";
#pragma warning(pop)
}
/* Insert char* into NaN. You are respsible for the lifetime of s. */
inline double
ensure_make_nan(const char* const s)
{
ensure_union u;
if (0 == s)
return ensure_ok;
u.l[ensure_lo()] = 0x7FFFFFFF;
#pragma warning(push)
#pragma warning(disable: 4311)
u.l[ensure_hi()] = (long)s;
#pragma warning(pop)
return u.d;
}
#ifdef isnan
#undef isnan
#endif
#endif /* ENSURE_H */