cloudy  trunk
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cpu.cpp
Go to the documentation of this file.
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 */
4 #if defined(__HP_aCC)
5 /* this is for the HP compiler on the sdx */
6 extern "C" unsigned long fegettrapenable();
7 extern "C" void fesettrapenable(unsigned long);
8 #endif
9 
10 #if defined(__ia64) && defined(__INTEL_COMPILER)
11 extern "C" unsigned long fpgetmask();
12 extern "C" void fpsetmask(unsigned long);
13 #endif
14 
15 #if defined(__sun) || defined(__sgi)
16 #include <ieeefp.h>
17 #if defined(HAVE_SUNMATH) || defined(FLUSH_DENORM_TO_ZERO)
18 #include <sunmath.h>
19 #endif
20 #endif
21 
22 #if defined(__alpha) && defined(__linux) && defined(__GNUC__)
23 #define __USE_GNU
24 #include <fenv.h>
25 #endif
26 
27 #ifdef __unix
28 #include <unistd.h>
29 #endif
30 
31 /* the redefinition of float in cddefines.h can cause problems in system headers
32  * hence these includes MUST come after the system header includes above */
33 #include "cddefines.h"
34 #include "path.h"
35 #include "trace.h"
36 
37 /* NB NB - this constructor needs to be called before any of the user code is executed !! */
39 {
40  DEBUG_ENTRY( "t_cpu()" );
41 
42 #ifdef CATCH_SIGNAL
43  // set up signal handlers so that we can properly terminate MPI runs...
44 
45 # ifdef __unix
46  p_action.sa_handler = &signal_handler;
47  sigemptyset( &p_action.sa_mask );
48  p_action.sa_flags = SA_NODEFER;
49 
50  p_default.sa_handler = SIG_DFL;
51  sigemptyset( &p_default.sa_mask );
52  p_default.sa_flags = SA_NODEFER;
53 
54  for( int sig=1; sig <= 31; sig++ )
55  {
56  // is the signal valid?
57  if( sigaction( sig, NULL, NULL ) == 0 )
58  // these two are for suspending and resuming a job
59  if( sig != SIGSTOP && sig != SIGCONT )
60  sigaction( sig, action(), NULL );
61  }
62 # endif
63 
64 # ifdef _MSC_VER
65  signal( SIGABRT, &signal_handler );
66  signal( SIGFPE, &signal_handler );
67  signal( SIGILL, &signal_handler );
68  signal( SIGINT, &signal_handler );
69  signal( SIGSEGV, &signal_handler );
70  signal( SIGTERM, &signal_handler );
71 # endif
72 #endif
73 
74  /* >>chng 05 dec 14, add test of endianness of the CPU, PvH */
75  endian.c[0] = 0x12;
76  endian.c[1] = 0x34;
77  endian.c[2] = 0x56;
78  endian.c[3] = 0x78;
79 
80  /* >>chng 05 dec 15, add signaling NaN for float and double to cpu struct, PvH */
81  /* in C++ this should be replaced by numeric_limits<TYPE>::signaling_NaN() */
82  if( sizeof(sys_float) == 4 )
83  {
84 # ifdef __mips
85  /* definition of signaling and quiet NaN is reversed on MIPS */
86  Float_SNaN_Value = 0xffffffff;
87 # else
88  if( big_endian() || little_endian() )
89  {
90  /* this should work on most modern CPU's */
91  Float_SNaN_Value = 0xffbfffff;
92  }
93  else
94  {
95  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
96  Float_SNaN_Value = -1;
97  }
98 # endif
99  }
100  else
101  {
102  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
103  Float_SNaN_Value = -1;
104  }
105 
106 # ifdef HAVE_INT64
107 
108  if( sizeof(double) == 8 )
109  {
110 # ifdef __mips
111  /* definition of signaling and quiet NaN is reversed on MIPS */
112  Double_SNaN_Value = 0xffffffffffffffff;
113 # else
114  /* this should work on most modern CPU's */
115  Double_SNaN_Value = 0xfff7ffffffbfffff;
116 # endif
117  }
118  else
119  {
120  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
121  Double_SNaN_Value = -1;
122  }
123 
124 # else
125 
126  if( sizeof(double) == 8 )
127  {
128 # ifdef __mips
129  /* definition of signaling and quiet NaN is reversed on MIPS */
130  Double_SNaN_Value[0] = 0xffffffff;
131  Double_SNaN_Value[1] = 0xffffffff;
132 # else
133  if( big_endian() )
134  {
135  /* this should work on most modern CPU's */
136  Double_SNaN_Value[0] = 0xfff7ffff;
137  Double_SNaN_Value[1] = 0xffbfffff;
138  }
139  else if( little_endian() )
140  {
141  /* this should work on most modern CPU's */
142  Double_SNaN_Value[0] = 0xffbfffff;
143  Double_SNaN_Value[1] = 0xfff7ffff;
144  }
145  else
146  {
147  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
148  Double_SNaN_Value[0] = -1;
149  Double_SNaN_Value[1] = -1;
150  }
151 # endif
152  }
153  else
154  {
155  /* this is an unusual CPU -> bit pattern for SNaN is unknown */
156  Double_SNaN_Value[0] = -1;
157  Double_SNaN_Value[1] = -1;
158  }
159 
160 # endif
161 
162  /* set FP environment to trap FP exceptions */
163  enable_traps();
164 
165  /* default is for failed asserts not to abort */
166  p_lgAssertAbort = false;
167 
168  const char *str;
169 
170  /* determine the no. of CPUs on this machine; used by PHYMIR, grid command, .... */
171 # if defined(_SC_NPROCESSORS_ONLN) /* Linux, Sun Sparc, DEC Alpha */
172  n_avail_CPU = sysconf(_SC_NPROCESSORS_ONLN);
173 # elif defined(_SC_NPROC_ONLN) /* SGI Iris */
174  n_avail_CPU = sysconf(_SC_NPROC_ONLN);
175 # elif defined(_SC_CRAY_NCPU) /* Cray */
176  n_avail_CPU = sysconf(_SC_CRAY_NCPU);
177 # elif defined(_WIN32)
178  str = getenv( "NUMBER_OF_PROCESSORS" );
179  if( str != NULL )
180  {
181  int found = sscanf( str, "%ld", &n_avail_CPU );
182  if( found != 1 )
183  n_avail_CPU = 1;
184  }
185  else
186  {
187  n_avail_CPU = 1;
188  }
189 # else
190  /* Other systems, supply no. of CPUs on OPTIMIZE PHYMIR command line */
191  n_avail_CPU = 1;
192 # endif
193 
194 # ifdef _WIN32
195  str = getenv( "COMPUTERNAME" );
196 # else
197  str = getenv( "HOSTNAME" );
198 # endif
199 
200  if( str != NULL )
201  strncpy( HostName, str, STDLEN );
202  else
203  strncpy( HostName, "unknown", STDLEN );
204  HostName[STDLEN-1] = '\0';
205 
206  /* pick up the path from the environment, if set by user */
207  const char *path = getenv( "CLOUDY_DATA_PATH" );
208 
209  /* if the environment variable was not set, the default set in path.h takes effect */
210  string chSearchPathRaw = ( path != NULL ) ? string( path ) : string( CLOUDY_DATA_PATH );
211 
212 # ifdef _WIN32
213  string separator( ";" );
214  char chExpectedEnd = '\\';
215 # else
216  string separator( ":" );
217  char chExpectedEnd = '/';
218 # endif
219 
220  chSearchPath.push_back( "" ); // the current working directory should be first and last
221  Split( chSearchPathRaw, separator, chSearchPath, SPM_RELAX );
222  chSearchPath.push_back( "" );
223 
224  for( vector<string>::size_type i=0; i < chSearchPath.size(); ++i )
225  {
226  if( chSearchPath[i].length() > 0 )
227  {
228  /* get last valid char */
229  char chEnd = *chSearchPath[i].rbegin();
230 
231  /* make sure path ends with directory separator */
232  if( chEnd != chExpectedEnd )
233  chSearchPath[i] += chExpectedEnd;
234  }
235  }
236 
237  nFileDone = 0;
238 }
239 
241 {
242  /* >>chng 01 aug 07, added code to circumvent math library bug with g++ on
243  * alpha-linux machines, see bug report 51072 on http://bugzilla.redhat.com, PvH */
244  /* >>chng 01 apr 17, added code for Solaris and SGI operating systems, PvH */
245  /* this routine contains no code for alphas or crays, they do not need
246  * special code to enable FP exceptions since they are enabled by default */
247 
248  /* there is no command line option on MS Visual Studio to force crash */
249 # if defined(_MSC_VER)
250  volatile unsigned int NewMask;
251 
252  /* | is a bitwise inclusive or, turns on bits
253  * 0|0 = 0
254  * 0|1 = 1|0 = 1|1 = 1 */
255  NewMask = _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_INVALID;
256  /* ~ is the unary bitwise complement - all bits flip */
257  NewMask = ~NewMask;
258  _controlfp( NewMask , _MCW_EM );
259 
260  /* this is the code for Linux PC (but not Linux alpha) to force crash */
261  /* >>chng 04 apr 26, added support for AMD64, enable FPE traps for SSE/SSE2, PvH */
262  /* >>chng 06 aug 12, added support for Apple MacOSX, and hopefully also Solaris x86, PvH */
263 # elif defined(__GNUC__) && ( defined(__i386) || defined(__amd64) )
264  volatile unsigned int Old_Mask, New_Mask;
265 # if defined(__SSE__) || defined(__SSE2__)
266  volatile unsigned int SSE_Mask;
267 # endif
268 
269 # define _FPU_MASK_IM 0x01 /* Invalid */
270 # define _FPU_MASK_DM 0x02 /* Denormalized */
271 # define _FPU_MASK_ZM 0x04 /* Division-by-zero */
272 # define _FPU_MASK_OM 0x08 /* Overflow */
273 # define _FPU_MASK_UM 0x10 /* Underflow */
274 # define _FPU_MASK_PM 0x20 /* Inexact */
275 
276  /* | is a bitwise inclusive or, turns on bits */
277  /* 0|0 = 0 */
278  /* 0|1 = 1|0 = 1|1 = 1 */
279 
280  /* ~ is the unary bitwise complement - all bits flip */
281 
282  /* this enables FPE traps for regular i387 FP instructions */
283 
284  volatile unsigned int UnMask = ~((unsigned int)( _FPU_MASK_ZM | _FPU_MASK_IM | _FPU_MASK_OM ));
285 
286  __asm__ volatile("fnstcw %0" : "=m" (*&Old_Mask));
287 
288  New_Mask = Old_Mask & UnMask;
289 
290  __asm__ volatile("fldcw %0" : : "m" (*&New_Mask));
291 
292 # if defined(__SSE__) || defined(__SSE2__)
293 
294 # if defined(FLUSH_DENORM_TO_ZERO)
295  /* using this causes denormalized numbers to be flushed to zero,
296  * which will speed up the code on Pentium 4 processors */
297  SSE_Mask = 0x9900;
298 # else
299  /* this version allows denormalized numbers to be retained */
300  SSE_Mask = 0x1900;
301 # endif
302 
303  /* this enables FPE traps for SSE/SSE2 instructions */
304 
305  __asm__ volatile( "ldmxcsr %0" : : "m" (*&SSE_Mask) );
306 
307 # endif
308 
309  /* this is for IA64 systems running g++ or icc (e.g. SGI, HP, ...) */
310 # elif defined(__ia64)
311 
312 # define FPSR_TRAP_VD (1 << 0) /* invalid op trap disabled */
313 # define FPSR_TRAP_DD (1 << 1) /* denormal trap disabled */
314 # define FPSR_TRAP_ZD (1 << 2) /* zero-divide trap disabled */
315 # define FPSR_TRAP_OD (1 << 3) /* overflow trap disabled */
316 # define FPSR_TRAP_UD (1 << 4) /* underflow trap disabled */
317 # define FPSR_TRAP_ID (1 << 5) /* inexact trap disabled */
318 
319 # define FPSR_SF0_FTZ (1 << 6) /* flush denormalized numbers to zero */
320 
321 # if defined(__GNUC_EXCL__)
322  /* __asm__ instructions are not supported by icc as of v9.0 */
323 # define _IA64_REG_AR_FPSR 40
324 
325 # define ia64_getreg( regnum ) __asm__ volatile( "mov %0=ar%1" : "=r" (fpsr) : "i"(regnum) )
326 # define ia64_setreg( regnum, val ) __asm__ volatile( "mov ar%0=%1" :: "i" (regnum), "r"(val): "memory" )
327 # define ia64_serialize __asm__ volatile( "srlz.i" );
328 
329  volatile unsigned long fpsr, flags = FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD;
330 
331  ia64_getreg( _IA64_REG_AR_FPSR );
332  fpsr &= ~flags;
333 # if defined(FLUSH_DENORM_TO_ZERO)
334  fpsr |= FPSR_SF0_FTZ;
335 # endif
336  ia64_setreg( _IA64_REG_AR_FPSR, fpsr );
337  /* this prevents RAW and WAW dependency violations in case this ever gets inlined... */
338  ia64_serialize;
339 
340 # elif defined(__INTEL_COMPILER)
341  /* this is for icc on IA64 SGI machines */
342  unsigned long fpsr = fpgetmask();
343  fpsr |= FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD;
344  fpsetmask( fpsr );
345 # elif defined(__HP_aCC)
346  /* this is for the HP compiler on the sdx */
347  unsigned long fpsr = fegettrapenable();
348  fpsr |= FPSR_TRAP_VD | FPSR_TRAP_ZD | FPSR_TRAP_OD;
349  fesettrapenable( fpsr );
350 # endif /* defined(__GNUC_EXCL__) */
351 
352  /* this is for Solaris and SGI to force crash */
353 # elif defined(__sun) || defined(__sgi)
354 
355  fp_except mask;
356 
357  /* >>chng 05 dec 30, accept FLUSH_DENORM_TO_ZERO as a synonym for HAVE_SUNMATH, PvH */
358 # if defined(HAVE_SUNMATH) || defined(FLUSH_DENORM_TO_ZERO)
359 
360  /* >>chng 01 oct 09, disable gradual underflow on ultrasparc whith g++
361  * (only needed for versions < 3.1 or >= 4.3.0, see Note 1).
362  *
363  * compile this module with:
364  * g++ [ other options... ] -I<include-dir> -DHAVE_SUNMATH -c cpu.cpp
365  * link the program with:
366  * g++ -L<library-dir> -o cloudy.exe *.o -lsunmath
367  *
368  * you probably need to use -I<include-dir> and -L<library-dir> to point the
369  * compiler/linker to the location of the sunmath.h header file and libsunmath.so
370  * library (e.g., -I/opt/SUNWspro/prod/include/cc -L/opt/SUNWspro/lib; note that
371  * the actual location may vary from one installation to another).
372  * See also bug report 4487 on http://gcc.gnu.org/bugzilla/
373  *
374  * Note 1: Starting with g++ 3.1, bug 4487 has been solved: -funsafe-math-optimizations
375  * will automatically disable gradual underflow. Hence using nonstandard_arithmetic()
376  * is no longer necessary. The option -funsafe-math-optimizations should be included
377  * both when compiling and linking:
378  *
379  * g++ [ other options... ] -funsafe-math-optimizations -c *.c
380  * g++ [ other options... ] -funsafe-math-optimizations -o cloudy.exe *.o
381  *
382  * Starting with g++ 4.3.0 the -funsafe-math-optimizations option can no longer be
383  * used as it implicitly enables -fno-trapping-math, which is unsafe for Cloudy
384  * because we do trap floating point exceptions.
385  *
386  * Note 2: Don't use nonstandard_arithmetic() with CC (the SunWorks/Forte compiler);
387  * use the -fast commandline option instead to disable gradual underflow (or use
388  * -fnonstd if you don't want all the other options enabled by -fast). The option
389  * -fast (or -fnonstd) should be included both when compiling and linking:
390  *
391  * CC [ other options... ] -fast -c *.c
392  * CC -fast -o cloudy.exe *.o
393  *
394  * PvH */
395  nonstandard_arithmetic();
396 # endif
397 
398  /* enable floating point exceptions on sun and sgi */
399  mask = fpgetmask();
400  mask = mask | FP_X_INV | FP_X_OFL | FP_X_DZ;
401  fpsetmask(mask);
402 
403 # elif defined(__alpha) && defined(__linux) && defined(__GNUC__)
404 
405  /* the following is not supported on all hardware platforms, but certainly for EV56
406  * and later. earlier versions may work as well, but that has not been tested.
407  * for details see https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=51072 */
408 # ifdef FE_NONIEEE_ENV
409  /* this prevents the infamous math library bug when compiling with gcc on alpha-linux
410  * machines. if this doesn't work on your system, the only alternative is to link
411  * against the Compaq math library: gcc *.o -lcpml -lm, or use ccc itself, PvH */
412  fesetenv(FE_NONIEEE_ENV);
413 # endif
414 
415 # endif
416  return;
417 }
418 
420 {
421  // when an FPE is caught, the mask is reset...
422  cpu.enable_traps();
423 # ifdef _MSC_VER
424  // at this point the signal handler has reverted to the default handler
425  signal( sig, &signal_handler );
426 # endif
427  throw bad_signal( sig );
428 }
429 
430 
432 {
433  fprintf(ioQQQ, "The path is:\n");
434  for( vector<string>::size_type i=1; i < cpu.chSearchPath.size()-1; ++i )
435  fprintf( ioQQQ, " ==%s==\n", cpu.chSearchPath[i].c_str() );
436 }
437 
438 FILE* open_data( const char* fname, const char* mode, access_scheme scheme )
439 {
440  DEBUG_ENTRY( "open_data()" );
441 
442  FILE* handle = NULL;
443  string FileName( fname );
444  vector<string>::size_type begin, end;
445  bool lgAbort = ( scheme == AS_DATA_ONLY || scheme == AS_DATA_OPTIONAL || scheme == AS_DATA_LOCAL ||
446  scheme == AS_LOCAL_DATA || scheme == AS_LOCAL_ONLY );
447 
448  switch( scheme )
449  {
450  case AS_DATA_ONLY:
451  case AS_DATA_ONLY_TRY:
452  case AS_DATA_OPTIONAL:
453  begin = 1;
454  end = cpu.chSearchPath.size()-1;
455  break;
456  case AS_DATA_LOCAL:
457  case AS_DATA_LOCAL_TRY:
458  begin = 1;
459  end = cpu.chSearchPath.size();
460  break;
461  case AS_LOCAL_DATA:
462  case AS_LOCAL_DATA_TRY:
463  begin = 0;
464  end = cpu.chSearchPath.size()-1;
465  break;
466  case AS_LOCAL_ONLY:
467  case AS_LOCAL_ONLY_TRY:
468  begin = 0;
469  end = 1;
470  break;
471  default:
472  TotalInsanity();
473  }
474 
475  string FullName;
476  for( vector<string>::size_type i=begin; i < end && handle == NULL; ++i )
477  {
478  FullName = cpu.chSearchPath[i] + FileName;
479  handle = fopen( FullName.c_str(), mode );
480  }
481 
482  if( trace.lgTrace )
483  fprintf( ioQQQ, " opening %s mode %s handle %p\n", FullName.c_str(), mode, handle );
484 
485  if( handle == NULL && lgAbort )
486  {
487  if( scheme == AS_DATA_OPTIONAL )
488  // presence is optional -> make warning less scary...
489  fprintf( ioQQQ, "\nI could not open the data file %s\n\n", fname );
490  else
491  fprintf( ioQQQ, "\nPROBLEM DISASTER I could not open the data file %s\n\n", fname );
492  if( cpu.nFileDone == 0 || scheme == AS_DATA_ONLY )
493  {
494  // failed on very first open -> most likely path is not correct
495  // failed on AS_DATA_ONLY -> CLOUDY_DATA_PATH may point to obsolete data dir
496  fprintf( ioQQQ, "Although there may be other reasons you have received this error,\n");
497  fprintf( ioQQQ, "the most likely are that the path has not been properly set\n");
498  fprintf( ioQQQ, "or that the path points to an old version of the data.\n\n");
499  fprintf( ioQQQ, "Please have a look at the file path.h in the source directory\n");
500  fprintf( ioQQQ, "to check how the variable CLOUDY_DATA_PATH is set - \n");
501  fprintf( ioQQQ, "it should give the location of the data files I need.\n");
502  fprintf( ioQQQ, "These are the files in the data download from the web site.\n\n");
503  fprintf( ioQQQ, "Recompile the code with the correct data path set in path.h\n");
504  fprintf( ioQQQ, "or use the shell command \"export CLOUDY_DATA_PATH=path\" to set the\n");
505  fprintf( ioQQQ, "path from a bash command prompt.\n\n");
506  cpu.printDataPath();
507  }
508  else
509  {
510  // failed on search including local directory -> most likely the file name
511  // was mistyped on a compile command, or Cloudy is run in the wrong directory
512  // if scheme == AS_DATA_OPTIONAL, this most likely is a stellar grid that is not installed.
513  fprintf( ioQQQ, "These are all the paths I tried:\n" );
514  for( vector<string>::size_type i=begin; i < end; ++i )
515  {
516  if( cpu.chSearchPath[i].length() > 0 )
517  fprintf( ioQQQ, " ==%s==\n", cpu.chSearchPath[i].c_str() );
518  else
519  fprintf( ioQQQ, " ==<local directory>==\n" );
520  }
521  // AS_DATA_OPTIONAL files should provide their own message (currently only stellar grids)
522  if( scheme != AS_DATA_OPTIONAL )
523  {
524  fprintf( ioQQQ, "\nAlthough there may be other reasons you have received this error,\n");
525  fprintf( ioQQQ, "the most likely are that you mistyped the file name, or that you\n");
526  fprintf( ioQQQ, "are running Cloudy in the wrong directory. If you are running a\n");
527  fprintf( ioQQQ, "COMPILE command, this needs to be done in the data directory.\n\n");
528  fprintf( ioQQQ, "Otherwise, please have a look at the file path.h in the source\n");
529  fprintf( ioQQQ, "directory to check how the variable CLOUDY_DATA_PATH is set - \n");
530  fprintf( ioQQQ, "it should give the location of the data files I need.\n");
531  fprintf( ioQQQ, "These are the files in the data download from the web site.\n\n");
532  fprintf( ioQQQ, "Recompile the code with the correct data path set in path.h\n");
533  fprintf( ioQQQ, "or use the shell command \"export CLOUDY_DATA_PATH=path\" to set the\n");
534  fprintf( ioQQQ, "path from a bash command prompt.\n\n");
535  }
536  }
537  fprintf(ioQQQ, "Sorry.\n\n\n");
538  cdEXIT(EXIT_FAILURE);
539  }
540 
541  ++cpu.nFileDone;
542 
543  return handle;
544 }
545 
552 {
553  if( sizeof(sys_float) == 4 )
554  *reinterpret_cast<int32*>(&x) = cpu.Float_SNaN_Value;
555  else
556  x = -FLT_MAX;
557 }
558 
559 void set_NaN(sys_float x[], /* x[n] */
560  long n)
561 {
562  long i;
563 
564  if( sizeof(sys_float) == 4 )
565  {
566  int32 *y = reinterpret_cast<int32*>(x);
567  for( i=0; i < n; i++ )
568  *y++ = cpu.Float_SNaN_Value;
569  }
570  else
571  {
572  for( i=0; i < n; i++ )
573  x[i] = -FLT_MAX;
574  }
575 }
576 
577 void set_NaN(double &x)
578 {
579  if( sizeof(double) == 8 )
580  {
581 # ifdef HAVE_INT64
582  *reinterpret_cast<int64*>(&x) = cpu.Double_SNaN_Value;
583 # else
584  int32 *y = reinterpret_cast<int32*>(&x);
585  *y++ = cpu.Double_SNaN_Value[0];
586  *y = cpu.Double_SNaN_Value[1];
587 # endif
588  }
589  else
590  x = -DBL_MAX;
591 }
592 
593 /* set_NaN - set NaN */
594 void set_NaN(double x[], /* x[n] */
595  long n)
596 {
597  long i;
598 
599  if( sizeof(double) == 8 )
600  {
601 # ifdef HAVE_INT64
602  int64 *y = reinterpret_cast<int64*>(x);
603  for( i=0; i < n; i++ )
604  *y++ = cpu.Double_SNaN_Value;
605 # else
606  int32 *y = reinterpret_cast<int32*>(x);
607  for( i=0; i < n; i++ )
608  {
609  *y++ = cpu.Double_SNaN_Value[0];
610  *y++ = cpu.Double_SNaN_Value[1];
611  }
612 # endif
613  }
614  else
615  {
616  for( i=0; i < n; i++ )
617  x[i] = -DBL_MAX;
618  }
619 }
620 
623 {
624  if( sizeof(sys_float) == 4 && FLT_MAX_EXP-FLT_MIN_EXP+3 == 256 )
625  {
626  int32 *p = reinterpret_cast<int32*>(&x);
627  int32 r = *p & 0x7f800000; r ^= 0x7f800000;
628  int32 s = *p & 0x007fffff;
629  return ( r == 0 && s != 0 );
630  }
631  else
632  /* we don't understand this CPU */
633  return false;
634 }
635 
637 bool MyIsnan(double &x)
638 {
639  if( sizeof(double) == 8 && DBL_MAX_EXP-DBL_MIN_EXP+3 == 2048 )
640  {
641 # ifdef HAVE_INT64
642  int64 *p = reinterpret_cast<int64*>(&x);
643  int64 r = *p & 0x7ff0000000000000; r ^= 0x7ff0000000000000;
644  int64 s = *p & 0x000fffffffffffff;
645  return ( r == 0 && s != 0 );
646 # else
647  int32 *p = reinterpret_cast<int32*>(&x);
648  if( cpu.little_endian() )
649  {
650  int32 r = p[1] & 0x7ff00000; r ^= 0x7ff00000;
651  int32 s = p[1] & 0x000fffff; s |= p[0];
652  return ( r == 0 && s != 0 );
653  }
654  else if( cpu.big_endian() )
655  {
656  int32 r = p[0] & 0x7ff00000; r ^= 0x7ff00000;
657  int32 s = p[0] & 0x000fffff; s |= p[1];
658  return ( r == 0 && s != 0 );
659  }
660  else
661  /* we don't understand this CPU */
662  return false;
663 # endif
664  }
665  else
666  /* we don't understand this CPU */
667  return false;
668 }

Generated for cloudy by doxygen 1.8.3.1