LongFloat.st
author Claus Gittinger <cg@exept.de>
Sat, 25 Sep 1999 15:20:37 +0200
changeset 4814 7825b9141f01
parent 4455 2d31d0d986be
child 4825 4c77d43433d1
permissions -rw-r--r--
changes to allow compilation under win32 (does not like strings beginning with a cr - how comes this ?)

"
 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 /* WIN32 */

#ifdef realIX
/*
 * no finite(x)
 */
# ifndef finite
#  define finite(x)     1
# endif
#endif /* realIX */

#ifdef WIN32
# define LONGFLOAT      long double
#endif
#if defined(__GNUC__) && defined(i386)
# define LONGFLOAT      long double
#endif

/*
 * on systems which do not support long doubles, fall back to Float
 * arithmetic
 */
#ifndef LONGFLOAT
# define LONGFLOAT       double
# define LONGFLOAT_CLASS  Float
# define LONGFLOAT_GLOBAL @global(Float)
#else
# define LONGFLOAT_CLASS LongFloat
# define LONGFLOAT_GLOBAL @global(LongFloat)
#endif

struct __longfloatstruct {
	HEADER
#ifdef __NEED_DOUBLE_ALIGN
	__FILLTYPE_DOUBLE       f_filler;
#endif
	LONGFLOAT               f_longfloatvalue;
};
#define __LongFloatInstPtr(obj)      ((struct __longfloatstruct *)(__objPtr(obj)))

#ifndef __longFloatVal
# define __longFloatVal(o) \
	__LongFloatInstPtr(o)->f_longfloatvalue
#endif

#ifndef __qMKLFLOAT
# define __qMKLFLOAT(__newFloat__, __fVal__) \
    { \
	__qNew(__newFloat__ , sizeof(struct __longfloatstruct)); \
	if (__newFloat__) { \
	    __qClass(__newFloat__) = LONGFLOAT_GLOBAL; \
	    __LongFloatInstPtr(__newFloat__)->f_longfloatvalue = (LONGFLOAT)(__fVal__); \
	} \
    }
#endif

#ifndef __isLongFloat
# define __isLongFloat(o) \
	(__qClass(o) == @global(LongFloat))
#endif

%}
! !

!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) / val;
            goto retResult;
        }
    } else if (__isShortFloat(aNumber)) {
        val = (LONGFLOAT)(__shortFloatVal(aNumber));
        if (val != 0.0) {
            result = __longFloatVal(self) / val;
            goto retResult;
        }
    }
%}.
    ((aNumber == 0) or:[aNumber = 0.0]) ifTrue:[
        "
         No, you shalt not divide by zero
        "
        ^ DivisionByZeroSignal raiseRequest.
    ].
    ^ aNumber quotientFromLongFloat:self
!

negated
    "return myself negated"

%{  /* NOCONTEXT */
    OBJ newFloat;
    LONGFLOAT rslt = - __longFloatVal(self);

    __qMKLFLOAT(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 
    "
!

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
!

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  
    "
!

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 ret 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 ret 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.6 1999-07-26 09:10:56 stefan Exp $'
! !