initial - not yet tested/released
authorClaus Gittinger <cg@exept.de>
Mon, 10 May 1999 15:12:16 +0200
changeset 4165 6d83608a7584
parent 4164 59da946fb307
child 4166 5730ad6b744b
initial - not yet tested/released
LongFloat.st
--- /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 $'
+! !
+