cloudy trunk
|
00001 /* This file is part of Cloudy and is copyright (C)1978-2008 by Gary J. Ferland and 00002 * others. For conditions of distribution and use see copyright notice in license.txt */ 00004 #if defined(__HP_aCC) 00005 /* this is for the HP compiler on the sdx */ 00006 extern "C" unsigned long fegettrapenable(); 00007 extern "C" void fesettrapenable(unsigned long); 00008 #endif 00009 00010 #if defined(__ia64) && defined(__INTEL_COMPILER) 00011 extern "C" unsigned long fpgetmask(); 00012 extern "C" void fpsetmask(unsigned long); 00013 #endif 00014 00015 #if defined(__sun) || defined(__sgi) 00016 #include <ieeefp.h> 00017 #if defined(HAVE_SUNMATH) || defined(FLUSH_DENORM_TO_ZERO) 00018 #include <sunmath.h> 00019 #endif 00020 #endif 00021 00022 #if defined(__alpha) && defined(__linux) && defined(__GNUC__) 00023 #define __USE_GNU 00024 #include <fenv.h> 00025 #endif 00026 00027 #ifdef __unix 00028 #include <unistd.h> 00029 #endif 00030 00031 /* the redefinition of float in cddefines.h can cause problems in system headers 00032 * hence these includes MUST come after the system header includes above */ 00033 #include "cddefines.h" 00034 #include "path.h" 00035 #include "trace.h" 00036 00037 /* NB NB - this constructor needs to be called before any of the user code is executed !! */ 00038 t_cpu::t_cpu() 00039 { 00040 DEBUG_ENTRY( "t_cpu()" ); 00041 00042 #ifdef CATCH_SIGNAL 00043 // set up signal handlers so that we can properly terminate MPI runs... 00044 00045 # ifdef __unix 00046 p_action.sa_handler = &signal_handler; 00047 sigemptyset( &p_action.sa_mask ); 00048 p_action.sa_flags = SA_NODEFER; 00049 00050 p_default.sa_handler = SIG_DFL; 00051 sigemptyset( &p_default.sa_mask ); 00052 p_default.sa_flags = SA_NODEFER; 00053 00054 for( int sig=1; sig <= 31; sig++ ) 00055 { 00056 // is the signal valid? 00057 if( sigaction( sig, NULL, NULL ) == 0 ) 00058 // these two are for suspending and resuming a job 00059 if( sig != SIGSTOP && sig != SIGCONT ) 00060 sigaction( sig, action(), NULL ); 00061 } 00062 # endif 00063 00064 # ifdef _MSC_VER 00065 signal( SIGABRT, &signal_handler ); 00066 signal( SIGFPE, &signal_handler ); 00067 signal( SIGILL, &signal_handler ); 00068 signal( SIGINT, &signal_handler ); 00069 signal( SIGSEGV, &signal_handler ); 00070 signal( SIGTERM, &signal_handler ); 00071 # endif 00072 #endif 00073 00074 /* >>chng 05 dec 14, add test of endianness of the CPU, PvH */ 00075 endian.c[0] = 0x12; 00076 endian.c[1] = 0x34; 00077 endian.c[2] = 0x56; 00078 endian.c[3] = 0x78; 00079 00080 /* >>chng 05 dec 15, add signaling NaN for float and double to cpu struct, PvH */ 00081 /* in C++ this should be replaced by numeric_limits<TYPE>::signaling_NaN() */ 00082 if( sizeof(sys_float) == 4 ) 00083 { 00084 # ifdef __mips 00085 /* definition of signaling and quiet NaN is reversed on MIPS */ 00086 Float_SNaN_Value = 0xffffffff; 00087 # else 00088 if( big_endian() || little_endian() ) 00089 { 00090 /* this should work on most modern CPU's */ 00091 Float_SNaN_Value = 0xffbfffff; 00092 } 00093 else 00094 { 00095 /* this is an unusual CPU -> bit pattern for SNaN is unknown */ 00096 Float_SNaN_Value = -1; 00097 } 00098 # endif 00099 } 00100 else 00101 { 00102 /* this is an unusual CPU -> bit pattern for SNaN is unknown */ 00103 Float_SNaN_Value = -1; 00104 } 00105 00106 # ifdef HAVE_INT64 00107 00108 if( sizeof(double) == 8 ) 00109 { 00110 # ifdef __mips 00111 /* definition of signaling and quiet NaN is reversed on MIPS */ 00112 Double_SNaN_Value = 0xffffffffffffffff; 00113 # else 00114 /* this should work on most modern CPU's */ 00115 Double_SNaN_Value = 0xfff7ffffffbfffff; 00116 # endif 00117 } 00118 else 00119 { 00120 /* this is an unusual CPU -> bit pattern for SNaN is unknown */ 00121 Double_SNaN_Value = -1; 00122 } 00123 00124 # else 00125 00126 if( sizeof(double) == 8 ) 00127 { 00128 # ifdef __mips 00129 /* definition of signaling and quiet NaN is reversed on MIPS */ 00130 Double_SNaN_Value[0] = 0xffffffff; 00131 Double_SNaN_Value[1] = 0xffffffff; 00132 # else 00133 if( big_endian() ) 00134 { 00135 /* this should work on most modern CPU's */ 00136 Double_SNaN_Value[0] = 0xfff7ffff; 00137 Double_SNaN_Value[1] = 0xffbfffff; 00138 } 00139 else if( little_endian() ) 00140 { 00141 /* this should work on most modern CPU's */ 00142 Double_SNaN_Value[0] = 0xffbfffff; 00143 Double_SNaN_Value[1] = 0xfff7ffff; 00144 } 00145 else 00146 { 00147 /* this is an unusual CPU -> bit pattern for SNaN is unknown */ 00148 Double_SNaN_Value[0] = -1; 00149 Double_SNaN_Value[1] = -1; 00150 } 00151 # endif 00152 } 00153 else 00154 { 00155 /* this is an unusual CPU -> bit pattern for SNaN is unknown */ 00156 Double_SNaN_Value[0] = -1; 00157 Double_SNaN_Value[1] = -1; 00158 } 00159 00160 # endif 00161 00162 /* set FP environment to trap FP exceptions */ 00163 enable_traps(); 00164 00165 /* default is for failed asserts not to abort */ 00166 p_lgAssertAbort = false; 00167 00168 const char *str; 00169 00170 /* determine the no. of CPUs on this machine; used by PHYMIR, grid command, .... */ 00171 # if defined(_SC_NPROCESSORS_ONLN) /* Linux, Sun Sparc, DEC Alpha */ 00172 n_avail_CPU = sysconf(_SC_NPROCESSORS_ONLN); 00173 # elif defined(_SC_NPROC_ONLN) /* SGI Iris */ 00174 n_avail_CPU = sysconf(_SC_NPROC_ONLN); 00175 # elif defined(_SC_CRAY_NCPU) /* Cray */ 00176 n_avail_CPU = sysconf(_SC_CRAY_NCPU); 00177 # elif defined(_WIN32) 00178 str = getenv( "NUMBER_OF_PROCESSORS" ); 00179 if( str != NULL ) 00180 { 00181 int found = sscanf( str, "%ld", &n_avail_CPU ); 00182 if( found != 1 ) 00183 n_avail_CPU = 1; 00184 } 00185 else 00186 { 00187 n_avail_CPU = 1; 00188 } 00189 # else 00190 /* Other systems, supply no. of CPUs on OPTIMIZE PHYMIR command line */ 00191 n_avail_CPU = 1; 00192 # endif 00193 00194 # ifdef _WIN32 00195 str = getenv( "COMPUTERNAME" ); 00196 # else 00197 str = getenv( "HOSTNAME" ); 00198 # endif 00199 00200 if( str != NULL ) 00201 strncpy( HostName, str, STDLEN ); 00202 else 00203 strncpy( HostName, "unknown", STDLEN ); 00204 HostName[STDLEN-1] = '\0'; 00205 00206 /* pick up the path from the environment, if set by user */ 00207 const char *path = getenv( "CLOUDY_DATA_PATH" ); 00208 00209 /* if the environment variable was not set, the default set in path.h takes effect */ 00210 string chSearchPathRaw = ( path != NULL ) ? string( path ) : string( CLOUDY_DATA_PATH ); 00211 00212 # ifdef _WIN32 00213 string separator( ";" ); 00214 char chExpectedEnd = '\\'; 00215 # else 00216 string separator( ":" ); 00217 char chExpectedEnd = '/'; 00218 # endif 00219 00220 chSearchPath.push_back( "" ); // the current working directory should be first and last 00221 Split( chSearchPathRaw, separator, chSearchPath, SPM_RELAX ); 00222 chSearchPath.push_back( "" ); 00223 00224 for( vector<string>::size_type i=0; i < chSearchPath.size(); ++i ) 00225 { 00226 if( chSearchPath[i].length() > 0 ) 00227 { 00228 /* get last valid char */ 00229 char chEnd = *chSearchPath[i].rbegin(); 00230 00231 /* make sure path ends with directory separator */ 00232 if( chEnd != chExpectedEnd ) 00233 chSearchPath[i] += chExpectedEnd; 00234 } 00235 } 00236 00237 nFileDone = 0; 00238 } 00239 00240 void t_cpu::enable_traps() const 00241 { 00242 /* >>chng 01 aug 07, added code to circumvent math library bug with g++ on 00243 * alpha-linux machines, see bug report 51072 on http://bugzilla.redhat.com, PvH */ 00244 /* >>chng 01 apr 17, added code for Solaris and SGI operating systems, PvH */ 00245 /* this routine contains no code for alphas or crays, they do not need 00246 * special code to enable FP exceptions since they are enabled by default */ 00247 00248 /* there is no command line option on MS Visual Studio to force crash */ 00249 # if defined(_MSC_VER) 00250 volatile unsigned int NewMask; 00251 00252 /* | is a bitwise inclusive or, turns on bits 00253 * 0|0 = 0 00254 * 0|1 = 1|0 = 1|1 = 1 */ 00255 NewMask = _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_INVALID; 00256 /* ~ is the unary bitwise complement - all bits flip */ 00257 NewMask = ~NewMask; 00258 _controlfp( NewMask , _MCW_EM ); 00259 00260 /* this is the code for Linux PC (but not Linux alpha) to force crash */ 00261 /* >>chng 04 apr 26, added support for AMD64, enable FPE traps for SSE/SSE2, PvH */ 00262 /* >>chng 06 aug 12, added support for Apple MacOSX, and hopefully also Solaris x86, PvH */ 00263 # elif defined(__GNUC__) && ( defined(__i386) || defined(__amd64) ) 00264 volatile unsigned int Old_Mask, New_Mask; 00265 # if defined(__SSE__) || defined(__SSE2__) 00266 volatile unsigned int SSE_Mask; 00267 # endif 00268 00269 # define _FPU_MASK_IM 0x01 /* Invalid */ 00270 # define _FPU_MASK_DM 0x02 /* Denormalized */ 00271 # define _FPU_MASK_ZM 0x04 /* Division-by-zero */ 00272 # define _FPU_MASK_OM 0x08 /* Overflow */ 00273 # define _FPU_MASK_UM 0x10 /* Underflow */ 00274 # define _FPU_MASK_PM 0x20 /* Inexact */ 00275 00276 /* | is a bitwise inclusive or, turns on bits */ 00277 /* 0|0 = 0 */ 00278 /* 0|1 = 1|0 = 1|1 = 1 */ 00279 00280 /* ~ is the unary bitwise complement - all bits flip */ 00281 00282 /* this enables FPE traps for regular i387 FP instructions */ 00283 00284 volatile unsigned int UnMask = ~((unsigned int)( _FPU_MASK_ZM | _FPU_MASK_IM | _FPU_MASK_OM )); 00285 00286 __asm__ volatile("fnstcw %0" : "=m" (*&Old_Mask)); 00287 00288 New_Mask = Old_Mask & UnMask; 00289 00290 __asm__ volatile("fldcw %0" : : "m" (*&New_Mask)); 00291 00292 # if defined(__SSE__) || defined(__SSE2__) 00293 00294 # if defined(FLUSH_DENORM_TO_ZERO) 00295 /* using this causes denormalized numbers to be flushed to zero, 00296 * which will speed up the code on Pentium 4 processors */ 00297 SSE_Mask = 0x9900; 00298 # else 00299 /* this version allows denormalized numbers to be retained */ 00300 SSE_Mask = 0x1900; 00301 # endif 00302 00303 /* this enables FPE traps for SSE/SSE2 instructions */ 00304 00305 __asm__ volatile( "ldmxcsr %0" : : "m" (*&SSE_Mask) ); 00306 00307 # endif 00308 00309 /* this is for IA64 systems running g++ or icc (e.g. SGI, HP, ...) */ 00310 # elif defined(__ia64) 00311 00312 # define FPSR_TRAP_VD (1 << 0) /* invalid op trap disabled */ 00313 # define FPSR_TRAP_DD (1 << 1) /* denormal trap disabled */ 00314 # define FPSR_TRAP_ZD (1 << 2) /* zero-divide trap disabled */ 00315 # define FPSR_TRAP_OD (1 << 3) /* overflow trap disabled */ 00316 # define FPSR_TRAP_UD (1 << 4) /* underflow trap disabled */ 00317 # define FPSR_TRAP_ID (1 << 5) /* inexact trap disabled */ 00318 00319 # define FPSR_SF0_FTZ (1 << 6) /* flush denormalized numbers to zero */ 00320 00321 # if defined(__GNUC_EXCL__) 00322 /* __asm__ instructions are not supported by icc as of v9.0 */ 00323 # define _IA64_REG_AR_FPSR 40 00324 00325 # define ia64_getreg( regnum ) __asm__ volatile( "mov %0=ar%1" : "=r" (fpsr) : "i"(regnum) ) 00326 # define ia64_setreg( regnum, val ) __asm__ volatile( "mov ar%0=%1" :: "i" (regnum), "r"(val): "memory" ) 00327 # define ia64_serialize __asm__ volatile( "srlz.i" ); 00328 00329 volatile unsigned long fpsr, flags = FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD; 00330 00331 ia64_getreg( _IA64_REG_AR_FPSR ); 00332 fpsr &= ~flags; 00333 # if defined(FLUSH_DENORM_TO_ZERO) 00334 fpsr |= FPSR_SF0_FTZ; 00335 # endif 00336 ia64_setreg( _IA64_REG_AR_FPSR, fpsr ); 00337 /* this prevents RAW and WAW dependency violations in case this ever gets inlined... */ 00338 ia64_serialize; 00339 00340 # elif defined(__INTEL_COMPILER) 00341 /* this is for icc on IA64 SGI machines */ 00342 unsigned long fpsr = fpgetmask(); 00343 fpsr |= FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD; 00344 fpsetmask( fpsr ); 00345 # elif defined(__HP_aCC) 00346 /* this is for the HP compiler on the sdx */ 00347 unsigned long fpsr = fegettrapenable(); 00348 fpsr |= FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD; 00349 fesettrapenable( fpsr ); 00350 # endif /* defined(__GNUC_EXCL__) */ 00351 00352 /* this is for Solaris and SGI to force crash */ 00353 # elif defined(__sun) || defined(__sgi) 00354 00355 fp_except mask; 00356 00357 /* >>chng 05 dec 30, accept FLUSH_DENORM_TO_ZERO as a synonym for HAVE_SUNMATH, PvH */ 00358 # if defined(HAVE_SUNMATH) || defined(FLUSH_DENORM_TO_ZERO) 00359 00360 /* >>chng 01 oct 09, disable gradual underflow on ultrasparc whith g++ 00361 * (only needed for versions < 3.1 or >= 4.3.0, see Note 1). 00362 * 00363 * compile this module with: 00364 * g++ [ other options... ] -I<include-dir> -DHAVE_SUNMATH -c cpu.cpp 00365 * link the program with: 00366 * g++ -L<library-dir> -o cloudy.exe *.o -lsunmath 00367 * 00368 * you probably need to use -I<include-dir> and -L<library-dir> to point the 00369 * compiler/linker to the location of the sunmath.h header file and libsunmath.so 00370 * library (e.g., -I/opt/SUNWspro/prod/include/cc -L/opt/SUNWspro/lib; note that 00371 * the actual location may vary from one installation to another). 00372 * See also bug report 4487 on http://gcc.gnu.org/bugzilla/ 00373 * 00374 * Note 1: Starting with g++ 3.1, bug 4487 has been solved: -funsafe-math-optimizations 00375 * will automatically disable gradual underflow. Hence using nonstandard_arithmetic() 00376 * is no longer necessary. The option -funsafe-math-optimizations should be included 00377 * both when compiling and linking: 00378 * 00379 * g++ [ other options... ] -funsafe-math-optimizations -c *.c 00380 * g++ [ other options... ] -funsafe-math-optimizations -o cloudy.exe *.o 00381 * 00382 * Starting with g++ 4.3.0 the -funsafe-math-optimizations option can no longer be 00383 * used as it implicitly enables -fno-trapping-math, which is unsafe for Cloudy 00384 * because we do trap floating point exceptions. 00385 * 00386 * Note 2: Don't use nonstandard_arithmetic() with CC (the SunWorks/Forte compiler); 00387 * use the -fast commandline option instead to disable gradual underflow (or use 00388 * -fnonstd if you don't want all the other options enabled by -fast). The option 00389 * -fast (or -fnonstd) should be included both when compiling and linking: 00390 * 00391 * CC [ other options... ] -fast -c *.c 00392 * CC -fast -o cloudy.exe *.o 00393 * 00394 * PvH */ 00395 nonstandard_arithmetic(); 00396 # endif 00397 00398 /* enable floating point exceptions on sun and sgi */ 00399 mask = fpgetmask(); 00400 mask = mask | FP_X_INV | FP_X_OFL | FP_X_DZ; 00401 fpsetmask(mask); 00402 00403 # elif defined(__alpha) && defined(__linux) && defined(__GNUC__) 00404 00405 /* the following is not supported on all hardware platforms, but certainly for EV56 00406 * and later. earlier versions may work as well, but that has not been tested. 00407 * for details see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=51072 */ 00408 # ifdef FE_NONIEEE_ENV 00409 /* this prevents the infamous math library bug when compiling with gcc on alpha-linux 00410 * machines. if this doesn't work on your system, the only alternative is to link 00411 * against the Compaq math library: gcc *.o -lcpml -lm, or use ccc itself, PvH */ 00412 fesetenv(FE_NONIEEE_ENV); 00413 # endif 00414 00415 # endif 00416 return; 00417 } 00418 00419 void t_cpu::signal_handler(int sig) 00420 { 00421 // when an FPE is caught, the mask is reset... 00422 cpu.enable_traps(); 00423 # ifdef _MSC_VER 00424 // at this point the signal handler has reverted to the default handler 00425 signal( sig, &signal_handler ); 00426 # endif 00427 throw bad_signal( sig ); 00428 } 00429 00430 00431 void t_cpu::printDataPath() const 00432 { 00433 fprintf(ioQQQ, "The path is:\n"); 00434 for( vector<string>::size_type i=1; i < cpu.chSearchPath.size()-1; ++i ) 00435 fprintf( ioQQQ, " ==%s==\n", cpu.chSearchPath[i].c_str() ); 00436 } 00437 00438 FILE* open_data( const char* fname, const char* mode, access_scheme scheme ) 00439 { 00440 DEBUG_ENTRY( "open_data()" ); 00441 00442 FILE* handle = NULL; 00443 string FileName( fname ); 00444 vector<string>::size_type begin, end; 00445 bool lgAbort = ( scheme == AS_DATA_ONLY || scheme == AS_DATA_OPTIONAL || scheme == AS_DATA_LOCAL || 00446 scheme == AS_LOCAL_DATA || scheme == AS_LOCAL_ONLY ); 00447 00448 switch( scheme ) 00449 { 00450 case AS_DATA_ONLY: 00451 case AS_DATA_ONLY_TRY: 00452 case AS_DATA_OPTIONAL: 00453 begin = 1; 00454 end = cpu.chSearchPath.size()-1; 00455 break; 00456 case AS_DATA_LOCAL: 00457 case AS_DATA_LOCAL_TRY: 00458 begin = 1; 00459 end = cpu.chSearchPath.size(); 00460 break; 00461 case AS_LOCAL_DATA: 00462 case AS_LOCAL_DATA_TRY: 00463 begin = 0; 00464 end = cpu.chSearchPath.size()-1; 00465 break; 00466 case AS_LOCAL_ONLY: 00467 case AS_LOCAL_ONLY_TRY: 00468 begin = 0; 00469 end = 1; 00470 break; 00471 default: 00472 TotalInsanity(); 00473 } 00474 00475 string FullName; 00476 for( vector<string>::size_type i=begin; i < end && handle == NULL; ++i ) 00477 { 00478 FullName = cpu.chSearchPath[i] + FileName; 00479 handle = fopen( FullName.c_str(), mode ); 00480 } 00481 00482 if( trace.lgTrace ) 00483 fprintf( ioQQQ, " opening %s mode %s handle %p\n", FullName.c_str(), mode, handle ); 00484 00485 if( handle == NULL && lgAbort ) 00486 { 00487 if( scheme == AS_DATA_OPTIONAL ) 00488 // presence is optional -> make warning less scary... 00489 fprintf( ioQQQ, "\nI could not open the data file %s\n\n", fname ); 00490 else 00491 fprintf( ioQQQ, "\nPROBLEM DISASTER I could not open the data file %s\n\n", fname ); 00492 if( cpu.nFileDone == 0 || scheme == AS_DATA_ONLY ) 00493 { 00494 // failed on very first open -> most likely path is not correct 00495 // failed on AS_DATA_ONLY -> CLOUDY_DATA_PATH may point to obsolete data dir 00496 fprintf( ioQQQ, "Although there may be other reasons you have received this error,\n"); 00497 fprintf( ioQQQ, "the most likely are that the path has not been properly set\n"); 00498 fprintf( ioQQQ, "or that the path points to an old version of the data.\n\n"); 00499 fprintf( ioQQQ, "Please have a look at the file path.h in the source directory\n"); 00500 fprintf( ioQQQ, "to check how the variable CLOUDY_DATA_PATH is set - \n"); 00501 fprintf( ioQQQ, "it should give the location of the data files I need.\n"); 00502 fprintf( ioQQQ, "These are the files in the data download from the web site.\n\n"); 00503 fprintf( ioQQQ, "Recompile the code with the correct data path set in path.h\n"); 00504 fprintf( ioQQQ, "or use the shell command \"export CLOUDY_DATA_PATH=path\" to set the\n"); 00505 fprintf( ioQQQ, "path from a bash command prompt.\n\n"); 00506 cpu.printDataPath(); 00507 } 00508 else 00509 { 00510 // failed on search including local directory -> most likely the file name 00511 // was mistyped on a compile command, or Cloudy is run in the wrong directory 00512 // if scheme == AS_DATA_OPTIONAL, this most likely is a stellar grid that is not installed. 00513 fprintf( ioQQQ, "These are all the paths I tried:\n" ); 00514 for( vector<string>::size_type i=begin; i < end; ++i ) 00515 { 00516 if( cpu.chSearchPath[i].length() > 0 ) 00517 fprintf( ioQQQ, " ==%s==\n", cpu.chSearchPath[i].c_str() ); 00518 else 00519 fprintf( ioQQQ, " ==<local directory>==\n" ); 00520 } 00521 // AS_DATA_OPTIONAL files should provide their own message (currently only stellar grids) 00522 if( scheme != AS_DATA_OPTIONAL ) 00523 { 00524 fprintf( ioQQQ, "\nAlthough there may be other reasons you have received this error,\n"); 00525 fprintf( ioQQQ, "the most likely are that you mistyped the file name, or that you\n"); 00526 fprintf( ioQQQ, "are running Cloudy in the wrong directory. If you are running a\n"); 00527 fprintf( ioQQQ, "COMPILE command, this needs to be done in the data directory.\n\n"); 00528 fprintf( ioQQQ, "Otherwise, please have a look at the file path.h in the source\n"); 00529 fprintf( ioQQQ, "directory to check how the variable CLOUDY_DATA_PATH is set - \n"); 00530 fprintf( ioQQQ, "it should give the location of the data files I need.\n"); 00531 fprintf( ioQQQ, "These are the files in the data download from the web site.\n\n"); 00532 fprintf( ioQQQ, "Recompile the code with the correct data path set in path.h\n"); 00533 fprintf( ioQQQ, "or use the shell command \"export CLOUDY_DATA_PATH=path\" to set the\n"); 00534 fprintf( ioQQQ, "path from a bash command prompt.\n\n"); 00535 } 00536 } 00537 fprintf(ioQQQ, "Sorry.\n\n\n"); 00538 cdEXIT(EXIT_FAILURE); 00539 } 00540 00541 ++cpu.nFileDone; 00542 00543 return handle; 00544 } 00545 00551 void set_NaN(sys_float &x) 00552 { 00553 if( sizeof(sys_float) == 4 ) 00554 *reinterpret_cast<int32*>(&x) = cpu.Float_SNaN_Value; 00555 else 00556 x = -FLT_MAX; 00557 } 00558 00559 void set_NaN(sys_float x[], /* x[n] */ 00560 long n) 00561 { 00562 long i; 00563 00564 if( sizeof(sys_float) == 4 ) 00565 { 00566 int32 *y = reinterpret_cast<int32*>(x); 00567 for( i=0; i < n; i++ ) 00568 *y++ = cpu.Float_SNaN_Value; 00569 } 00570 else 00571 { 00572 for( i=0; i < n; i++ ) 00573 x[i] = -FLT_MAX; 00574 } 00575 } 00576 00577 void set_NaN(double &x) 00578 { 00579 if( sizeof(double) == 8 ) 00580 { 00581 # ifdef HAVE_INT64 00582 *reinterpret_cast<int64*>(&x) = cpu.Double_SNaN_Value; 00583 # else 00584 int32 *y = reinterpret_cast<int32*>(&x); 00585 *y++ = cpu.Double_SNaN_Value[0]; 00586 *y = cpu.Double_SNaN_Value[1]; 00587 # endif 00588 } 00589 else 00590 x = -DBL_MAX; 00591 } 00592 00593 /* set_NaN - set NaN */ 00594 void set_NaN(double x[], /* x[n] */ 00595 long n) 00596 { 00597 long i; 00598 00599 if( sizeof(double) == 8 ) 00600 { 00601 # ifdef HAVE_INT64 00602 int64 *y = reinterpret_cast<int64*>(x); 00603 for( i=0; i < n; i++ ) 00604 *y++ = cpu.Double_SNaN_Value; 00605 # else 00606 int32 *y = reinterpret_cast<int32*>(x); 00607 for( i=0; i < n; i++ ) 00608 { 00609 *y++ = cpu.Double_SNaN_Value[0]; 00610 *y++ = cpu.Double_SNaN_Value[1]; 00611 } 00612 # endif 00613 } 00614 else 00615 { 00616 for( i=0; i < n; i++ ) 00617 x[i] = -DBL_MAX; 00618 } 00619 } 00620 00622 bool MyIsnan(sys_float &x) 00623 { 00624 if( sizeof(sys_float) == 4 && FLT_MAX_EXP-FLT_MIN_EXP+3 == 256 ) 00625 { 00626 int32 *p = reinterpret_cast<int32*>(&x); 00627 int32 r = *p & 0x7f800000; r ^= 0x7f800000; 00628 int32 s = *p & 0x007fffff; 00629 return ( r == 0 && s != 0 ); 00630 } 00631 else 00632 /* we don't understand this CPU */ 00633 return false; 00634 } 00635 00637 bool MyIsnan(double &x) 00638 { 00639 if( sizeof(double) == 8 && DBL_MAX_EXP-DBL_MIN_EXP+3 == 2048 ) 00640 { 00641 # ifdef HAVE_INT64 00642 int64 *p = reinterpret_cast<int64*>(&x); 00643 int64 r = *p & 0x7ff0000000000000; r ^= 0x7ff0000000000000; 00644 int64 s = *p & 0x000fffffffffffff; 00645 return ( r == 0 && s != 0 ); 00646 # else 00647 int32 *p = reinterpret_cast<int32*>(&x); 00648 if( cpu.little_endian() ) 00649 { 00650 int32 r = p[1] & 0x7ff00000; r ^= 0x7ff00000; 00651 int32 s = p[1] & 0x000fffff; s |= p[0]; 00652 return ( r == 0 && s != 0 ); 00653 } 00654 else if( cpu.big_endian() ) 00655 { 00656 int32 r = p[0] & 0x7ff00000; r ^= 0x7ff00000; 00657 int32 s = p[0] & 0x000fffff; s |= p[1]; 00658 return ( r == 0 && s != 0 ); 00659 } 00660 else 00661 /* we don't understand this CPU */ 00662 return false; 00663 # endif 00664 } 00665 else 00666 /* we don't understand this CPU */ 00667 return false; 00668 }