root/branches/newmole/source/cddefines.h

Revision 2596, 46.6 kB (checked in by rporter, 13 days ago)

branches/newmole/source - bring in trunk r2592:2595, except I blocked the changes to ion_solver.cpp.

  • Property svn:eol-style set to native
Line 
1/* This file is part of Cloudy and is copyright (C)1978-2008 by Gary J. Ferland and
2 * others.  For conditions of distribution and use see copyright notice in license.txt */
3
4#ifndef _CDDEFINES_H_
5#define _CDDEFINES_H_
6
7#ifdef _MSC_VER
8/* disable warning that conditional expression is constant, true or false in if */
9#       pragma warning( disable : 4127 )
10/* we are not using MS foundation class */
11#       ifndef WIN32_LEAN_AND_MEAN
12#               define WIN32_LEAN_AND_MEAN
13#       endif
14#endif
15/* these headers are needed by all files */
16/*lint -e129 these resolve several issues pclint has with my system headers */
17/*lint -e78 */
18/*lint -e830 */
19/*lint -e38 */
20/*lint -e148 */
21/*lint -e114 */
22/*lint -e18 */
23/*lint -e49 */
24#include <stdio.h>
25#include <stdlib.h>
26#include <math.h>
27#include <assert.h>
28#include <string.h>
29#include <float.h>
30#include <limits>
31#include <limits.h>
32#include <time.h>
33#include <signal.h>
34#include <string>
35#include <sstream>
36#include <vector>
37#include <valarray>
38#include <complex>
39#include <map>
40#include <memory>
41#include <stdexcept>
42#include <algorithm>
43#include <fstream>
44#include <bitset>
45#ifdef DMALLOC
46#include <dmalloc.h>
47#endif
48/*lint +e18 */
49/*lint +e49 */
50/*lint +e38 */
51/*lint +e148 */
52/*lint +e830 */
53/*lint +e78 */
54/*lint -e129 */
55
56using namespace std;
57
58/** define EXTERN as nothing before including cddefines.h to allocate global data */
59#ifndef EXTERN
60#define EXTERN extern
61#endif
62
63#undef STATIC
64#ifdef USE_GPROF
65#define STATIC
66#else
67#define STATIC static
68#endif
69
70#ifdef FLT_IS_DBL
71typedef double realnum;
72#else
73typedef float realnum;
74#endif
75
76//Compile-time assertion after Alexandrescu
77template<bool> struct StaticAssertFailed;
78template<> struct StaticAssertFailed<true> {};
79#define STATIC_ASSERT(x) ((void)StaticAssertFailed< (x) == true >())
80
81typedef float sys_float;
82// prevent explicit float's from creeping back into the code
83#define float PLEASE_USE_REALNUM_NOT_FLOAT
84
85/* make sure this is globally visible as well! */
86#include "cpu.h"
87
88//*************************************************************************
89//
90//! Singleton: template to construct classes where a single instance can
91//! be accessed across the entire program. Construct your class as follows:
92//!
93//! class t_myclass : public Singleton<t_myclass>
94//! {
95//!     friend class Singleton<t_myclass>;
96//! protected:
97//!     t_myclass(); // make sure the contructor is protected!
98//! public:
99//!     long myfunc() const { return 43; }
100//! };
101//!
102//! and use as follows throughout the code:
103//!
104//! long l = t_myclass::Inst().myfunc();
105//!
106//!   NB NB - This implementation is not threadsafe !!
107//
108// This implementation has been obtained from Wikipedia
109//
110//*************************************************************************
111
112template<typename T> class Singleton
113{
114public:
115        static T& Inst()
116        {
117                static T instance;  // assumes T has a protected default constructor
118                return instance;
119        }
120};
121
122/**************************************************************************
123 *
124 * these are variables and pointers for output from the code, used everywhere
125 * declared extern here, and definition is in cddefines.cpp
126 *
127 **************************************************************************/
128
129/** ioQQQ is the file hand to the output file itself,
130 * ioQQQ is set to stdout by default in cdInit,
131 * and is reset to anything else by calling cdOutp */
132EXTERN FILE *ioQQQ;
133
134EXTERN FILE *ioStdin;
135
136extern FILE *ioMAP;
137
138/** we shall write errors to this file, it is set
139 * to stderr in cdInit */
140EXTERN FILE* ioPrnErr;
141
142/** this set true when abort sequence is initiated - serious meltdown is happening */
143EXTERN bool lgAbort;
144
145/** flag lgTestIt turned on if routine TestCode ever called, only generates
146 * comment that test code is in place */
147EXTERN bool lgTestCodeCalled;
148
149/** flag lgTestOn set true with SET TEST command
150 * for some test code to be run somewhere */
151EXTERN bool lgTestCodeEnabled;
152
153/** this is flag saying whether to print errors to
154 * standard error output */
155EXTERN bool lgPrnErr;
156
157/** nzone is zone counter, incremented in routine cloudy
158 * is zero during search phase, 1 for first zone at illuminated face */
159EXTERN long int nzone;
160
161/** this is nzone + conv.nPres2Ioniz/100 in ConvBase */
162EXTERN double fnzone;
163
164/** the iteration counter, set and incremented in routine cloudy,
165 * ==1 during first iteration, 2 during second, etc */
166EXTERN long int iteration;
167
168/** number of simulations done with this coreload - 1 for first sim */
169EXTERN long int nSimThisCoreload;
170
171/**
172 * this is the number zero, used to trick clever compilers when
173 * dividing by it to crash program
174 * there is a routine called zero - this name cannot overlap
175 * definition is in cddefines.cpp
176 */
177extern const double ZeroNum;
178
179/**************************************************************************
180 *
181 * these are constants used to dimension several vectors and index arrays
182 *
183 **************************************************************************/
184
185/** FILENAME_PATH_LENGTH is the size of the string that holds the path.  The longest
186 * string that can be held is one less than this, due to the end
187 * end of string sentinel in C.  Increase this is a larger string
188 * is needed to hold the path on your system */
189const int FILENAME_PATH_LENGTH = 200;
190
191/** twice the above, so that we can add file name to end of full path */
192const int FILENAME_PATH_LENGTH_2  = FILENAME_PATH_LENGTH*2;
193
194/** this is limit to longest line of information that is scanned in,
195 * end of line char is actually at this +1, dim of vector is this + 1
196 * all routines that scan in information should use this to dim vars */ 
197const int INPUT_LINE_LENGTH = 200;
198
199/** This is the number of elements included in the code,
200 * is used to set lengths of many vectors */
201const int LIMELM = 30;
202
203/** the number of iso sequences now in the code */
204const int NISO = 2;
205
206/** following is real limit to how many levels can be computed for
207 * model hydrogen atom - this has the one extra included, so at most
208 * iso.numLevels_max[ipH_LIKE] can be NHYDRO_MAX_LEVEL-1 and vectors should be dim NHYDRO_MAX_LEVEL*/
209const int NHYDRO_MAX_LEVEL = 401;
210
211/** this is the maximum particle density allowed in cm^-3 */
212const double MAX_DENSITY = 1.e21;
213
214#if 0
215/** The default value of the stopping temperature */
216const double TEMP_STOP_DEFAULT = 4000.;
217/** highest temperature to ever allow */
218const double TEMP_LIMIT_HIGH = 1e10;
219/** lowest temperature to ever allow */
220const double TEMP_LIMIT_LOW = 2.8;
221#endif
222
223/** this is used to add to depth to prevent div or log of zero */
224const double DEPTH_OFFSET = 1.e-30;
225
226 /* these are flags for various colliders that are used across the code */
227enum collider {
228        ipELECTRON,
229        ipPROTON,
230        ipHE_PLUS,
231        ipALPHA,
232        //ipATOMH,
233        //ipHE_2PLUS,
234        //ipH2_ORTHO,
235        //ipH2_PARA,
236        ipNCOLLIDER
237};
238
239/* indices within recombination coefficient array */
240/* ipRecEsc is state specific escape probability*/
241const int ipRecEsc = 2;
242/* the net escaping, including destruction by background and optical deepth*/
243const int ipRecNetEsc = 1;
244/* ipRecRad is state specific radiative recombination rate*/
245const int ipRecRad = 0;
246/** with the above, the total radiative rec per ion is
247 * iso.RadRecomb[ipISO][nelem][n][ipRecRad]*
248   iso.RadRecomb[ipISO][nelem][n][ipRecNetEsc]*dense.eden; */
249
250/* these specify the form of the line redistribution function */
251/* partial redistribution with wings */
252const int ipPRD = 1;
253/* complete redistribution, core only, no wings, Hummer's K2 function */
254const int ipCRD = -1;
255/* complete redistribution with wings */
256const int ipCRDW = 2;
257/* redistribution function for Lya, calls Hummer routine for H-like series only */
258const int ipLY_A = -2;
259/* core function for K2 destruction */
260const int ipDEST_K2 = 1;
261/* core function for complete redist destruction */
262const int ipDEST_INCOM = 2;
263/* core function for simple destruction */
264const int ipDEST_SIMPL = 3;
265
266/** some levels for hydrogenic species */
267
268const int ipH1s = 0;
269const int ipH2s = 1;
270const int ipH2p = 2;
271const int ipH3s = 3;
272const int ipH3p = 4;
273const int ipH3d = 5;
274const int ipH4s = 6;
275const int ipH4p = 7;
276const int ipH4d = 8;
277const int ipH4f = 9;
278const int ipH5s = 10;
279const int ipH5p = 11;
280const int ipH5d = 12;
281const int ipH5f = 13;
282const int ipH5g = 14;
283const int ipH6s = 15;
284
285/** some levels for he-like species */
286
287/* level 1 */
288const int ipHe1s1S = 0;
289
290/* level 2 */
291const int ipHe2s3S = 1;
292const int ipHe2s1S = 2;
293const int ipHe2p3P0 = 3;
294const int ipHe2p3P1 = 4;
295const int ipHe2p3P2 = 5;
296const int ipHe2p1P = 6;
297
298/* level 3 */
299const int ipHe3s3S = 7;
300const int ipHe3s1S = 8;
301const int ipHe3p3P = 9;
302const int ipHe3d3D = 10;
303const int ipHe3d1D = 11;
304const int ipHe3p1P = 12;
305
306/* level 4 */
307const int ipHe4s3S = 13;
308const int ipHe4s1S = 14;
309const int ipHe4p3P = 15;
310const int ipHe4d3D = 16;
311const int ipHe4d1D = 17;
312const int ipHe4f3F = 18;
313const int ipHe4f1F = 19;
314const int ipHe4p1P = 20;
315
316/** these are array indices for isoelectronic sequences,
317 * same as element but used for array addressing to make
318 * context totally clear */
319const int ipH_LIKE = 0;
320const int ipHE_LIKE = 1;
321const int ipLI_LIKE = 2;
322const int ipBE_LIKE = 3;
323const int ipB_LIKE = 4;
324const int ipC_LIKE = 5;
325const int ipN_LIKE = 6;
326const int ipO_LIKE = 7;
327const int ipF_LIKE = 8;
328const int ipNE_LIKE = 9;
329const int ipNA_LIKE = 10;
330const int ipMG_LIKE = 11;
331const int ipAL_LIKE = 12;
332const int ipSI_LIKE = 13;
333const int ipP_LIKE = 14;
334const int ipS_LIKE = 15;
335const int ipCL_LIKE = 16;
336const int ipAR_LIKE = 17;
337
338/** these are indices for some elements, on the C scale */
339const int ipHYDROGEN = 0;
340const int ipHELIUM = 1;
341const int ipLITHIUM = 2;
342const int ipBERYLLIUM = 3;
343const int ipBORON = 4;
344const int ipCARBON = 5;
345const int ipNITROGEN = 6;
346const int ipOXYGEN = 7;
347const int ipFLUORINE = 8;
348const int ipNEON = 9;
349const int ipSODIUM = 10;
350const int ipMAGNESIUM = 11;
351const int ipALUMINIUM = 12;
352const int ipSILICON = 13;
353const int ipPHOSPHORUS = 14;
354const int ipSULPHUR = 15;
355const int ipCHLORINE = 16;
356const int ipARGON = 17;
357const int ipPOTASSIUM = 18;
358const int ipCALCIUM = 19;
359const int ipSCANDIUM = 20;
360const int ipTITANIUM = 21;
361const int ipVANADIUM = 22;
362const int ipCHROMIUM = 23;
363const int ipMANGANESE = 24;
364const int ipIRON = 25;
365const int ipCOBALT = 26;
366const int ipNICKEL = 27;
367const int ipCOPPER = 28;
368const int ipZINC = 29;
369
370/***************************************************************************
371 * the following are prototypes for some routines that are part of the
372 * debugging process - they come and go in any particular sub. 
373 * it is not necessary to declare them when used since they are defined here
374 **************************************************************************/
375
376/**
377 fudge enter fudge factors, or some arbitrary number, with fudge command
378 return value is the fudge factor
379 fudge(-1) queries the routine for the number of fudge parameters that
380 were entered, zero returned if none
381 \param ipnt integer saying which of the possible numbers on the fudge
382 command to use - 0 would be the first
383 */ 
384double fudge(long int ipnt);
385
386/**
387 broken set flag saying that the code is broken
388 */ 
389void broken(void);
390
391/**fixit set flag saying that this code needs attention, but is not broken,
392 * code is in service.cpp */
393void fixit(void);
394
395/**CodeReview - placed next to code that needs to be checked */ 
396void CodeReview(void);
397
398/**TestCode set flag saying that test code is in place */
399void TestCode(void);
400
401/**MyMalloc wrapper for malloc().  Returns a good pointer or dies.
402\param size use same type as library function malloc
403\param file
404\param line
405*/
406void *MyMalloc(size_t size, const char *file, int line);
407
408/**MyCalloc wrapper for calloc().  Returns a good pointer or dies.
409\param num use same type as library function CALLOC
410\param size
411*/
412void *MyCalloc(size_t num, size_t size);
413
414/**MyRealloc wrapper for realloc().  Returns a good pointer or dies.
415\param num use same type as library function REALLOC
416\param size
417*/
418void *MyRealloc(void *p, size_t size);
419
420/** MyAssert a version of assert that fails gracefully
421\param *file
422\param line
423*/ 
424void MyAssert(const char *file, int line);
425
426/** the Cloudy exit handler
427\param iexit, EXIT_FAILURE for failure, EXIT_SUCCESS for success
428*/
429NORETURN void cdExit(int iexit);
430
431class cloudy_exit
432{
433        const char* p_routine;
434        const char* p_file;
435        long p_line;
436        int p_exit;
437public:
438        cloudy_exit(const char* routine, const char* file, long line, int exit_code)
439        {
440                p_routine = routine;
441                p_file = file;
442                p_line = line;
443                p_exit = exit_code;
444        }
445        virtual ~cloudy_exit() throw()
446        {
447                p_routine = NULL;
448                p_file = NULL;
449        }
450        const char* routine() const throw()
451        {
452                return p_routine;
453        }
454        const char* file() const throw()
455        {
456                return p_file;
457        }
458        long line() const
459        {
460                return p_line;
461        }
462        int exit_status() const
463        {
464                return p_exit;
465        }
466};
467
468// workarounds for __func__ are defined in cpu.h
469#define cdEXIT( FAIL ) throw cloudy_exit( __func__, __FILE__, __LINE__, FAIL )
470
471// calls like puts( "[Stop in MyRoutine]" ) have been integrated in cdEXIT above
472#define puts( STR ) Using_puts_before_cdEXIT_is_no_longer_needed
473
474/** print comment asking to show output to me */
475void ShowMe(void);
476
477/**TotalInsanity general error handler for something that cannot happen, exits */
478NORETURN void TotalInsanity(void);
479
480/**BadRead tried to read internal data and failed */
481NORETURN void BadRead(void);
482
483/**BadOpen tried to open data files and failed */
484NORETURN void BadOpen(void);
485
486/**
487   NoNumb general error handler for no numbers on input line
488   \param *chCard
489 */ 
490NORETURN void NoNumb(char *chCard);
491
492/** dbg_printf is a debug print routine that was provided by Peter Teuben,
493 * as a component from his NEMO package.  It offers run-time specification
494 * of the level of debugging */ 
495int dbg_printf(int debug, const char *fmt, ...);
496
497/** dprintf -- version of fprintf which prepends DEBUG */
498int dprintf(FILE *fp, const char *format, ...);
499
500/**read_whole_line safe version of fgets - read a line,
501 * return null if cannot read line or if input line is too long
502 \param char *chLine - previously allocated string where the line
503 image will be stored
504 \param int nChar size of chLine, we will return NULL if input line is
505 longer than this
506 \param FILE *ioIN a previously opened file handle, will read from from here
507*/
508char *read_whole_line( char *chLine , int nChar , FILE *ioIN );
509
510/**************************************************************************
511 *
512 * various macros used by the code
513 *
514 **************************************************************************/
515
516/** to avoid errors introduced by C's infamous double-negative logic,
517 * this uses NDEBUG (the ANSI std macro used to tell assert that
518 * we are not debugging) to define DEBUG */
519#ifndef NDEBUG
520#       define DEBUG
521#else
522#       undef DEBUG
523#endif
524
525/** use special version of malloc - it tests result and dies if cannot allocate space */
526#if defined(malloc)
527/* ...but if malloc is a macro, assume it is instrumented by a memory debugging tool
528 * (e.g. dmalloc) */
529#       define MALLOC(exp) (malloc(exp))
530#else
531/* Otherwise instrument and protect it ourselves */
532#       define MALLOC(exp) (MyMalloc(exp,__FILE__, __LINE__))
533#endif
534
535/** now special version of calloc - it dies if cannot allocate space. */
536#if defined(calloc)
537/* ...but if calloc is a macro, assume it is instrumented by a memory debugging tool */
538#       define CALLOC calloc
539#else
540/* Otherwise instrument and protect it ourselves */
541#       define CALLOC MyCalloc
542#endif
543
544/** now special version of calloc - it dies if cannot allocate space. */
545#if defined(realloc)
546/* ...but if calloc is a macro, assume it is instrumented by a memory debugging tool */
547#       define REALLOC realloc
548#else
549/* Otherwise instrument and protect it ourselves */
550#       define REALLOC MyRealloc
551#endif
552
553class bad_signal
554{
555        int p_sig;
556public:
557        explicit bad_signal(int sig)
558        {
559                p_sig = sig;
560        }
561        virtual ~bad_signal() throw() {}
562        int sig() const throw()
563        {
564                return p_sig;
565        }
566};
567
568class bad_assert
569{
570        const char* p_file;
571        long p_line;
572public:
573        bad_assert(const char* file, long line)
574        {
575                p_file = file;
576                p_line = line;
577        }
578        virtual ~bad_assert() throw()
579        {
580                p_file = NULL;
581        }
582        const char* file() const throw()
583        {
584                return p_file;
585        }
586        long line() const throw()
587        {
588                return p_line;
589        }
590};
591
592class bad_mpi {
593        long p_failMode;
594public:
595        bad_mpi(long failMode) : p_failMode(failMode) {}
596        long failMode() const { return p_failMode; }
597};
598
599/* the do { ... } while ( 0 ) construct prevents bugs in code like this:
600 * if( test )
601 *      ASSERT( n == 10 );
602 * else
603 *      do something else...
604 */
605#undef  ASSERT
606#ifndef OLD_ASSERT
607/** a cloudy version of the assert macro that can be recovered from */
608#       ifdef NDEBUG
609#               define ASSERT(exp) ((void)0)
610#       else
611#               define ASSERT(exp) \
612                        do { \
613                                if (!(exp)) \
614                                { \
615                                        if( cpu.lgAssertAbort() ) \
616                                                abort();          \
617                                        else \
618                                                throw bad_assert(__FILE__,__LINE__); \
619                                } \
620                        } while( 0 )
621#       endif
622#else
623/** the old version of the assert macro that terminates safely */
624#       ifdef NDEBUG
625#               define ASSERT(exp) ((void)0)
626#       else
627#               define ASSERT(exp) \
628                        do { \
629                                if (!(exp)) \
630                                        MyAssert(__FILE__, __LINE__); \
631                        } while( 0 )
632#       endif
633#endif
634
635NORETURN inline void OUT_OF_RANGE(const char* str)
636{
637        if( cpu.lgAssertAbort() )
638                abort();
639        else
640                throw out_of_range( str );
641}
642
643/* Windows does not define isnan */
644/* use our version on all platforms since the isnanf
645 * function does not exist under Solaris 9 either */
646#undef isnan
647#define isnan MyIsnan
648
649/** entry and exit of each routine will go here,
650 * macros enabled if compiler-set flag DEBUG_FUN is defined */
651class t_debug : public Singleton<t_debug>
652{
653        friend class Singleton<t_debug>;
654        FILE *p_fp;
655        int p_callLevel;
656protected:
657        t_debug()
658        {
659                p_fp = stderr;
660                p_callLevel = 0;
661        }
662public:
663        void enter(const char *name)
664        {
665                ++p_callLevel;
666                fprintf(p_fp,"%*c%s\n",p_callLevel,'>',name);
667        }
668        void leave(const char *name)
669        {
670                fprintf(p_fp,"%*c%s\n",p_callLevel,'<',name);
671                --p_callLevel;
672        }               
673};
674
675template<bool lgTrace>
676class debugtrace
677{
678        const char *p_name;
679public:
680        explicit debugtrace(const char *funcname)
681        {
682                p_name = funcname;
683#               ifdef _MSC_VER
684                /* disable warning that conditional expression is constant, true or false in if */
685#               pragma warning( disable : 4127 )
686#               endif
687                if( lgTrace )
688                        t_debug::Inst().enter(p_name);
689        }
690        ~debugtrace()
691        {
692#               ifdef _MSC_VER
693                /* disable warning that conditional expression is constant, true or false in if */
694#               pragma warning( disable : 4127 )
695#               endif
696                if( lgTrace )
697                        t_debug::Inst().leave(p_name);
698                p_name = NULL;
699        }
700        const char* name() const
701        {
702                return p_name;
703        }
704};
705
706#ifdef DEBUG_FUN
707#define DEBUG_ENTRY( funcname ) debugtrace<true> DEBUG_ENTRY( funcname )
708#else
709#ifdef __GNUC__
710#define DEBUG_ENTRY( funcname ) ((void)0)
711#else
712#define DEBUG_ENTRY( funcname ) debugtrace<false> DEBUG_ENTRY( funcname )
713#endif
714#endif
715
716/* TorF(l) returns a 'T' or 'F' depending on the 'logical' expr 'l' */
717inline char TorF( bool l ) { return l ? 'T' : 'F'; }
718/* */
719
720/** checks whether argument is odd */
721inline bool is_odd( int j ) { return (j&1) == 1; }
722inline bool is_odd( long j ) { return (j&1L) == 1L; }
723/* */
724
725/** nint rounds to the nearest long int */
726inline long nint( double x ) { return static_cast<long>( (x < 0.) ? x-0.5 : x+0.5 ); }
727/* */
728
729/* define min for mixed arguments, the rest already exists */
730inline long min( int a, long b ) { long c = a; return ( (c < b) ? c : b ); }
731inline long min( long a, int b ) { long c = b; return ( (a < c) ? a : c ); }
732inline double min( sys_float a, double b ) { double c = a; return ( (c < b) ? c : b ); }
733inline double min( double a, sys_float b ) { double c = b; return ( (a < c) ? a : c ); }
734
735#undef MIN2
736/** MIN2 takes two arguments, returns the smaller of the two */
737#define MIN2 min
738/* */
739
740#undef MIN3
741/** MIN3 takes 3 arguments, returns the smallest of the 3 */
742#define MIN3(a,b,c) (min(min(a,b),c))
743/* */
744
745#undef MIN4
746/** MIN2 takes 4 arguments, returns the smallest of the 4 */
747#define MIN4(a,b,c,d) (min(min(a,b),min(c,d)))
748/* */
749
750/* define max for mixed arguments, the rest already exists */
751inline long max( int a, long b ) { long c = a; return ( (c > b) ? c : b ); }
752inline long max( long a, int b ) { long c = b; return ( (a > c) ? a : c ); }
753inline double max( sys_float a, double b ) { double c = a; return ( (c > b) ? c : b ); }
754inline double max( double a, sys_float b ) { double c = b; return ( (a > c) ? a : c ); }
755
756#undef MAX2
757/** MAX2 takes two arguments, returns the larger of the two */
758#define MAX2 max
759/* */
760
761#undef MAX3
762/** MAX3 takes 3 arguments, returns the largest of the 3 */
763#define MAX3(a,b,c) (max(max(a,b),c))
764/* */
765
766#undef MAX4
767/** MAX2 takes 4 arguments, returns the largest of the 4 */
768#define MAX4(a,b,c,d) (max(max(a,b),max(c,d)))
769/* */
770
771/** FP sign transfer (fortran sign function) - sign of y times abs value of x
772\param x
773\param y
774*/
775template<class T>
776inline T sign( T x, T y )
777{
778        return ( y < T() ) ? -abs(x) : abs(x);
779}
780/* */
781
782/** sign3 returns -1 for negative arguments, +1 for positive, and 0 for zero (pascal sign function) */
783template<class T>
784inline int sign3( T x ) { return ( x < T() ) ? -1 : ( ( x > T() ) ? 1 : 0 ); }
785/* */
786
787/** checks whether two FP numbers are "equal" (differ no more than n epsilon) */
788inline bool fp_equal( sys_float x, sys_float y, int n=3 )
789{
790#ifdef _MSC_VER
791        /* disable warning that conditional expression is constant, true or false in if */
792#       pragma warning( disable : 4127 )
793        /* we are not using MS foundation class */
794#       ifndef WIN32_LEAN_AND_MEAN
795#               define WIN32_LEAN_AND_MEAN
796#       endif
797#endif
798        ASSERT( n >= 1 );
799        // mimic IEEE behavior
800        if( isnan(x) || isnan(y) )
801                return false;
802        int sx = sign3(x);
803        int sy = sign3(y);
804        // treat zero cases first to avoid division by zero below
805        if( sx == 0 && sy == 0 )
806                return true;
807        // either x or y is zero (but not both), or x and y have different sign
808        if( sx*sy != 1 )
809                return false;
810        x = abs(x);
811        y = abs(y);
812        return ( 1.f - min(x,y)/max(x,y) < ((sys_float)n+0.1f)*FLT_EPSILON );
813}
814
815inline bool fp_equal( double x, double y, int n=3 )
816{
817        ASSERT( n >= 1 );
818        // mimic IEEE behavior
819        if( isnan(x) || isnan(y) )
820                return false;
821        int sx = sign3(x);
822        int sy = sign3(y);
823        // treat zero cases first to avoid division by zero below
824        if( sx == 0 && sy == 0 )
825                return true;
826        // either x or y is zero (but not both), or x and y have different sign
827        if( sx*sy != 1 )
828                return false;
829        x = abs(x);
830        y = abs(y);
831        return ( 1. - min(x,y)/max(x,y) < ((double)n+0.1)*DBL_EPSILON );
832}
833
834inline bool fp_equal_tol( sys_float x, sys_float y, sys_float tol )
835{
836        ASSERT( tol > 0.f );
837        // mimic IEEE behavior
838        if( isnan(x) || isnan(y) )
839                return false;
840        // make sure the tolerance is not too stringent
841        ASSERT( tol >= FLT_EPSILON*max(abs(x),abs(y)) );
842        return ( abs( x-y ) <= tol );
843}
844
845inline bool fp_equal_tol( double x, double y, double tol )
846{
847        ASSERT( tol > 0. );
848        // mimic IEEE behavior
849        if( isnan(x) || isnan(y) )
850                return false;
851        // make sure the tolerance is not too stringent
852        ASSERT( tol >= DBL_EPSILON*max(abs(x),abs(y)) );
853        return ( abs( x-y ) <= tol );
854}
855
856/** checks whether a number is within bounds */
857inline bool fp_bound( sys_float lo, sys_float x, sys_float hi, int n=3 )
858{
859        ASSERT( n >= 1 );
860        // mimic IEEE behavior
861        if( isnan(x) || isnan(lo) || isnan(hi) )
862                return false;
863        if( fp_equal(lo,hi,n) )
864                return fp_equal(0.5f*(lo+hi),x,n);
865        if( ((hi-x)/(hi-lo))*((x-lo)/(hi-lo)) < -((sys_float)n+0.1f)*FLT_EPSILON )
866                return false;
867        return true;
868}
869inline bool fp_bound( double lo, double x, double hi, int n=3 )
870{
871        ASSERT( n >= 1 );
872        // mimic IEEE behavior
873        if( isnan(x) || isnan(lo) || isnan(hi) )
874                return false;
875        if( fp_equal(lo,hi,n) )
876                return fp_equal(0.5*(lo+hi),x,n);
877        if( ((hi-x)/(hi-lo))*((x-lo)/(hi-lo)) < -((double)n+0.1)*DBL_EPSILON )
878                return false;
879        return true;
880}
881inline bool fp_bound_tol( sys_float lo, sys_float x, sys_float hi, sys_float tol )
882{
883        ASSERT( tol > 0.f );
884        // mimic IEEE behavior
885        if( isnan(x) || isnan(lo) || isnan(hi) )
886                return false;
887        if( fp_equal_tol(lo,hi,tol) )
888                return fp_equal_tol(0.5f*(lo+hi),x,tol);
889        if( ((hi-x)/(hi-lo))*((x-lo)/(hi-lo)) < -tol )
890                return false;
891        return true;
892}
893inline bool fp_bound_tol( double lo, double x, double hi, double tol )
894{
895        ASSERT( tol > 0. );
896        // mimic IEEE behavior
897        if( isnan(x) || isnan(lo) || isnan(hi) )
898                return false;
899        if( fp_equal_tol(lo,hi,tol) )
900                return