signals vs. errors
"
COPYRIGHT (c) 1996 by Claus Gittinger
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:libbasic' }"
LimitedPrecisionReal variableByteSubclass:#ShortFloat
instanceVariableNames:''
classVariableNames:''
poolDictionaries:''
category:'Magnitude-Numbers'
!
!ShortFloat primitiveDefinitions!
%{
#include <errno.h>
#ifndef __OPTIMIZE__
# define __OPTIMIZE__
#endif
#define __USE_ISOC9X 1
#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)
# ifndef NAN
# include <bits/nan.h>
# endif
#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
%}
! !
!ShortFloat class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1996 by Claus Gittinger
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
"
ShortFloats represent rational numbers with limited precision.
They use the C-compilers 'float' format, which is usually the IEE single float format.
In contrast to Floats (which use the C-compilers 64bit 'double' format),
ShortFloats give you 32 bit floats.
Notice, that ST/X Floats are what Doubles are in ST-80 and ShortFloats are
ST-80's Floats respectively.
This may change in one of the next versions (at least on machines, which
provide different float and double types in their C-compiler.
WARNING:
The layout of shortFloat instances is known by the runtime system and the compiler;
you may not add instance variables here.
Also, subclassing is complicated by the fact, that the VM creates floats/shortFloats,
and does some of its float-checks by an identity compare with the ShortFloat-class.
(i.e. your subclasses instances may not be recognized as float-like objects,
thus mixed mode arithmetic will always coerce them, effectively slowing things down).
This may be changed, to use a flag bit in the class.
Mixed mode arithmetic:
shortFloat op shortFloat -> shortFloat
shortFloat op fix -> shortFloat
shortFloat op fraction -> shortFloat
shortFloat op integer -> shortFloat
shortFloat op longFloat -> longFloat
shortFloat op float -> float
shortFloat op complex -> complex
[author:]
Claus Gittinger
[see also:]
Number
Float LongFloat Fraction FixedPoint Integer Complex
FloatArray DoubleArray
"
! !
!ShortFloat class methodsFor:'instance creation'!
basicNew
"return a new shortFloat - here we return 0.0
- shortFloats are usually NOT created this way ...
Its implemented here to allow things like binary store & load
of shortFloats. (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;
__qMKSFLOAT(newFloat, 0.0);
RETURN (newFloat);
%}
!
fastFromString:aString at:startIndex
"return the next ShortFloat from the string starting at startIndex.
No spaces are skipped.
This is a specially tuned entry (using a low-level C-call), which
returns garbage if the argument string is not a valid float number.
It has been added to allow higher speed string decomposition into
numbers."
%{
if (__isString(aString) && __isSmallInteger(startIndex)) {
char *cp = (char *)(__stringVal(aString));
int idx = __intVal(startIndex) - 1;
double atof();
double val;
if ((unsigned)idx < __stringSize(aString)) {
val = atof(cp + idx);
RETURN (__MKSFLOAT(val));
}
}
%}.
self primitiveFailed.
"
ShortFloat fastFromString:'123.45' at:1
ShortFloat fastFromString:'123.45' at:2
ShortFloat fastFromString:'123.45E4' at:1
ShortFloat fastFromString:'hello123.45E4' at:6
ShortFloat fastFromString:'12345' at:1
ShortFloat fastFromString:'12345' at:2
ShortFloat fastFromString:'12345' at:3
ShortFloat fastFromString:'12345' at:4
ShortFloat fastFromString:'12345' at:5
ShortFloat fastFromString:'12345' at:6
ShortFloat fastFromString:'12345' at:0
ShortFloat fastFromString:'hello123.45E4' at:1
Time millisecondsToRun:[
100000 timesRepeat:[
ShortFloat readFrom:'123.45'
]
]
"
"
Time millisecondsToRun:[
100000 timesRepeat:[
ShortFloat fastFromString:'123.45' at:1
]
]
"
!
readFrom:aStringOrStream
"read a shortFloat from a string"
|num|
num := super readFrom:aStringOrStream onError:[self error:'conversion error for: ' , self name].
num notNil ifTrue:[
num := num asShortFloat
].
^ num
"
ShortFloat readFrom:'0.1'
ShortFloat readFrom:'0'
ShortFloat readFrom:'.123'
ShortFloat readFrom:'-.123'
ShortFloat readFrom:'1e4'
"
"Modified: / 7.1.1998 / 16:17:59 / cg"
!
readFrom:aStringOrStream onError:exceptionBlock
"read a shortFloat from a string"
|num|
num := super readFrom:aStringOrStream onError:nil.
num isNil ifTrue:[
^ exceptionBlock value
].
^ num asShortFloat
"
ShortFloat readFrom:'0.1'
ShortFloat readFrom:'0'
ShortFloat readFrom:'.123'
"
"Modified: / 7.1.1998 / 16:17:59 / cg"
! !
!ShortFloat class methodsFor:'binary storage'!
readBinaryIEEESingleFrom:aStream
"read a float value from the binary stream, aStream,
interpreting the next bytes as an IEEE formatted 4-byte float"
|f|
f := ShortFloat basicNew.
self readBinaryIEEESingleFrom:aStream into:f.
^ f
"Created: 16.4.1996 / 21:00:35 / cg"
!
readBinaryIEEESingleFrom:aStream into:aFloat
"read a float value from the binary stream, aStream,
interpreting the next bytes as an IEEE formatted 4-byte float"
aFloat isShortFloat ifFalse:[self error].
"
this implementation is wrong: does not work on non-IEEE machines
(to date all machines where ST/X is running on use
IEEE float format. Need more here, when porting ST/X to 370's)
"
self isIEEEFormat ifFalse:[self error:'unsupported operation'].
UninterpretedBytes isBigEndian ifFalse:[
"swap the bytes"
8 to:4 by:-1 do:[:i |
aFloat basicAt:i put:(aStream next)
].
^ self
].
1 to:4 do:[:i |
aFloat basicAt:i put:aStream next
]
!
storeBinaryIEEESingle:aFloat on:aStream
"store aFloat as an IEEE formatted 4-byte float
onto the binary stream, aStream"
aFloat isShortFloat ifFalse:[self error].
"
this implementation is wrong: does not work on non-IEEE machines
(to date all machines where ST/X is running on use
IEEE float format. Need more here, when porting ST/X to 370's)
"
self isIEEEFormat ifFalse:[self error:'unsupported operation'].
UninterpretedBytes isBigEndian ifFalse:[
"swap the bytes"
8 to:4 by:-1 do:[:i |
aStream nextPut:(aFloat basicAt:i).
].
^ self
].
1 to:4 do:[:i |
aStream nextPut:(aFloat basicAt:i).
]
! !
!ShortFloat class methodsFor:'constants'!
e
"return the constant e as ShortFloat"
^ Float e asShortFloat
!
pi
"return the constant pi as ShortFloat"
^ Float pi asShortFloat
!
unity
"return the neutral element for multiplication (1.0) as ShortFloat"
^ 1.0 asShortFloat
"Modified: 23.4.1996 / 09:26:51 / cg"
!
zero
"return the neutral element for addition (0.0) as ShortFloat"
^ 0.0 asShortFloat
"Modified: 23.4.1996 / 09:26:45 / cg"
! !
!ShortFloat class methodsFor:'queries'!
exponentCharacter
^ $e
!
isBuiltInClass
"return true if this class is known by the run-time-system.
Here, true is returned for myself, false for subclasses."
^ self == ShortFloat
"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
!
numBitsInExponent
"answer the number of bits in the exponent
This is an IEEE float, where 8 bits are available:
seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
"
^ 8
!
numBitsInMantissa
"answer the number of bits in the mantissa.
This is an IEEE float, where 23 bits (the hidden one is not counted here) are available:
seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
"
^ 23
!
precision
"answer the precision of a ShortFloat (in bits)
This is an IEEE float, only the fraction from the normalized mantissa is stored
and so there is a hidden bit and the mantissa is actually represented by 24 binary digits"
^ 24
!
radix
"answer the radix of a ShortFloats 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"
! !
!ShortFloat methodsFor:'arithmetic'!
* aNumber
"return the product of the receiver and the argument, aNumber"
%{ /* NOCONTEXT */
OBJ newFloat;
float result;
double dResult;
if (__isSmallInteger(aNumber)) {
result = __shortFloatVal(self) * (float)(__intVal(aNumber));
retResult:
__qMKSFLOAT(newFloat, result);
RETURN ( newFloat );
}
if (__isShortFloat(aNumber)) {
result = __shortFloatVal(self) * __shortFloatVal(aNumber);
goto retResult;
}
if (__isFloatLike(aNumber)) {
dResult = (double) __shortFloatVal(self)* __floatVal(aNumber);
__qMKFLOAT(newFloat, dResult);
RETURN ( newFloat );
}
%}.
^ aNumber productFromShortFloat:self
!
+ aNumber
"return the sum of the receiver and the argument, aNumber"
%{ /* NOCONTEXT */
OBJ newFloat;
float result;
double dResult;
if (__isSmallInteger(aNumber)) {
result = __shortFloatVal(self) + (float)(__intVal(aNumber));
retResult:
__qMKSFLOAT(newFloat, result);
RETURN ( newFloat );
}
if (__isShortFloat(aNumber)) {
result = __shortFloatVal(self) + __shortFloatVal(aNumber);
goto retResult;
}
if (__isFloatLike(aNumber)) {
dResult = (double) __shortFloatVal(self) + __floatVal(aNumber);
__qMKFLOAT(newFloat, dResult);
RETURN ( newFloat );
}
%}.
^ aNumber sumFromShortFloat:self
!
- aNumber
"return the difference of the receiver and the argument, aNumber"
%{ /* NOCONTEXT */
OBJ newFloat;
float result;
double dResult;
if (__isSmallInteger(aNumber)) {
result = __shortFloatVal(self) - (float)(__intVal(aNumber));
retResult:
__qMKSFLOAT(newFloat, result);
RETURN ( newFloat );
}
if (__isShortFloat(aNumber)) {
result = __shortFloatVal(self) - __shortFloatVal(aNumber);
goto retResult;
}
if (__isFloatLike(aNumber)) {
dResult = (double) __shortFloatVal(self) - __floatVal(aNumber);
__qMKFLOAT(newFloat, dResult);
RETURN ( newFloat );
}
%}.
^ aNumber differenceFromShortFloat:self
!
/ aNumber
"return the quotient of the receiver and the argument, aNumber"
%{ /* NOCONTEXT */
OBJ newFloat;
float result, val;
double dResult, dVal;
if (__isSmallInteger(aNumber)) {
if (aNumber != __MKSMALLINT(0)) {
result = __shortFloatVal(self) / (float)(__intVal(aNumber));
retResult:
__qMKSFLOAT(newFloat, result);
RETURN ( newFloat );
}
}
if (__isShortFloat(aNumber)) {
val = __shortFloatVal(aNumber);
if (val != 0.0) {
result = __shortFloatVal(self) / val;
goto retResult;
}
}
if (__isFloatLike(aNumber)) {
dVal = __floatVal(aNumber);
if (dVal != 0.0) {
dResult = (double) __shortFloatVal(self) / dVal;
__qMKFLOAT(newFloat, dResult);
RETURN ( newFloat );
}
}
%}.
((aNumber == 0) or:[aNumber = 0.0]) ifTrue:[
"
No, you shalt not divide by zero
"
^ ZeroDivide raiseRequestWith:thisContext.
].
^ aNumber quotientFromShortFloat:self
!
negated
"return myself negated"
%{ /* NOCONTEXT */
OBJ newFloat;
float rslt = - __shortFloatVal(self);
__qMKSFLOAT(newFloat, rslt);
RETURN ( newFloat );
%}.
^ 0.0 - self
!
uncheckedDivide:aNumber
"return the quotient of the receiver and the argument, aNumber.
Do not check for divide by zero (return NaN or infinity).
This operation is provided for emulators of other languages/semantics,
where no exception is raised for these results (i.e. Java).
Its only defined if the arguments type is the same as the receivers."
%{ /* NOCONTEXT */
OBJ newFloat;
float result, val;
double dResult, dVal;
if (__isSmallInteger(aNumber)) {
result = __shortFloatVal(self) / (float)(__intVal(aNumber));
retResult:
__qMKSFLOAT(newFloat, result);
RETURN ( newFloat );
}
if (__isShortFloat(aNumber)) {
val = __shortFloatVal(aNumber);
result = __shortFloatVal(self) / val;
goto retResult;
}
if (__isFloatLike(aNumber)) {
dVal = __floatVal(aNumber);
dResult = (double) __shortFloatVal(self) / dVal;
__qMKFLOAT(newFloat, dResult);
RETURN ( newFloat );
}
%}.
^ aNumber quotientFromShortFloat:self
"
0.0 asShortFloat uncheckedDivide:0
1.0 asShortFloat uncheckedDivide:0.0
"
! !
!ShortFloat methodsFor:'coercing & converting'!
asFloat
"return a Float with same value as the receiver"
%{ /* NOCONTEXT */
OBJ newFloat;
double dVal = (double)__shortFloatVal(self);
__qMKFLOAT(newFloat, dVal);
RETURN ( newFloat );
%}
"
1.0 asShortFloat asFloat
"
!
asInteger
"return an integer with same value - might truncate"
%{ /* NOCONTEXT */
float fVal;
fVal = __shortFloatVal(self);
if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) {
RETURN ( __MKSMALLINT( (INT)fVal) );
}
%}.
^ super asInteger
"
12345.0 asShortFloat asInteger
1e15 asShortFloat asInteger
"
!
asShortFloat
"return a ShortFloat with same value as the receiver - thats me"
^ self
!
asTrueFraction
"return a fraction or integer with the same value as the receiver"
^ self asFloat asTrueFraction
!
coerce:aNumber
"return aNumber converted into receivers type"
^ aNumber asShortFloat
!
generality
"return the generality value - see ArithmeticValue>>retry:coercing:"
^ 70
! !
!ShortFloat methodsFor:'comparing'!
< aNumber
"return true, if the argument is greater"
%{ /* NOCONTEXT */
if (__isSmallInteger(aNumber)) {
RETURN ( (__shortFloatVal(self) < (float)(__intVal(aNumber))) ? true : false );
}
if (aNumber != nil) {
if (__qIsFloatLike(aNumber)) {
RETURN ( (double)(__shortFloatVal(self) < __floatVal(aNumber)) ? true : false );
}
if (__qIsShortFloat(aNumber)) {
RETURN ( (__shortFloatVal(self) < __shortFloatVal(aNumber)) ? true : false );
}
}
%}.
^ aNumber lessFromShortFloat:self
"
1.0 asShortFloat > (1/3)
"
!
<= aNumber
"return true, if the argument is greater or equal"
%{ /* NOCONTEXT */
if (__isSmallInteger(aNumber)) {
RETURN ( (__shortFloatVal(self) <= (float)(__intVal(aNumber))) ? true : false );
}
if (aNumber != nil) {
if (__qIsFloatLike(aNumber)) {
RETURN ( (double)(__shortFloatVal(self) <= __floatVal(aNumber)) ? true : false );
}
if (__qIsShortFloat(aNumber)) {
RETURN ( (__shortFloatVal(self) <= __shortFloatVal(aNumber)) ? true : false );
}
}
%}.
^ self retry:#<= coercing:aNumber
!
= aNumber
"return true, if the argument represents the same numeric value
as the receiver, false otherwise"
%{ /* NOCONTEXT */
if (__isSmallInteger(aNumber)) {
RETURN ( (__shortFloatVal(self) == (float)(__intVal(aNumber))) ? true : false );
}
if (aNumber == nil) {
RETURN (false);
}
if (__qIsFloatLike(aNumber)) {
RETURN ( (double)(__shortFloatVal(self) == __floatVal(aNumber)) ? true : false );
}
if (__qIsShortFloat(aNumber)) {
RETURN ( (__shortFloatVal(self) == __shortFloatVal(aNumber)) ? true : false );
}
%}.
^ aNumber equalFromShortFloat:self
!
> aNumber
"return true, if the argument is less"
%{ /* NOCONTEXT */
if (__isSmallInteger(aNumber)) {
RETURN ( (__shortFloatVal(self) > (float)(__intVal(aNumber))) ? true : false );
}
if (aNumber != nil) {
if (__qIsFloatLike(aNumber)) {
RETURN ( (double)(__shortFloatVal(self) > __floatVal(aNumber)) ? true : false );
}
if (__qIsShortFloat(aNumber)) {
RETURN ( (__shortFloatVal(self) > __shortFloatVal(aNumber)) ? true : false );
}
}
%}.
^ self retry:#> coercing:aNumber
!
>= aNumber
"return true, if the argument is less or equal"
%{ /* NOCONTEXT */
if (__isSmallInteger(aNumber)) {
RETURN ( (__shortFloatVal(self) >= (float)(__intVal(aNumber))) ? true : false );
}
if (aNumber != nil) {
if (__qIsFloatLike(aNumber)) {
RETURN ( (double)(__shortFloatVal(self) >= __floatVal(aNumber)) ? true : false );
}
if (__qIsShortFloat(aNumber)) {
RETURN ( (__shortFloatVal(self) >= __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
].
].
^ self asFloat hash
"
1.2345 hash
1.2345 asShortFloat hash
1.0 hash
1.0 asShortFloat hash
0.5 asShortFloat hash
0.25 asShortFloat hash
0.5 hash
0.25 hash
"
!
~= aNumber
"return true, if the arguments value are not equal"
%{ /* NOCONTEXT */
if (aNumber != nil) {
if (__isSmallInteger(aNumber)) {
RETURN ( (__shortFloatVal(self) != (float)(__intVal(aNumber))) ? true : false );
}
if (__qIsFloatLike(aNumber)) {
RETURN ( (double)(__shortFloatVal(self) != __floatVal(aNumber)) ? true : false );
}
if (__qIsShortFloat(aNumber)) {
RETURN ( (__shortFloatVal(self) != __shortFloatVal(aNumber)) ? true : false );
}
} else {
RETURN ( true );
}
%}.
^ super ~= aNumber
! !
!ShortFloat 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__
#ifdef SYSV
sprintf(buffer, "%.6lg", (double)__shortFloatVal(self));
#else
sprintf(buffer, "%.6G", (double)__shortFloatVal(self));
#endif
__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') || (*cp == 'E')) break;
}
if (! *cp) {
*cp++ = '.';
*cp++ = '0';
*cp = '\0';
}
s = __MKSTRING(buffer COMMA_SND);
if (s != nil) {
RETURN (s);
}
%}.
^ self asFloat printString
!
printfPrintString:formatString
"non-portable: return a printed representation of the receiver
as specified by formatString, which is defined by printf.
If you use this, be aware, that specifying doubles differs on
systems; on SYSV machines you have to give something like %lf,
while on BSD systems the format string has to be %F.
Also, the resulting string may not be longer than 255 bytes -
since thats the (static) size of the buffer.
This method is NONSTANDARD and may be removed without notice."
%{ /* STACK: 400 */
char buffer[256];
OBJ s;
if (__isString(formatString)) {
sprintf(buffer, __stringVal(formatString), __shortFloatVal(self));
s = __MKSTRING(buffer COMMA_SND);
if (s != nil) {
RETURN (s);
}
}
%}.
self primitiveFailed
"ShortFloat pi printfPrintString:'%%lg -> %lg'"
"ShortFloat pi printfPrintString:'%%lf -> %lf'"
"ShortFloat pi printfPrintString:'%%7.5lg -> %7.5lg'"
"ShortFloat pi printfPrintString:'%%G -> %G'"
"ShortFloat pi printfPrintString:'%%F -> %F'"
"ShortFloat pi printfPrintString:'%%7.5G -> %7.5G'"
"ShortFloat pi printfPrintString:'%%7.5F -> %7.5F'"
! !
!ShortFloat 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 */
double frexp();
INT exp;
__threadErrno = 0;
#if defined(i386) && defined(__GNUC__)
frexpf( __shortFloatVal(self), &exp);
#else
frexp( (double)(__shortFloatVal(self)), &exp);
#endif
if (__threadErrno == 0) {
RETURN (__MKSMALLINT(exp));
}
%}.
^ super exponent
"
4.0 asShortFloat exponent
2.0 asShortFloat exponent
1.0 asShortFloat exponent
0.5 asShortFloat exponent
0.25 asShortFloat exponent
0.00000011111 asShortFloat 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 */
INT exp;
#if defined(i386) && defined(__GNUC__)
float frac;
__threadErrno = 0;
frac = frexpf( (double)__shortFloatVal(self), &exp);
if (__threadErrno == 0) {
RETURN (__MKSFLOAT(frac));
}
#else
double frexp();
double frac;
__threadErrno = 0;
frac = frexp( (double)(__shortFloatVal(self)), &exp);
if (__threadErrno == 0) {
RETURN (__MKFLOAT(frac));
}
#endif
%}.
^ self primitiveFailed
"
1.0 asShortFloat exponent
1.0 asShortFloat mantissa
0.5 asShortFloat exponent
0.5 asShortFloat mantissa
0.25 asShortFloat exponent
0.25 asShortFloat mantissa
0.00000011111 asShortFloat exponent
0.00000011111 asShortFloat mantissa
"
! !
!ShortFloat methodsFor:'testing'!
isFinite
"return true, if the receiver is a finite float
i.e. not NaN and not infinite."
%{ /* NOCONTEXT */
#if defined(i386) && defined(__GNUC__)
if (finitef(__shortFloatVal(self))) { RETURN (true); }
#else
double dV = (double) __shortFloatVal(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); }
#endif
%}.
^false
"
1.0 asShortFloat isFinite
(0.0 asShortFloat uncheckedDivide: 0.0) isFinite
(1.0 asShortFloat 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 */
#if defined(i386) && defined(__GNUC__)
if (isnanf(__shortFloatVal(self))) { RETURN (true); }
#else
double dV = (double)(__shortFloatVal(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 */
#endif /* i386 */
%}.
^ false
"
1.0 asShortFloat isNaN
(0.0 asShortFloat uncheckedDivide: 0.0) isNaN
"
!
isNegativeZero
"many systems have two float.Pnt zeros"
%{
#if defined(i386) && defined(linux)
RETURN ((__ByteArrayInstPtr(self)->ba_element[sizeof(float)-1] == 128) ? true : false );
#endif
%}.
^ super isNegativeZero
"
0.0 asShortFloat isNegativeZero
-0.0 asShortFloat isNegativeZero
"
!
negative
"return true if the receiver is less than zero"
%{ /* NOCONTEXT */
RETURN ( (__shortFloatVal(self) < 0.0) ? true : false );
%}.
!
numberOfBits
"return the size (in bits) of the real;
typically, 32 is returned here,
but who knows ..."
%{ /* NOCONTEXT */
RETURN (__MKSMALLINT (sizeof(float) * 8));
%}
"
1.2 numberOfBits
1.2 asShortFloat numberOfBits
"
!
positive
"return true if the receiver is greater or equal to zero"
%{ /* NOCONTEXT */
RETURN ( (__shortFloatVal(self) >= 0.0) ? true : false );
%}
!
strictlyPositive
"return true if the receiver is greater than zero"
%{ /* NOCONTEXT */
RETURN ( (__shortFloatVal(self) > 0.0) ? true : false );
%}
! !
!ShortFloat methodsFor:'truncation & rounding'!
ceiling
"return the smallest integer which is greater or equal to the receiver."
|val|
%{
float fVal;
#if defined(i386) && defined(__GNUC__)
fVal = ceilf(__shortFloatVal(self));
#else
fVal = (float)(ceil((double)__shortFloatVal(self)));
#endif
/*
* ST-80 (and X3J20) returns integer.
*/
if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) {
RETURN ( __MKSMALLINT( (INT) fVal ) );
}
__qMKSFLOAT(val, fVal);
%}.
^ val asInteger
"
0.5 asShortFloat ceiling
-0.5 asShortFloat ceiling
"
!
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 */
float fVal;
OBJ v;
#if defined(i386) && defined(__GNUC__)
fVal = ceilf(__shortFloatVal(self));
#else
fVal = (float) ceil((double)__shortFloatVal(self));
#endif
__qMKSFLOAT(v, fVal);
RETURN (v);
%}
"
0.5 asShortFloat ceilingAsFloat
-0.5 asShortFloat ceilingAsFloat
-1.5 asShortFloat ceilingAsFloat
"
!
floor
"return the integer nearest the receiver towards negative infinity."
|val|
%{
float fVal;
#if defined(i386) && defined(__GNUC__)
fVal = floorf(__shortFloatVal(self));
#else
fVal = (float)(floor((double)__shortFloatVal(self)));
#endif
/*
* ST-80 (and X3J20) returns integer.
*/
if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) {
RETURN ( __MKSMALLINT( (INT) fVal ) );
}
__qMKSFLOAT(val, fVal);
%}.
^ val asInteger
"
0.5 asShortFloat floor
-0.5 asShortFloat floor
"
!
floorAsFloat
"return the float which represents the next lower
integer nearest the receiver towards negative infinity.
Much like floor, but returns a float result - useful if the result
will be used in another float operation, to avoid costy int-conversion."
%{ /* NOCONTEXT */
float fVal;
OBJ v;
#if defined(i386) && defined(__GNUC__)
fVal = floorf(__shortFloatVal(self));
#else
fVal = (float)(floor((double)__shortFloatVal(self)));
#endif
__qMKSFLOAT(v, fVal);
RETURN ( v );
%}
"
0.5 asShortFloat floorAsFloat
-0.5 asShortFloat floorAsFloat
"
!
fractionPart
"extract the after-decimal fraction part.
such that (self truncated + self fractionPart) = self"
%{ /* NOCONTEXT */
double modf();
double frac, trunc;
__threadErrno = 0;
frac = modf((double)(__shortFloatVal(self)), &trunc);
if (! isnan(frac)) {
if (__threadErrno == 0) {
RETURN (__MKSFLOAT((float)frac));
}
}
%}.
^ self class
raise:#domainErrorSignal
receiver:self
selector:#fractionPart
arguments:#()
errorString:'bad receiver in fractionPart'
"
1.6 asShortFloat fractionPart + 1.6 asShortFloat truncated
-1.6 asShortFloat fractionPart + -1.6 asShortFloat truncated
1.0 asShortFloat fractionalPart
0.5 asShortFloat fractionalPart
0.25 asShortFloat fractionalPart
3.14159 asShortFloat fractionalPart
12345673.14159 asShortFloat fractionalPart
123456731231231231.14159 asShortFloat fractionalPart
"
!
rounded
"return the receiver rounded to the nearest integer"
|val|
%{
float fVal;
fVal = __shortFloatVal(self);
#if defined(i386) && defined(__GNUC__)
if (fVal < 0.0) {
fVal = ceilf(fVal - (float)0.5);
} else {
fVal = floorf(fVal + (float)0.5);
}
#else
if (fVal < 0.0) {
fVal = (float)ceil((double)fVal - 0.5);
} else {
fVal = (float)floor((double)fVal + 0.5);
}
#endif
/*
* ST-80 (and X3J20) returns integer.
*/
if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) {
RETURN ( __MKSMALLINT( (INT) fVal ) );
}
__qMKSFLOAT(val, fVal);
%}.
^ val asInteger
"
0.4 asShortFloat rounded
0.5 asShortFloat rounded
0.6 asShortFloat rounded
-0.4 asShortFloat rounded
-0.5 asShortFloat rounded
-0.6 asShortFloat rounded
"
!
roundedAsFloat
"return the receiver rounded to the nearest integer as a float.
This is much like #rounded, 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 */
float fVal;
OBJ v;
fVal = __shortFloatVal(self);
#if defined(i386) && defined(__GNUC__)
if (fVal < 0.0) {
fVal = ceilf(fVal - (float)0.5);
} else {
fVal = floorf(fVal + (float)0.5);
}
#else
if (fVal < 0.0) {
fVal = (float)ceil((double)fVal - 0.5);
} else {
fVal = (float)floor((double)fVal + 0.5);
}
#endif
__qMKSFLOAT(v, fVal);
RETURN (v);
%}
"
0.4 asShortFloat rounded
0.5 asShortFloat rounded
0.6 asShortFloat rounded
-0.4 asShortFloat rounded
-0.5 asShortFloat rounded
-0.6 asShortFloat rounded
0.4 asShortFloat roundedAsFloat
0.5 asShortFloat roundedAsFloat
0.6 asShortFloat roundedAsFloat
-0.4 asShortFloat roundedAsFloat
-0.5 asShortFloat roundedAsFloat
-0.6 asShortFloat roundedAsFloat
"
!
truncated
"return the receiver truncated towards zero as an integer"
|val|
%{
float fVal;
fVal = __shortFloatVal(self);
#if defined(i386) && defined(__GNUC__)
if (fVal < 0.0) {
fVal = ceilf(fVal);
} else {
fVal = floorf(fVal);
}
#else
if (fVal < 0.0) {
fVal = (float)ceil((double)fVal);
} else {
fVal = (float)floor((double)fVal);
}
#endif
/*
* ST-80 (and X3J20) returns integer.
*/
if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) {
RETURN ( __MKSMALLINT( (INT) fVal ) );
}
__qMKSFLOAT(val, fVal);
%}.
^ val asInteger
"
0.5 asShortFloat truncated
-0.5 asShortFloat truncated
0.5 asShortFloat truncatedAsFloat
-0.5 asShortFloat truncatedAsFloat
"
!
truncatedAsFloat
"return the receiver truncated towards zero as a float.
This is much like #truncated, 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 */
float fVal;
OBJ v;
fVal = __shortFloatVal(self);
#if defined(i386) && defined(__GNUC__)
if (fVal < 0.0) {
fVal = ceilf(fVal);
} else {
fVal = floorf(fVal);
}
#else
if (fVal < 0.0) {
fVal = (float)ceil((double)fVal);
} else {
fVal = (float)floor((double)fVal);
}
#endif
__qMKSFLOAT(v, fVal);
RETURN (v);
%}
"
0.5 asShortFloat truncated
-0.5 asShortFloat truncated
0.5 asShortFloat truncatedAsFloat
-0.5 asShortFloat truncatedAsFloat
"
! !
!ShortFloat class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libbasic/ShortFloat.st,v 1.75 2003-06-17 14:11:23 cg Exp $'
! !