--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LongFloat.st Mon May 10 15:12:16 1999 +0200
@@ -0,0 +1,940 @@
+"
+ COPYRIGHT (c) 1999 by eXept Software AG
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+"
+
+
+
+LimitedPrecisionReal variableByteSubclass:#LongFloat
+ instanceVariableNames:''
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Magnitude-Numbers'
+!
+
+!LongFloat primitiveDefinitions!
+%{
+
+#include <errno.h>
+
+#ifndef __OPTIMIZE__
+# define __OPTIMIZE__
+#endif
+#include <math.h>
+
+/*
+ * on some systems errno is a macro ... check for it here
+ */
+#ifndef errno
+ extern errno;
+#endif
+
+#if defined (_AIX)
+# include <float.h>
+#endif
+#if defined(IRIX)
+# include <nan.h>
+#endif
+#if defined(LINUX)
+# include <nan.h>
+#endif
+#if defined(solaris) || defined(sunos)
+# include <nan.h>
+#endif
+
+#ifdef WIN32
+/*
+ * no finite(x) ?
+ * no isnan(x) ?
+ */
+# ifndef finite
+# define finite(x) 1
+# endif
+# ifndef isnan
+# define isnan(x) 0
+# endif
+#endif
+
+#ifdef realIX
+/*
+ * no finite(x)
+ */
+# ifndef finite
+# define finite(x) 1
+# endif
+#endif
+
+#ifdef WIN32
+# define LONGFLOAT long double
+#endif
+
+#ifndef LONGFLOAT
+# define LONGFLOAT double
+#endif
+
+#ifndef __qMKLFLOAT
+# define __qMKLFLOAT(__newFloat__, __fVal__) \
+ { \
+ __qNew(__newFloat__ , 10); \
+ if (__newFloat__) { \
+ __qClass(__newFloat__) = @global(LongFloat); \
+ ((long double *)(__newFloat->i_instvars))[0] = __fVal__; \
+ } \
+ }
+%}
+! !
+
+!LongFloat class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 1999 by eXept Software AG
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+"
+!
+
+documentation
+"
+ LongFloats represent rational numbers with limited precision. In ST/X, Float uses
+ the underlying C-compilers double implementation, while LongFloats are
+ mapped onto C-long doubles.
+ Therefore instances of Float are usually represented by the 8-byte IEE
+ double precision float format (64 bits), while LongFloats use 10byte extended IEE format
+ (80 bits).
+ But there is no guaranty - on systems which do not support long doubles,
+ LongFloats are represented as Doubles.
+
+ [author:]
+ Claus Gittinger
+
+ [see also:]
+ Number
+ Float ShortFloat Fraction FixedPoint Integer
+"
+
+! !
+
+!LongFloat class methodsFor:'instance creation'!
+
+basicNew
+ "return a new longFloat - here we return 0.0
+ - LongFloats are usually NOT created this way ...
+ Its implemented here to allow things like binary store & load
+ of longFloats. (but even this support will go away eventually, its not
+ a good idea to store the bits of a float - the reader might have a
+ totally different representation - so floats will eventually be
+ binary stored in a device independent format."
+
+%{ /* NOCONTEXT */
+ OBJ newFloat;
+
+ __qMKLFLOAT(newFloat, 0.0); /* OBJECT ALLOCATION */
+ RETURN (newFloat);
+%}
+!
+
+readFrom:aStringOrStream onError:exceptionBlock
+ "read a longFloat from a string"
+
+ |num|
+
+ num := super readFrom:aStringOrStream onError:nil.
+ num isNil ifTrue:[
+ ^ exceptionBlock value
+ ].
+ ^ num asLongFloat
+
+ "
+ LongFloat readFrom:'0.1'
+ LongFloat readFrom:'0'
+ "
+
+ "Modified: / 7.1.1998 / 16:17:59 / cg"
+! !
+
+!LongFloat class methodsFor:'constants'!
+
+pi
+ "return the constant pi as LongFloat"
+
+ ^ 3.14159 asLongFloat
+
+ "Modified: 23.4.1996 / 09:26:31 / cg"
+!
+
+unity
+ "return the neutral element for multiplication (1.0) as LongFloat"
+
+ ^ 1.0 asLongFloat
+
+ "Modified: 23.4.1996 / 09:26:51 / cg"
+!
+
+zero
+ "return the neutral element for addition (0.0) as LongFloat"
+
+ ^ 0.0 asLongFloat
+
+ "Modified: 23.4.1996 / 09:26:45 / cg"
+! !
+
+!LongFloat class methodsFor:'queries'!
+
+isBuiltInClass
+ "return true if this class is known by the run-time-system.
+ Here, true is returned for myself, false for subclasses."
+
+ ^ self == LongFloat
+
+ "Modified: 23.4.1996 / 16:00:23 / cg"
+!
+
+isIEEEFormat
+ "return true, if this machine represents floats in IEEE format.
+ Currently, no support is provided for non-ieee machines
+ to convert their floats into this (which is only relevant,
+ if such a machine wants to send floats as binary to some other
+ machine).
+ Machines with non-IEEE format are VAXed and IBM370-type systems
+ (among others). Today, most systems use IEEE format floats."
+
+ ^ true "/ this may be a lie
+! !
+
+!LongFloat methodsFor:'arithmetic'!
+
+* aNumber
+ "return the product of the receiver and the argument, aNumber"
+
+%{ /* NOCONTEXT */
+
+ OBJ newFloat;
+ LONGFLOAT result;
+
+ if (__isSmallInteger(aNumber)) {
+ result = __longFloatVal(self) * (LONGFLOAT)(__intVal(aNumber));
+retResult:
+ __qMKLFLOAT(newFloat, result);
+ RETURN ( newFloat );
+ } else if (__isLongFloat(aNumber)) {
+ result = __longFloatVal(self) * __longFloatVal(aNumber);
+ goto retResult;
+ } else if (__isFloatLike(aNumber)) {
+ result = __longFloatVal(self) * (LONGFLOAT)(__floatVal(aNumber));
+ goto retResult;
+ } else if (__isShortFloat(aNumber)) {
+ result = __longFloatVal(self) * (LONGFLOAT)(__shortFloatVal(aNumber));
+ goto retResult;
+ }
+%}.
+ ^ aNumber productFromLongFloat:self
+!
+
++ aNumber
+ "return the sum of the receiver and the argument, aNumber"
+
+%{ /* NOCONTEXT */
+
+ OBJ newFloat;
+ LONGFLOAT result;
+
+ if (__isSmallInteger(aNumber)) {
+ result = __longFloatVal(self) + (LONGFLOAT)(__intVal(aNumber));
+retResult:
+ __qMKLFLOAT(newFloat, result);
+ RETURN ( newFloat );
+ } else if (__isLongFloat(aNumber)) {
+ result = __longFloatVal(self) + __longFloatVal(aNumber);
+ goto retResult;
+ } else if (__isShortFloat(aNumber)) {
+ result = __longFloatVal(self) + (LONGFLOAT)(__shortFloatVal(aNumber));
+ goto retResult;
+ } else if (__isFloatLike(aNumber)) {
+ result = __longFloatVal(self) + (LONGFLOAT)(__floatVal(aNumber));
+ goto retResult;
+ }
+%}.
+ ^ aNumber sumFromLongFloat:self
+!
+
+- aNumber
+ "return the difference of the receiver and the argument, aNumber"
+
+%{ /* NOCONTEXT */
+
+ OBJ newFloat;
+ LONGFLOAT result;
+
+ if (__isSmallInteger(aNumber)) {
+ result = __longFloatVal(self) - (LONGFLOAT)(__intVal(aNumber));
+retResult:
+ __qMKLFLOAT(newFloat, result);
+ RETURN ( newFloat );
+ } else if (__isLongFloat(aNumber)) {
+ result = __longFloatVal(self) - __longFloatVal(aNumber);
+ goto retResult;
+ } else if (__isShortFloat(aNumber)) {
+ result = __longFloatVal(self) - (LONGFLOAT)(__shortFloatVal(aNumber));
+ goto retResult;
+ } else if (__isFloatLike(aNumber)) {
+ result = __longFloatVal(self) - (LONGFLOAT)(__floatVal(aNumber));
+ goto retResult;
+ }
+%}.
+ ^ aNumber differenceFromLongFloat:self
+!
+
+/ aNumber
+ "return the quotient of the receiver and the argument, aNumber"
+
+%{ /* NOCONTEXT */
+
+ OBJ newFloat;
+ LONGFLOAT result, val;
+
+ if (__isSmallInteger(aNumber)) {
+ if (aNumber != __MKSMALLINT(0)) {
+ result = __longFloatVal(self) / (LONGFLOAT)(__intVal(aNumber));
+retResult:
+ __qMKLFLOAT(newFloat, result);
+ RETURN ( newFloat );
+ }
+ } else if (__isLongFloat(aNumber)) {
+ val = __longFloatVal(aNumber);
+ if (val != 0.0) {
+ result = __longFloatVal(self) / val;
+ goto retResult;
+ }
+ } else if (__isFloatLike(aNumber)) {
+ val = (LONGFLOAT)(__floatVal(aNumber));
+ if (val != 0.0) {
+ result = __longFloatVal(self) / dVal;
+ goto retResult;
+ }
+ } else if (__isShortFloat(aNumber)) {
+ val = (LONGFLOAT)(__shortFloatVal(aNumber));
+ if (val != 0.0) {
+ result = __longFloatVal(self) / dVal;
+ goto retResult;
+ }
+ }
+%}.
+ ((aNumber == 0) or:[aNumber = 0.0]) ifTrue:[
+ "
+ No, you shalt not divide by zero
+ "
+ ^ DivisionByZeroSignal raise.
+ ].
+ ^ aNumber quotientFromLongFloat:self
+!
+
+negated
+ "return myself negated"
+
+%{ /* NOCONTEXT */
+ OBJ newFloat;
+ LONGFLOAT rslt = - __longFloatVal(self);
+
+ __qMKKFLOAT(newFloat, rslt);
+ RETURN ( newFloat );
+%}
+
+!
+
+uncheckedDivide:aNumber
+ "return the quotient of the receiver and the argument, aNumber
+ Do not check for divide by zero (return NaN or infinity)"
+
+%{ /* NOCONTEXT */
+
+ OBJ newFloat;
+ LONGFLOAT result, val;
+
+ if (__isSmallInteger(aNumber)) {
+ result = __longFloatVal(self) / (LONGFLOAT)(__intVal(aNumber));
+retResult:
+ __qMKLFLOAT(newFloat, result);
+ RETURN ( newFloat );
+ } else if (__isLongFloat(aNumber)) {
+ result = __longFloatVal(self) / __longFloatVal(aNumber);
+ goto retResult;
+ } else if (__isFloatLike(aNumber)) {
+ val = (LONGFLOAT)(__floatVal(aNumber));
+ result = __longFloatVal(self) / val;
+ goto retResult;
+ } else if (__isShortFloat(aNumber)) {
+ val = (LONGFLOAT)(__shortFloatVal(aNumber));
+ result = __longFloatVal(self) / val;
+ goto retResult;
+ }
+%}.
+ ^ aNumber quotientFromLongFloat:self
+
+ "
+ 0.0 asLongFloat uncheckedDivide:0
+ 1.0 asLongFloat uncheckedDivide:0.0
+ "
+
+! !
+
+!LongFloat methodsFor:'coercion and converting'!
+
+asFloat
+ "return a Float with same value as the receiver"
+
+%{ /* NOCONTEXT */
+
+ OBJ newFloat;
+ double dVal = (double)__longFloatVal(self);
+
+ __qMKFLOAT(newFloat, dVal);
+ RETURN ( newFloat );
+%}
+
+ "
+ 1.0 asLongFloat
+ "
+!
+
+asShortFloat
+ "return a ShortFloat with same value as the receiver"
+
+%{ /* NOCONTEXT */
+
+ OBJ newFloat;
+ float fVal = (float)__longFloatVal(self);
+
+ __qMKSFLOAT(newFloat, fVal);
+ RETURN ( newFloat );
+%}
+
+ "
+ 1.0 asLongFloat asShortFloat
+ "
+!
+
+asInteger
+ "return an integer with same value - might truncate"
+
+%{ /* NOCONTEXT */
+ LONGFLOAT fVal;
+
+ fVal = __longFloatVal(self);
+ if ((fVal >= (LONGFLOAT)_MIN_INT) && (fVal <= (LONGFLOAT)_MAX_INT)) {
+ RETURN ( __MKSMALLINT( (INT)fVal) );
+ }
+%}.
+ ^ super asInteger
+
+ "
+ 12345.0 asLongFloat asInteger
+ 1e15 asLongFloat asInteger
+ "
+!
+
+asLongFloat
+ "return a LongFloat with same value as the receiver - thats me"
+
+ ^ self
+!
+
+generality
+ "return the generality value - see ArithmeticValue>>retry:coercing:"
+
+ ^ 90
+! !
+
+!LongFloat methodsFor:'comparing'!
+
+< aNumber
+ "return true, if the argument is greater"
+
+%{ /* NOCONTEXT */
+
+ if (__isSmallInteger(aNumber)) {
+ RETURN ( (__longFloatVal(self) < (LONGFLOAT)(__intVal(aNumber))) ? true : false );
+ }
+ if (__isLongFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) < __longFloatVal(aNumber)) ? true : false );
+ }
+ if (__isFloatLike(aNumber)) {
+ RETURN ( (__longFloatVal(self) < (LONGFLOAT)(__floatVal(aNumber))) ? true : false );
+ }
+ if (__isShortFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) < (LONGFLOAT)(__shortFloatVal(aNumber))) ? true : false );
+ }
+%}.
+ ^ aNumber lessFromLongFloat:self
+
+ "
+ 1.0 asLongFloat > (1/3)
+ 1.0 asLongFloat > (1/3) asLongFloat
+ "
+!
+
+<= aNumber
+ "return true, if the argument is greater or equal"
+
+%{ /* NOCONTEXT */
+
+ if (__isSmallInteger(aNumber)) {
+ RETURN ( (__longFloatVal(self) <= (LONGFLOAT)(__intVal(aNumber))) ? true : false );
+ }
+ if (__isLongFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) <= __longFloatVal(aNumber)) ? true : false );
+ }
+ if (__isFloatLike(aNumber)) {
+ RETURN ( (__longFloatVal(self) <= (LONGFLOAT)(__floatVal(aNumber))) ? true : false );
+ }
+ if (__isShortFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) <= (LONGFLOAT)(__shortFloatVal(aNumber))) ? true : false );
+ }
+%}.
+ ^ self retry:#<= coercing:aNumber
+
+!
+
+= aNumber
+ "return true, if the arguments value are equal by value"
+
+%{ /* NOCONTEXT */
+
+ if (__isSmallInteger(aNumber)) {
+ RETURN ( (__longFloatVal(self) == (LONGFLOAT)(__intVal(aNumber))) ? true : false );
+ }
+ if (__isLongFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) == __longFloatVal(aNumber)) ? true : false );
+ }
+ if (__isFloatLike(aNumber)) {
+ RETURN ( (__longFloatVal(self) == (LONGFLOAT)(__floatVal(aNumber))) ? true : false );
+ }
+ if (__isShortFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) == (LONGFLOAT)(__shortFloatVal(aNumber))) ? true : false );
+ }
+%}.
+ ^ self retry:#= coercing:aNumber
+
+!
+
+> aNumber
+ "return true, if the argument is less"
+
+%{ /* NOCONTEXT */
+
+ if (__isSmallInteger(aNumber)) {
+ RETURN ( (__longFloatVal(self) > (LONGFLOAT)(__intVal(aNumber))) ? true : false );
+ }
+ if (__isLongFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) > __longFloatVal(aNumber)) ? true : false );
+ }
+ if (__isFloatLike(aNumber)) {
+ RETURN ( (__longFloatVal(self) > (LONGFLOAT)(__floatVal(aNumber))) ? true : false );
+ }
+ if (__isShortFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) > (LONGFLOAT)(__shortFloatVal(aNumber))) ? true : false );
+ }
+%}.
+ ^ self retry:#> coercing:aNumber
+!
+
+>= aNumber
+ "return true, if the argument is less or equal"
+
+%{ /* NOCONTEXT */
+
+ if (__isSmallInteger(aNumber)) {
+ RETURN ( (__longFloatVal(self) >= (LONGFLOAT)(__intVal(aNumber))) ? true : false );
+ }
+ if (__isLongFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) >= __longFloatVal(aNumber)) ? true : false );
+ }
+ if (__isFloatLike(aNumber)) {
+ RETURN ( (__longFloatVal(self) >= (LONGFLOAT)(__floatVal(aNumber))) ? true : false );
+ }
+ if (__isShortFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) >= (LONGFLOAT)(__shortFloatVal(aNumber))) ? true : false );
+ }
+%}.
+ ^ self retry:#>= coercing:aNumber
+!
+
+hash
+ "return a number for hashing; redefined, since floats compare
+ by numeric value (i.e. 3.0 = 3), therefore 3.0 hash must be the same
+ as 3 hash."
+
+ |i|
+
+ (self >= SmallInteger minVal and:[self <= SmallInteger maxVal]) ifTrue:[
+ i := self asInteger.
+ self = i ifTrue:[
+ ^ i hash
+ ].
+ ].
+
+ "
+ mhmh take some of my value-bits to hash on
+ "
+ ^ (((self basicAt:4) bitAnd:16r3F) bitShift:24) +
+ ((self basicAt:3) bitShift:16) +
+ ((self basicAt:2) bitShift:8) +
+ (self basicAt:1)
+
+ "
+ 1.2345 hash
+ 1.2345 asLongFloat hash
+ 1.0 hash
+ 1.0 asLongFloat hash
+ "
+!
+
+~= aNumber
+ "return true, if the arguments value are not equal"
+
+%{ /* NOCONTEXT */
+
+ if (__isSmallInteger(aNumber)) {
+ RETURN ( (__longFloatVal(self) != (LONGFLOAT)(__intVal(aNumber))) ? true : false );
+ }
+ if (__isLongFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) != __longFloatVal(aNumber)) ? true : false );
+ }
+ if (__isFloatLike(aNumber)) {
+ RETURN ( (__longFloatVal(self) != (LONGFLOAT)(__floatVal(aNumber))) ? true : false );
+ }
+ if (__isShortFloat(aNumber)) {
+ RETURN ( (__longFloatVal(self) != (LONGFLOAT)(__shortFloatVal(aNumber))) ? true : false );
+ }
+%}.
+ ^ self retry:#~= coercing:aNumber
+
+! !
+
+!LongFloat methodsFor:'printing & storing'!
+
+printString
+ "return a printed representation of the receiver
+ LimitedPrecisonReal and its subclasses use #printString instead of
+ #printOn: as basic print mechanism."
+
+%{ /* NOCONTEXT */
+
+ char buffer[64];
+ REGISTER char *cp;
+ OBJ s;
+
+ /*
+ * actually only needed on sparc: since thisContext is
+ * in a global register, which gets destroyed by printf,
+ * manually save it here - very stupid ...
+ */
+ __BEGIN_PROTECT_REGISTERS__
+
+ sprintf(buffer, "%.6LG", __longFloatVal(self));
+
+ __END_PROTECT_REGISTERS__
+
+ /*
+ * kludge to make integral float f prints as "f.0" (not as "f" as printf does)
+ * (i.e. look if string contains '.' or 'e' and append '.0' if not)
+ */
+ for (cp = buffer; *cp; cp++) {
+ if ((*cp == '.') || (*cp == 'e')) break;
+ }
+ if (! *cp) {
+ *cp++ = '.';
+ *cp++ = '0';
+ *cp = '\0';
+ }
+
+ s = __MKSTRING(buffer COMMA_SND);
+ if (s != nil) {
+ RETURN (s);
+ }
+%}.
+ "
+ memory allocation (for the new string) failed.
+ When we arrive here, there was no memory, even after a garbage collect.
+ This means, that the VM wanted to get some more memory from the
+ OS, which was not kind enough to give it.
+ Bad luck - you should increase the swap space on your machine.
+ "
+ ^ ObjectMemory allocationFailureSignal raise.
+! !
+
+!LongFloat methodsFor:'special access'!
+
+exponent
+ "extract a normalized floats exponent.
+ The returned value depends on the float-representation of
+ the underlying machine and is therefore highly unportable.
+ This is not for general use.
+ This assumes that the mantissa is normalized to
+ 0.5 .. 1.0 and the floats value is mantissa * 2^exp"
+
+%{ /* NOCONTEXT */
+
+#if 0
+ double frexp();
+ double frac;
+ INT exp;
+
+ errno = 0;
+ frac = frexp( (double)(__shortFloatVal(self)), &exp);
+ if (errno == 0) {
+ RETURN (__MKSMALLINT(exp));
+ }
+#endif
+%}.
+ ^ self primitiveFailed
+
+ "
+ 1.0 asLongFloat exponent
+ 1.0 asLongFloat exponent
+ 0.5 asLongFloat exponent
+ 0.25 asLongFloat exponent
+ 0.00000011111 asLongFloat exponent
+ "
+!
+
+mantissa
+ "extract a normalized floats mantissa.
+ The returned value depends on the float-representation of
+ the underlying machine and is therefore highly unportable.
+ This is not for general use.
+ This assumes that the mantissa is normalized to
+ 0.5 .. 1.0 and the floats value is mantissa * 2^exp"
+
+%{ /* NOCONTEXT */
+
+#if 0
+ double frexp();
+ double frac;
+ INT exp;
+
+ errno = 0;
+ frac = frexp( (double)(__shortFloatVal(self)), &exp);
+ if (errno == 0) {
+ RETURN (__MKFLOAT(frac));
+ }
+#endif
+%}.
+ ^ self primitiveFailed
+
+ "
+ 1.0 asLongFloat exponent
+ 1.0 asLongFloat mantissa
+
+ 0.5 asLongFloat exponent
+ 0.5 asLongFloat mantissa
+
+ 0.25 asLongFloat exponent
+ 0.25 asLongFloat mantissa
+
+ 0.00000011111 asLongFloat exponent
+ 0.00000011111 asLongFloat mantissa
+ "
+! !
+
+!LongFloat methodsFor:'testing'!
+
+isFinite
+ "return true, if the receiver is a finite float
+ i.e. not NaN and not infinite."
+
+%{ /* NOCONTEXT */
+
+ double dV = (double) __longFloatVal(self);
+
+ /*
+ * notice: on machines which do not provide
+ * a finite() macro or function (WIN32),
+ * this may always return true here ...
+ */
+ if (finite(dV)) { RETURN (true); }
+%}.
+ ^false
+
+ "
+ 1.0 asLongFloat isFinite
+ (0.0 asLongFloat uncheckedDivide: 0.0) isFinite
+ (1.0 asLongFloat uncheckedDivide: 0.0) isFinite
+ "
+!
+
+isNaN
+ "return true, if the receiver is an invalid float (NaN - not a number).
+ These are not created by ST/X float operations (they raise an exception);
+ however, inline C-code could produce them ..."
+
+%{ /* NOCONTEXT */
+
+ double dV = (double)(__longFloatVal(self));
+
+ /*
+ * notice: on machines which do not provide
+ * a finite() macro or function (WIN32),
+ * this may always return false here ...
+ */
+ if (isnan(dV)) { RETURN (true); }
+
+#if 0 /* Currently all our systems support isnan()
+ * If not, you have to fix librun/jinterpret.c also.
+ */
+
+ /*
+ * sigh - every vendor is playing its own game here ...
+ * Q: what are standards worth, anyway ?
+ */
+#ifdef IS_NAN
+ if (IS_NAN(dV)) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef IS_QNAN
+ if (IS_QNAN(dV)) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef FLT_SNAN
+ if (dV == FLT_SNAN) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef FLT_QNAN
+ if (dV == FLT_QNAN) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef _SNANF
+ if (dV == _SNAN) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef _QNANF
+ if (dV == _QNAN) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef IsPosNAN
+ if IsPosNAN(dV) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef IsNegNAN
+ if IsNegNAN(dV) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef NAN
+ if (dV == NAN) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#ifdef NaN
+ if (NaN(dV)) { RETURN (true); }
+ RETURN (false);
+#endif
+
+#endif /* 0 */
+%}.
+ ^ false
+
+ "
+ 1.0 asLongFloat isNaN
+ (0.0 asLongFloat uncheckedDivide: 0.0) isNaN
+ "
+!
+
+negative
+ "return true if the receiver is less than zero"
+
+%{ /* NOCONTEXT */
+
+ RETURN ( (__longFloatVal(self) < 0.0) ? true : false );
+%}
+!
+
+positive
+ "return true if the receiver is greater or equal to zero"
+
+%{ /* NOCONTEXT */
+
+ RETURN ( (__longFloatVal(self) >= 0.0) ? true : false );
+%}
+!
+
+strictlyPositive
+ "return true if the receiver is greater than zero"
+
+%{ /* NOCONTEXT */
+
+ RETURN ( (__longFloatVal(self) > 0.0) ? true : false );
+%}
+! !
+
+!LongFloat methodsFor:'truncation and rounding'!
+
+floor
+ "return the integer nearest the receiver towards negative infinity."
+
+ |val|
+
+ ^ val asInteger
+
+ "
+ 0.5 asLongFloat floor
+ -0.5 asLongFloat floor
+ "
+!
+
+fractionPart
+ "extract the after-decimal fraction part.
+ the floats value is
+ float truncated + float fractionalPart"
+
+%{ /* NOCONTEXT */
+#if 0
+ double modf();
+ double frac, trunc;
+
+ errno = 0;
+ frac = modf((double)(__shortFloatVal(self)), &trunc);
+ if (errno == 0) {
+ RETURN (__MKSFLOAT(frac));
+ }
+#endif
+%}.
+ ^ self primitiveFailed
+
+ "
+ 1.0 asLongFloat fractionalPart
+ 0.5 asLongFloat fractionalPart
+ 0.25 asLongFloat fractionalPart
+ 3.14159 asLongFloat fractionalPart
+ 12345673.14159 asLongFloat fractionalPart
+ 123456731231231231.14159 asLongFloat fractionalPart
+ "
+
+! !
+
+!LongFloat class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libbasic/LongFloat.st,v 1.1 1999-05-10 13:12:16 cg Exp $'
+! !
+