QuadFloat.st
author Claus Gittinger <cg@exept.de>
Sat, 02 May 2020 21:40:13 +0200
changeset 5476 7355a4b11cb6
parent 5384 764be1a073d6
permissions -rw-r--r--
#FEATURE by cg class: Socket class added: #newTCPclientToHost:port:domain:domainOrder:withTimeout: changed: #newTCPclientToHost:port:domain:withTimeout:

"
 COPYRIGHT (c) 2018 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.
"
"{ Package: 'stx:libbasic2' }"

"{ NameSpace: Smalltalk }"

LimitedPrecisionReal variableByteSubclass:#QuadFloat
	instanceVariableNames:''
	classVariableNames:'QuadFloatZero QuadFloatOne Pi E Epsilon NaN PositiveInfinity
		NegativeInfinity Halfpi HalfpiNegative Phi'
	poolDictionaries:''
	category:'Magnitude-Numbers'
!

!QuadFloat primitiveDefinitions!
%{
#ifdef __xxosx__
# define SUPPORT_QUADFLOAT
#endif

#include <math.h>

extern float128_t STX_addq(float128_t, float128_t, int);
extern float128_t STX_mulq(float128_t, float128_t);
extern float128_t STX_divq(float128_t, float128_t);
extern float128_t STX_negq(float128_t);
extern float128_t STX_absq(float128_t);
extern float128_t STX_floorq(float128_t);
extern float128_t STX_frexpq(float128_t, int*);
extern float128_t STX_ceilq(float128_t);
extern float128_t STX_logq(float128_t);
extern float128_t STX_log10q(float128_t);
extern float128_t STX_log2q(float128_t);
extern float128_t STX_expq(float128_t);
extern float128_t STX_sinq(float128_t);
extern float128_t STX_cosq(float128_t);
extern float128_t STX_tanq(float128_t);
extern float128_t STX_sinhq(float128_t);
extern float128_t STX_coshq(float128_t);
extern float128_t STX_tanhq(float128_t);
extern float128_t STX_asinq(float128_t);
extern float128_t STX_acosq(float128_t);
extern float128_t STX_atanq(float128_t);
extern float128_t STX_asinhq(float128_t);
extern float128_t STX_acoshq(float128_t);
extern float128_t STX_atanhq(float128_t);
extern float128_t STX_qZero;
extern float128_t STX_dbltoq(double);
extern float128_t STX_inttoq(long);
extern double STX_qtodbl(float128_t);
extern int STX_isNanq(float128_t*);
extern int STX_prcmpq(float128_t*, float128_t*);

#define STX_isfiniteq(q)    (!STX_isNanq(&(q)) && !STX_isInfq(&(q)))
#define STX_eqq(x1, x2)     (STX_prcmpq (&(x1), &(x2)) == 0)
#define STX_neqq(x1, x2)    (STX_prcmpq (&(x1), &(x2)) != 0)
#define STX_gtq(x1, x2)     (STX_prcmpq (&(x1), &(x2)) > 0)
#define STX_geq(x1, x2)     (STX_prcmpq (&(x1), &(x2)) >= 0)
#define STX_ltq(x1, x2)     (STX_prcmpq (&(x1), &(x2)) < 0)
#define STX_leq(x1, x2)     (STX_prcmpq (&(x1), &(x2)) <= 0)

#ifdef __win32__
/*
 * no finite(x) ?
 * no isnan(x) ?
 */
# ifndef isnan
#  define isnan(x)      \
	((((unsigned int *)(&x))[0] == 0x00000000) && \
	 (((unsigned int *)(&x))[1] == 0xFFF80000))
# endif

# ifndef isPositiveInfinity
#  define isPositiveInfinity(x) \
	((((unsigned int *)(&x))[0] == 0x00000000) && \
	 (((unsigned int *)(&x))[1] == 0x7FF00000))
# endif

# ifndef isNegativeInfinity
#  define isNegativeInfinity(x) \
	((((unsigned int *)(&x))[0] == 0x00000000) && \
	 (((unsigned int *)(&x))[1] == 0xFFF00000))
# endif

# ifndef isinf
#  define isinf(x) \
	((((unsigned int *)(&x))[0] == 0x00000000) && \
	 ((((unsigned int *)(&x))[1] & 0x7FF00000) == 0x7FF00000))
# endif

# ifndef isfinite
#  define isfinite(x) (!isinf(x) && !isnan(x))
# endif

#else // not win32
#endif

%}
! !

!QuadFloat primitiveVariables!
%{
%}
! !

!QuadFloat primitiveFunctions!
%{
%}
! !

!QuadFloat class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 2018 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
"
    QuadFloats represent rational numbers with limited precision
    and are mapped to IEEE quadruple precision format (128bit),
    also called binary128.

    If the underlying cpu supports them natively, the machine format (long double) is
    used. Otherwise, a software emulation is done, which is much slower.
    Thus only use them, if you really need the additional precision;
    if not, use Float (which are doubles) or LongFloats which usually have IEEE extended precision (80bit).

    QuadFloats give you definite 128 bit quadruple floats,
    thus, code using quadFloats is guaranteed to be portable from one architecture to another.

    Representation:
	    128bit quadruple IEEE floats (16bytes);
	    112 bit mantissa,
	    16 bit exponent,
	    34 decimal digits (approx.)

    On Sparc CPUs, this is a native supported type (long double) and fast;
    on x86 CPUs, this is emulated and slow.

    Mixed mode arithmetic:
	quadFloat op anyFloat    -> quadFloat
	anyFloat op quadFloat    -> quadFloat

    Range and precision of storage formats: see LimitedPrecisionReal >> documentation

    [author:]
	Claus Gittinger

    [see also:]
	Number
	Float ShortFloat LongFloat Fraction FixedPoint Integer Complex
	FloatArray DoubleArray
	https://en.wikipedia.org/wiki/Extended_precision
"
! !

!QuadFloat class methodsFor:'instance creation'!

basicNew
    "return a new quadFloat - here we return 0.0
     - QuadFloats are usually NOT created this way ...
     Its implemented here to allow things like binary store & load
     of quadFloats.
     (but it is not a good idea to store the bits of a float - the reader might have a
      totally different representation - so floats should be
      binary stored in a device independent format)."

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;

    if (sizeof(long double) == sizeof(float128_t)) {
	__qMKLFLOAT(newFloat, 0.0);   /* OBJECT ALLOCATION */
    } else {
	float128_t qf = STX_qZero;
	__qMKQFLOAT(newFloat, qf);   /* OBJECT ALLOCATION */
    }
    RETURN (newFloat);
#endif /* SUPPORT_QUADFLOAT */
%}.
    self error:'QuadFloats not supported on this patform'

    "Created: / 06-06-2019 / 17:18:58 / Claus Gittinger"
!

fromFloat:aFloat
    "return a new quadFloat, given a float value"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;

    if (__isFloatLike(aFloat)) {
        double f = __floatVal(aFloat);
        float128_t qf;

        qf = STX_dbltoq (f);
        __qMKQFLOAT(newFloat, qf);   /* OBJECT ALLOCATION */
        RETURN (newFloat);
    }
#endif /*
*/
%}.
    aFloat isFloat ifTrue:[
        self errorUnsupported.
        ^ aFloat asLongFloat
    ].
    ArgumentError raise

    "
     QuadFloat fromFloat:123.0
     123.0 asQuadFloat
     123 asQuadFloat
    "

    "Created: / 06-06-2019 / 18:01:03 / Claus Gittinger"
!

fromInteger:anInteger
    "return a new quadFloat, given an integer value"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;

    if (__isSmallInteger(anInteger)) {
	INT iVal = __intVal(anInteger);
	float128_t qf;

	qf = STX_inttoq( (long)iVal );
	__qMKQFLOAT(newFloat, qf);   /* OBJECT ALLOCATION */
	RETURN (newFloat);
    }
#endif /* SUPPORT_QUADFLOAT */
%}.
    ^ super fromInteger:anInteger

    "
     QuadFloat fromInteger:123
     123 asQuadFloat
    "
!

fromLongFloat:aFloat
    "return a new quadFloat, given a long float value"

%{  /* NOCONTEXT */
#ifdef xSUPPORT_QUADFLOAT
    OBJ newFloat;
    union {
        LONGFLOAT_t lf;         // is long double
        extFloat80_t ef;        // is 80bit ext
        float128_t qf;          // is 128bit quad
    } u;

    if (__isLongFloat(aFloat)) {
        u.lf = __longFloatVal(aFloat);

        if (sizeof(LONGFLOAT_t) == 16) {
            // longFloat is already 128 bits in size (sparc)
            __qMKQFLOAT(newFloat, u.qf);   /* OBJECT ALLOCATION */
            RETURN (newFloat);
        }
        if (sizeof(LONGFLOAT_t) < 16) {
            // assume 80bit extended float format (amd64, x86_64)
            u.qf = extF80_to_f128( u.ef);
            __qMKQFLOAT(newFloat, u.qf);   /* OBJECT ALLOCATION */
            RETURN (newFloat);
        }
        // fall into error case
    }
#endif /* SUPPORT_QUADFLOAT */
%}.
    aFloat isLongFloat ifTrue:[
        self errorUnsupported.
        ^ aFloat asLongFloat
    ].
    ArgumentError raise

    "
     QuadFloat fromLongFloat:123.0 asLongFloat
    "
!

fromShortFloat:aShortFloat
    "return a new quadFloat, given a float value"

    ^ self fromFloat:(aShortFloat asFloat)

    "
     QuadFloat fromShortFloat:123.0 asShortFloat
    "

    "Created: / 08-06-2019 / 03:28:37 / Claus Gittinger"
! !

!QuadFloat class methodsFor:'coercing & converting'!

coerce:aNumber
    "convert the argument aNumber into an instance of the receiver (class) and return it."

    ^ aNumber asQuadFloat.

    "Created: / 06-06-2019 / 16:51:01 / Claus Gittinger"
! !

!QuadFloat class methodsFor:'constants'!

NaN
    "return a quadFloat which represents not-a-Number (i.e. an invalid number)"

    |nan|

    NaN isNil ifTrue:[
%{  /* NOCONTEXT */
#ifdef xSUPPORT_QUADFLOAT
	{
	    OBJ newFloat;
	    float128_t qf;

	    softfloat_commonNaNToF128M( (uint32_t*)(&qf) );
	    __qMKQFLOAT(newFloat, qf);   /* OBJECT ALLOCATION */
	    nan = newFloat;
	}
#endif /* SUPPORT_QUADFLOAT */
%}.
	nan isNil ifTrue:[
	    self errorUnsupported
	].
	NaN := nan
    ].
    ^ NaN
!

e
    "return the constant e as quadFloat"

    E isNil ifTrue:[
	"/ eDigits has enough digits for 128bit IEEE quads
	"/ do not use as a literal constant here - we cannot depend on the underlying C-compiler here...
	E  := self readFrom:(Number eDigits)
    ].
    ^ E

    "Created: / 06-06-2019 / 17:01:54 / Claus Gittinger"
!

infinity
    "return a quadFloat which represents +INF"

    |inf|

    PositiveInfinity isNil ifTrue:[
%{  /* NOCONTEXT */
#ifdef xSUPPORT_QUADFLOAT
	{
	    OBJ newFloat;
	    struct uint128 uiZ;
	    union ui128_f128 uZ;
	    float128_t qf;

	    uiZ.v64 = packToF128UI64( 0, 0x7FFF, 0 );
	    uiZ.v0 = 0;
	    uZ.ui = uiZ;
	    qf = uZ.f;
	    __qMKQFLOAT(newFloat, qf);   /* OBJECT ALLOCATION */
	    inf = newFloat;
	}
#endif /* SUPPORT_QUADFLOAT */
%}.
	inf isNil ifTrue:[
	    self errorUnsupported
	].
	PositiveInfinity := inf
    ].
    ^ PositiveInfinity

    "Created: / 08-06-2019 / 14:05:26 / Claus Gittinger"
!

negativeInfinity
    "return a quadFloat which represents -INF"

    |inf|

    NegativeInfinity isNil ifTrue:[
%{  /* NOCONTEXT */
#ifdef xSUPPORT_QUADFLOAT
	{
	    OBJ newFloat;
	    struct uint128 uiZ;
	    union ui128_f128 uZ;
	    float128_t qf;

	    uiZ.v64 = packToF128UI64( 1, 0x7FFF, 0 );
	    uiZ.v0 = 0;
	    uZ.ui = uiZ;
	    qf = uZ.f;
	    __qMKQFLOAT(newFloat, qf);   /* OBJECT ALLOCATION */
	    inf = newFloat;
	}
#endif /* SUPPORT_QUADFLOAT */
%}.
	inf isNil ifTrue:[
	    self errorUnsupported
	].
	NegativeInfinity := inf
    ].
    ^ NegativeInfinity

    "Created: / 08-06-2019 / 14:05:50 / Claus Gittinger"
!

phi
    "return the constant phi as quadFloat"

    Phi isNil ifTrue:[
	"/ phiDigits has enough digits for 128bit IEEE quads
	"/ do not use as a literal constant here - we cannot depend on the underlying C-compiler here...
	Phi  := self readFrom:(Number phiDigits)
    ].
    ^ Phi
!

pi
    "return the constant pi as quadFloat"

    Pi isNil ifTrue:[
	"/ piDigits has enough digits for 128bit IEEE quads
	"/ do not use as a literal constant here - we cannot depend on the underlying C-compiler here...
	Pi  := self readFrom:(Number piDigits)
    ].
    ^ Pi

    "Created: / 06-06-2019 / 17:09:51 / Claus Gittinger"
!

unity
    "return the neutral element for multiplication (1.0) as QuadFloat"

    QuadFloatOne isNil ifTrue:[
	QuadFloatOne := 1.0 asQuadFloat.
    ].
    ^ QuadFloatOne

    "Created: / 07-06-2019 / 03:26:38 / Claus Gittinger"
!

zero
    "return the neutral element for addition (0.0) as QuadFloat"

    QuadFloatZero isNil ifTrue:[
	QuadFloatZero := 0.0 asQuadFloat
    ].
    ^ QuadFloatZero

    "Created: / 07-06-2019 / 09:22:56 / Claus Gittinger"
! !

!QuadFloat class methodsFor:'error reportng'!

errorUnsupported
    "you may proceed from this error, to get a long float number result 
     (of course, with less than expected precision)"

    self errorUnsupported:'QuadFloats not supported on this patform'

    "Created: / 07-06-2019 / 02:44:39 / Claus Gittinger"

    "
     UnimplementedFunctionalityError handle:[:ex |
         ex proceed
     ] do:[
         1.0 asQuadFloat
     ]. 
    "
! !

!QuadFloat class methodsFor:'queries'!

epsilon
    "return the maximum relative spacing of instances of mySelf
     (i.e. the value-delta of the least significant bit)"

    Epsilon isNil ifTrue:[
	Epsilon := self computeEpsilon.
    ].
    ^ Epsilon

    "
     self epsilon
    "

    "Created: / 10-06-2019 / 21:21:18 / Claus Gittinger"
!

exponentCharacter
    "return the character used to print between mantissa an exponent.
     Also used by the scanner when reading numbers."

    ^ $Q

    "Created: / 10-06-2019 / 21:28:04 / Claus Gittinger"
!

numBitsInExponent
    "answer the number of bits in the exponent.
     This is an IEEE 128bit quadfloat, where 15 bits are available in the exponent:
	seeeeeee eeeeeeee mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm...
    "

    ^ 15

    "
     1.0 class numBitsInExponent -> 11
     1.0 asShortFloat class numBitsInExponent -> 8
     1.0 asLongFloat class numBitsInExponent -> 15
     1.0 asQuadFloat class numBitsInExponent -> 15
    "

    "Created: / 11-06-2019 / 00:14:55 / Claus Gittinger"
!

numBitsInMantissa
    "answer the number of bits in the mantissa (the significant)
     This is an 128bit quadfloat, where 112 bits are available in the mantissa 
     (the hidden bit is not counted here):
        seeeeeee eeeeeeee mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm...
    "

    ^ 112

    "
     1.0 class numBitsInMantissa
     1.0 asShortFloat class numBitsInMantissa
     1.0 asLongFloat class numBitsInMantissa
     1.0 asQuadFloat class numBitsInMantissa
    "

    "Created: / 07-06-2019 / 03:24:20 / Claus Gittinger"
!

radix
    "answer the radix of a QuadFloat's exponent
     This is an IEEE float, which is represented as binary"

    ^ 2 "must be careful here, whenever ST/X is used on VAX or a 370"

    "Created: / 19-07-2019 / 17:28:00 / Claus Gittinger"
! !

!QuadFloat methodsFor:'arithmetic'!

* aNumber
    "return the product of the receiver and the argument."

    aNumber class == QuadFloat ifTrue:[
        ^ aNumber productFromQuadFloat:self
    ].
    "/ DEBUGGING
    thisContext isReallyRecursive ifTrue:[self error].
    ^ aNumber productFromQuadFloat:self
!

+ aNumber
    "return the sum of the receiver and the argument, aNumber"

    ^ aNumber sumFromQuadFloat:self
!

- aNumber
    "return the difference of the receiver and the argument, aNumber"

    ^ aNumber differenceFromQuadFloat:self
!

/ aNumber
    "return the quotient of the receiver and the argument, aNumber"

    aNumber isZero ifTrue:[
	"
	 No, you shalt not divide by zero
	"
	^ ZeroDivide raiseRequestWith:thisContext.
    ].
    ^ aNumber quotientFromQuadFloat:self
!

abs
    "return the absolute value of the receiver
     reimplemented here for speed"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_absq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

ceiling
    "return the smallest integer which is greater or equal to the receiver."

    |val|

%{
#ifdef SUPPORT_QUADFLOAT
    float128_t qVal;
    float128_t qMinInt;
    float128_t qMaxInt;

    qVal = __quadFloatVal(self);
    qVal = STX_ceilq(qVal);

    qMinInt = STX_dbltoq((double)_MIN_INT);
    qMaxInt = STX_dbltoq((double)_MAX_INT);
    if (STX_geq(qVal, qMinInt) && STX_leq(qVal, qMaxInt)) {
	double dVal = STX_qtodbl(qVal);
	RETURN ( __mkSmallInteger( (INT) dVal ) );
    }
    __qMKQFLOAT(val, qVal);
#endif
%}.
    ^ val asInteger

    "
     0.5 asQuadFloat ceiling
     0.5 asQuadFloat ceilingAsFloat
     -0.5 asQuadFloat ceiling
     -0.5 asQuadFloat ceilingAsFloat
    "
!

ceilingAsFloat
    "return the smallest integer-valued float greater or equal to the receiver.
     This is much like #ceiling, but avoids a (possibly expensive) conversion
     of the result to an integer.
     It may be useful, if the result is to be further used in another float-operation."

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_ceilq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

cos
    "return the cosine of the receiver (interpreted as radians)"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_cosq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

cosh
    "return the hyperbolic cosine of the receiver (interpreted as radians)"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_coshq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

exp
    "return e raised to the power of the receiver"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_expq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

exponent
    "extract a normalized float's (unbiased) 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 float's value is: mantissa * 2^exp"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    float128_t myVal;
    float128_t frac;
    int exp;

    myVal = __quadFloatVal(self);
#if 1
    // should we?
    if (! (STX_isNanq(&myVal) || STX_isInfq(&myVal)))
#endif
    {
	frac = STX_frexpq(myVal, &exp);
	RETURN (__mkSmallInteger(exp));
    }
#endif
%}.
    ^ super exponent

    "
     1.0 exponent
     1.0 asQuadFloat exponent
     2.0 exponent
     2.0 asQuadFloat exponent
     3.0 exponent
     3.0 asQuadFloat exponent
     4.0 exponent
     4.0 asQuadFloat exponent
     0.5 exponent
     0.5 asQuadFloat exponent
     0.4 exponent
     0.4 asQuadFloat exponent
     0.25 exponent
     0.25 asQuadFloat exponent
     0.2 exponent
     0.2 asQuadFloat exponent
     0.00000011111 exponent
     0.00000011111 asQuadFloat exponent
     0.0 exponent
     0.0 asQuadFloat exponent

     1e1000 exponent -> error (INF)
     1e1000 asQuadFloat exponent -> error (INF)
    "
!

floor
    "return the integer nearest the receiver towards negative infinity."

    |val|

%{
#ifdef SUPPORT_QUADFLOAT
    float128_t qVal;
    float128_t qMinInt;
    float128_t qMaxInt;

    qVal = __quadFloatVal(self);
    qVal = STX_floorq(qVal);

    qMinInt = STX_dbltoq((double)_MIN_INT);
    qMaxInt = STX_dbltoq((double)_MAX_INT);
    if (STX_geq(qVal, qMinInt) && STX_leq(qVal, qMaxInt)) {
	double dVal = STX_qtodbl(qVal);
	RETURN ( __mkSmallInteger( (INT) dVal ) );
    }
    __qMKQFLOAT(val, qVal);
#endif
%}.
    ^ val asInteger

    "
     0.5 asQuadFloat floor
     0.5 asQuadFloat floorAsFloat
     -0.5 asQuadFloat floor
     -0.5 asQuadFloat floorAsFloat
    "
!

floorAsFloat
    "return the integer nearest the receiver towards negative infinity as a float.
     This is much like #floor, but avoids a (possibly expensive) conversion
     of the result to an integer.
     It may be useful, if the result is to be further used in another float-operation."

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_floorq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

ln
    "return natural logarithm of the receiver."

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_logq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

log
    "return log base 10 of the receiver.
     Alias for log:10."

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_log10q(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

log2
    "return logarithm dualis of the receiver."

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_log2q(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

mantissa
    "extract a normalized float's 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 float's value is mantissa * 2^exp"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    float128_t myVal;
    float128_t frac;
    int exp;
    OBJ newFloat;

    myVal = __quadFloatVal(self);
    // ouch: math libs seem to not care for NaN here;
#if 1
    // should we?
    if (! (STX_isNanq(&myVal) || STX_isInfq(&myVal)))
#endif
    {
	frac = STX_frexpq(myVal, &exp);
	__qMKQFLOAT(newFloat, frac);
	RETURN ( newFloat );
    }
#endif
%}.
    ^ super mantissa

    "
     1.0 exponent
     1.0 asQuadFloat exponent
     1.0 mantissa
     1.0 asQuadFloat mantissa

     0.25 exponent
     0.25 asQuadFloat exponent
     0.25 mantissa
     0.25 asQuadFloat mantissa

     0.00000011111 exponent
     0.00000011111 mantissa

     1e1000 mantissa
    "

    "Modified: / 20-06-2017 / 11:37:13 / cg"
    "Modified (comment): / 26-05-2019 / 03:12:55 / Claus Gittinger"
!

negated
    "return the receiver negated"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_negq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

rem: aNumber
    "return the floating point remainder of the receiver and the argument, aNumber"

    aNumber isZero ifTrue:[
	"
	 No, you shalt not divide by zero
	"
	^ ZeroDivide raiseRequestWith:thisContext.
    ].
    ^ aNumber remainderFromLongFloat:self
!

sin
    "return the sine of the receiver (interpreted as radians)"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_sinq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

sinh
    "return the hyperbolic sine of the receiver (interpreted as radians)"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_sinhq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

tan
    "return the tangent of the receiver (interpreted as radians)"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_tanq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
!

tanh
    "return the hyperbolic tangent of the receiver (interpreted as radians)"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal;

    myVal = __quadFloatVal(self);
    result = STX_tanhq(myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif
%}.
! !

!QuadFloat methodsFor:'coercing & converting'!

asFloat
    "return a Float with same value as the receiver.
     Raises an error if the receiver exceeds the float range."

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t qVal = __quadFloatVal(self);
    double dVal = STX_qtodbl(qVal);

    if (isfinite(dVal) || !STX_isfiniteq(qVal)) {
	__qMKFLOAT(newFloat, dVal);
	RETURN ( newFloat );
    }
#endif
%}.
    "
     value out of range
     if you need -INF for a zero receiver, try Number trapInfinity:[...]
    "
    ^ self class
	raise:#infiniteResultSignal
	receiver:self
	selector:#asFloat
	arguments:#()
	errorString:'receiver is out of the double-precision float range'

    "
     1.0 asQuadFloat asFloat
    "
!

asIEEEFloat
    "return an IEEE soft float with same value as receiver"

    ^ IEEEFloat fromFloat:self

    "
     123 asFloat asIEEEFloat
     0 asShortFloat asIEEEFloat
     0 asLongFloat asIEEEFloat
     0 asQuadFloat asIEEEFloat
     0.0 asIEEEFloat
    "
!

asQuadFloat
    ^ self

    "
     1.0 asQuadFloat asQuadFloat
    "
!

generality
    "return the generality value - see ArithmeticValue>>retry:coercing:"

    ^ 93

    "Created: / 07-06-2019 / 09:30:58 / Claus Gittinger"
! !

!QuadFloat methodsFor:'comparing'!

< aNumber
    "return true, if the argument is greater"

    ^ aNumber lessFromQuadFloat:self

    "Created: / 07-06-2019 / 09:25:47 / Claus Gittinger"
!

= aNumber
    "return true, if the argument represents the same numeric value
     as the receiver, false otherwise"

    ^ aNumber equalFromQuadFloat:self

    "Created: / 07-06-2019 / 09:25:27 / Claus Gittinger"
!

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
	].
    ].

    ^ self asFloat hash

    "
     1.2345 hash
     1.2345 asShortFloat hash
     1.2345 asLongFloat hash
     1.2345 asQuadFloat hash

     1.0 hash
     1.0 asShortFloat hash
     1.0 asLongFloat hash
     1.0 asQuadFloat hash

     0.5 asShortFloat hash
     0.5 asShortFloat hash
     0.5 asLongFloat hash
     0.5 asQuadFloat hash

     0.25 asShortFloat hash
     0.25 asShortFloat hash
     0.25 asLongFloat hash
     0.25 asQuadFloat hash
    "

    "Created: / 07-06-2019 / 09:28:07 / Claus Gittinger"
! !

!QuadFloat methodsFor:'double dispatching'!

differenceFromQuadFloat:aQuadFloat
%{
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal, argVal;

    myVal = __quadFloatVal(self);
    argVal = __quadFloatVal(aQuadFloat);
    result = STX_addq( argVal, myVal, 1 );
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif // SUPPORT_QUADFLOAT
%}.
    self errorUnsupported
!

equalFromQuadFloat:aQuadFloat
    "sent when aQuadFloat does not know how to compare agaist the receiver, self"

%{
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal, argVal;

    myVal = __quadFloatVal(self);
    argVal = __quadFloatVal(aQuadFloat);
    RETURN (STX_eqq(argVal, myVal) ? true : false);
#endif // SUPPORT_QUADFLOAT
%}.
    self errorUnsupported

    "Modified: / 08-06-2019 / 13:31:48 / Claus Gittinger"
!

lessFromQuadFloat:aQuadFloat
    "sent when aQuadFloat does not know how to compare agaist the receiver, self"

%{
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal, argVal;

    myVal = __quadFloatVal(self);
    argVal = __quadFloatVal(aQuadFloat);
    RETURN (STX_ltq(argVal, myVal) ? true : false);
#endif // SUPPORT_QUADFLOAT
%}.
    self errorUnsupported
!

productFromQuadFloat:aQuadFloat
    "sent when aQuadFloat does not know how to multiply the receiver, self"

%{
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal, argVal;

    myVal = __quadFloatVal(self);
    argVal = __quadFloatVal(aQuadFloat);
    result = STX_mulq(myVal, argVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif // SUPPORT_QUADFLOAT
%}.
    self errorUnsupported
!

quotientFromQuadFloat:aQuadFloat
    "sent when aQuadFloat does not know how to multiply the receiver, self"

%{
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal, argVal;

    myVal = __quadFloatVal(self);
    argVal = __quadFloatVal(aQuadFloat);
    result = STX_divq(argVal, myVal);
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif // SUPPORT_QUADFLOAT
%}.
    self errorUnsupported
!

sumFromQuadFloat:aQuadFloat
    "sent when aQuadFloat does not know how to add the receiver, self"

%{
#ifdef SUPPORT_QUADFLOAT
    OBJ newFloat;
    float128_t result, myVal, argVal;

    myVal = __quadFloatVal(self);
    argVal = __quadFloatVal(aQuadFloat);
    result = STX_addq( myVal, argVal, 0 );
    __qMKQFLOAT(newFloat, result);
    RETURN ( newFloat );
#endif // SUPPORT_QUADFLOAT
%}.
    self errorUnsupported
! !

!QuadFloat methodsFor:'error reportng'!

errorUnsupported
    self class errorUnsupported

    "Modified: / 07-06-2019 / 02:44:51 / Claus Gittinger"
! !

!QuadFloat methodsFor:'printing'!

printOn:aStream
    |mantissa exponent|

    mantissa := self mantissa.
    exponent := self exponent.

    self exponent == 0 ifTrue:[
	mantissa printOn:aStream.
	aStream nextPutAll:'.0'.
	^ self
    ].
    mantissa == 0 ifTrue:[
	"/ a zero mantissa is impossible - except for zero and a few others
	exponent == 0 ifTrue:[ aStream nextPutAll:'0.0'. ^ self].
	self == NaN ifTrue:[ aStream nextPutAll:'NAN'. ^ self ].
	self == NegativeInfinity ifTrue:[ aStream nextPutAll:'-INF'. ^ self].
	self == PositiveInfinity ifTrue:[ aStream nextPutAll:'INF'. ^ self].

	self error:'invalid largeFloat' mayProceed:true.
	aStream nextPutAll:'Invalid'. ^ self.
    ].

    exponent >= 0 ifTrue:[
	(mantissa bitShift:exponent) printOn:aStream.
	aStream nextPutAll:'.0'.
	^ self
    ].
    ((mantissa / (1 bitShift:exponent negated)) asFixedPoint:6) printOn:aStream.

    "Created: / 11-06-2019 / 00:13:00 / Claus Gittinger"
! !

!QuadFloat methodsFor:'queries'!

isFinite
    "return true, if the receiver is a finite float (not NaN and not +/-INF)"

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    float128_t myVal;

    myVal = __quadFloatVal(self);
    RETURN (STX_isfiniteq(myVal) ? true : false);
#endif // SUPPORT_QUADFLOAT
%}.

    "
	1.0 isFinite
	self NaN isFinite
	self infinity isFinite
	self negativeInfinity isFinite
	(0.0 uncheckedDivide: 0.0) isFinite
	(1.0 uncheckedDivide: 0.0) isFinite
    "
!

isInfinite
    "return true, if the receiver is an infinite float (+Inf or -Inf)."

%{  /* NOCONTEXT */
#ifdef SUPPORT_QUADFLOAT
    float128_t myVal;

    myVal = __quadFloatVal(self);
    RETURN (STX_isInfq(&myVal) ? true : false);
#endif // SUPPORT_QUADFLOAT
%}.

    "
	1.0 asQuadFloat isFinite
	1.0 asQuadFloat isInfinite
	self NaN isFinite
	self NaN isInfinite
	self infinity isFinite
	self infinity isInfinite
	self negativeInfinity isFinite
	self negativeInfinity isInfinite
	(0.0 uncheckedDivide: 0.0) isFinite
	(1.0 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 */
#ifdef SUPPORT_QUADFLOAT
    float128_t myVal;

    myVal = __quadFloatVal(self);
    RETURN (STX_isNanq(&myVal) ? true : false);
#endif // SUPPORT_QUADFLOAT
%}.

    "
	1.0 asQuadFloat isFinite
	self NaN isFinite
	self infinity isFinite
	(0.0 uncheckedDivide: 0.0) isFinite
	(1.0 uncheckedDivide: 0.0) isFinite
    "
! !

!QuadFloat methodsFor:'testing'!

isQuadFloat
    "return true, if the receiver is some kind of quad floating point number (iee quad precision)"

    ^ true
! !

!QuadFloat class methodsFor:'documentation'!

version_CVS
    ^ '$Header$'
! !