ShortFloat.st
branchjv
changeset 18017 7fef9e17913f
parent 18011 deb0c3355881
parent 14719 a354c1ef4a56
child 18022 f23232c2eaef
--- a/ShortFloat.st	Wed Jan 23 10:08:55 2013 +0000
+++ b/ShortFloat.st	Mon Jan 28 21:53:19 2013 +0000
@@ -38,6 +38,10 @@
  extern errno;
 #endif
 
+#if !defined (WIN32)
+# include <locale.h>
+#endif
+
 #if defined (_AIX)
 # include <float.h>
 #endif
@@ -167,7 +171,10 @@
     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.
+    ST-80's Floats respectively. The reason was to make ST/X's floats compatible
+    to bothe visualWorks and other smalltalks, which use C-doubles for the Float class.
+    Thus, STX's Float precision is not worse than that of other ST's.
+
     This may change in one of the next versions (at least on machines, which
     provide different float and double types in their C-compiler.
 
@@ -237,15 +244,15 @@
 
 %{   /* NOCONTEXT */
      if (__isStringLike(aString) && __isSmallInteger(startIndex)) {
-        char *cp = (char *)(__stringVal(aString));
-        int idx = __intVal(startIndex) - 1;
-        double atof();
-        double val;
+	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));
-        }
+	if ((unsigned)idx < __stringSize(aString)) {
+	    val = atof(cp + idx);
+	    RETURN (__MKSFLOAT(val));
+	}
      }
 %}.
      self primitiveFailed.
@@ -265,17 +272,17 @@
      ShortFloat fastFromString:'hello123.45E4' at:1
 
      Time millisecondsToRun:[
-        100000 timesRepeat:[
-            ShortFloat readFrom:'123.45'
-        ]
+	100000 timesRepeat:[
+	    ShortFloat readFrom:'123.45'
+	]
      ]
     "
 
     "
      Time millisecondsToRun:[
-        100000 timesRepeat:[
-            ShortFloat fastFromString:'123.45' at:1
-        ]
+	100000 timesRepeat:[
+	    ShortFloat fastFromString:'123.45' at:1
+	]
      ]
     "
 !
@@ -362,14 +369,14 @@
     self isIEEEFormat ifFalse:[self error:'unsupported operation'].
 
     UninterpretedBytes isBigEndian ifFalse:[
-        "swap the bytes"
-        4 to:1 by:-1 do:[:i |
-            aFloat basicAt:i put:(aStream next)
-        ].
-        ^ self
+	"swap the bytes"
+	4 to:1 by:-1 do:[:i |
+	    aFloat basicAt:i put:(aStream next)
+	].
+	^ self
     ].
     1 to:4 do:[:i |
-        aFloat basicAt:i put:aStream next
+	aFloat basicAt:i put:aStream next
     ]
 
     "not part of libboss, as this is also used by others (TIFFReader)"
@@ -393,14 +400,14 @@
     self isIEEEFormat ifFalse:[self error:'unsupported operation'].
 
     UninterpretedBytes isBigEndian ifFalse:[
-        "swap the bytes"
-        4 to:1 by:-1 do:[:i |
-            aStream nextPut:(float basicAt:i).
-        ].
-        ^ self
+	"swap the bytes"
+	4 to:1 by:-1 do:[:i |
+	    aStream nextPut:(float basicAt:i).
+	].
+	^ self
     ].
     1 to:4 do:[:i |
-        aStream nextPut:(float basicAt:i).
+	aStream nextPut:(float basicAt:i).
     ]
 
     "not part of libboss, as this is also used by others (TIFFReader)"
@@ -438,6 +445,11 @@
     "Modified: 23.4.1996 / 09:26:45 / cg"
 ! !
 
+!ShortFloat class methodsFor:'odbc queries'!
+
+odbcTypeSymbol
+    ^ #'SQL_FLOAT'
+! !
 
 !ShortFloat class methodsFor:'queries'!
 
@@ -664,6 +676,60 @@
 
 !
 
+rem: aNumber
+    "return the floating point remainder of the receiver and the argument, aNumber"
+
+%{  /* NOCONTEXT */
+
+    /*
+     * notice:
+     * the following inline code handles some common cases,
+     * and exists as an optimization, to speed up those cases.
+     *
+     * Conceptionally, (and for most other argument types),
+     * mixed arithmetic is implemented by double dispatching
+     * (see the message send at the bottom)
+     */
+    OBJ newFloat;
+    float result, val;
+    double dResult, dVal;
+
+    if (__isSmallInteger(aNumber)) {
+	if (aNumber != __mkSmallInteger(0)) {
+	    val = (float)__intVal(aNumber);
+computeResult:
+#ifdef NO_FMODF
+	    dResult = fmod((double)__shortFloatVal(self), (double)val) ;
+	    result = (float)dResult;
+#else
+	    result = fmodf(__shortFloatVal(self), val) ;
+#endif
+	    __qMKSFLOAT(newFloat, result);
+	    RETURN ( newFloat );
+	}
+    } else if (__isFloatLike(aNumber)) {
+	dVal = __floatVal(aNumber);
+	if (dVal != 0.0) {
+	    dResult = fmod((double)(__shortFloatVal(self)), dVal) ;
+	    __qMKFLOAT(newFloat, dResult);
+	    RETURN ( newFloat );
+	}
+    } else if (__isShortFloat(aNumber)) {
+	val = __shortFloatVal(aNumber);
+	if (val != 0.0) {
+	    goto computeResult;
+	}
+    }
+%}.
+    ((aNumber == 0) or:[aNumber = 0.0]) ifTrue:[
+	"
+	 No, you shalt not divide by zero
+	"
+	^ ZeroDivide raiseRequestWith:thisContext.
+    ].
+    ^ aNumber remainderFromShortFloat:self
+!
+
 uncheckedDivide:aNumber
     "return the quotient of the receiver and the argument, aNumber.
      Do not check for divide by zero (return NaN or Infinity).
@@ -945,23 +1011,23 @@
     OBJ newFloat;
 
     if (sizeof(float) == 4) {
-        x = __shortFloatVal(self);
-        {
-            float xhalf = 0.5f * x;
-            int i = *(int*)&x; // store floating-point bits in integer
+	x = __shortFloatVal(self);
+	{
+	    float xhalf = 0.5f * x;
+	    int i = *(int*)&x; // store floating-point bits in integer
 
-            i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method
-            x = *(float*)&i; // convert new bits into float
-            x = x*(1.5f - xhalf*x*x); // One round of Newton's method
-            __qMKSFLOAT(newFloat, x);
-            RETURN ( newFloat );
-        }
+	    i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method
+	    x = *(float*)&i; // convert new bits into float
+	    x = x*(1.5f - xhalf*x*x); // One round of Newton's method
+	    __qMKSFLOAT(newFloat, x);
+	    RETURN ( newFloat );
+	}
     }
 %}.
     ^ 1 / self sqrt
 
     "
-     10.0 asShortFloat fastInverseSqrt   
+     10.0 asShortFloat fastInverseSqrt
      (1 / 10.0 asShortFloat sqrt)
     "
 
@@ -970,18 +1036,18 @@
 
      a := 345 asShortFloat.
      t0 := Time millisecondsToRun:[
-        1000000 timesRepeat:[
-        ]
+	1000000 timesRepeat:[
+	]
      ].
      t1 := Time millisecondsToRun:[
-        1000000 timesRepeat:[
-            a fastInverseSqrt
-        ]
+	1000000 timesRepeat:[
+	    a fastInverseSqrt
+	]
      ].
      t2 := Time millisecondsToRun:[
-        1000000 timesRepeat:[
-            (1 / a sqrt)
-        ]
+	1000000 timesRepeat:[
+	    (1 / a sqrt)
+	]
      ].
      Transcript show:'empty: '; showCR:t0.
      Transcript show:'fast: '; showCR:t1.
@@ -1013,56 +1079,56 @@
     __END_PROTECT_REGISTERS__
 
     if (len >= 0 && len <= sizeof(buffer)-3) {
-        /*
-         * 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 == ',') || (*cp == 'E') || (*cp == 'e')) break;
-        }
-        if (!*cp && (cp[-1] >= '0') && (cp[-1] <= '9')) {
-            if (__isCharacter(@global(DecimalPointCharacterForPrinting))) {
-                *cp++ = __intVal(__characterVal(@global(DecimalPointCharacterForPrinting)));
-            } else {
-                *cp++ = '.';
-            }
-            *cp++ = '0';
-            *cp = '\0';
-        } else {
-            if (cp && (*cp == '.')) {
-                if (__isCharacter(@global(DecimalPointCharacterForPrinting))) {
-                    *cp = __intVal(__characterVal(@global(DecimalPointCharacterForPrinting)));
-                }
-            }
-        }
+	/*
+	 * 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 == ',') || (*cp == 'E') || (*cp == 'e')) break;
+	}
+	if (!*cp && (cp[-1] >= '0') && (cp[-1] <= '9')) {
+	    if (__isCharacter(@global(DecimalPointCharacterForPrinting))) {
+		*cp++ = __intVal(__characterVal(@global(DecimalPointCharacterForPrinting)));
+	    } else {
+		*cp++ = '.';
+	    }
+	    *cp++ = '0';
+	    *cp = '\0';
+	} else {
+	    if (cp && (*cp == '.')) {
+		if (__isCharacter(@global(DecimalPointCharacterForPrinting))) {
+		    *cp = __intVal(__characterVal(@global(DecimalPointCharacterForPrinting)));
+		}
+	    }
+	}
 
-        s = __MKSTRING(buffer);
-        if (s != nil) {
-            RETURN (s);
-        }
+	s = __MKSTRING(buffer);
+	if (s != nil) {
+	    RETURN (s);
+	}
     }
 %}.
     ^ self asFloat printString
 
     "
-        1.234 asShortFloat printString.
-        1.0 asShortFloat printString.
-        1e10 asShortFloat printString.
-        1.2e3 asShortFloat printString.
-        1.2e30 asShortFloat printString.
-        (1.0 uncheckedDivide:0) asShortFloat printString.
-        (0.0 uncheckedDivide:0) asShortFloat printString.
-        self pi printString.
+	1.234 asShortFloat printString.
+	1.0 asShortFloat printString.
+	1e10 asShortFloat printString.
+	1.2e3 asShortFloat printString.
+	1.2e30 asShortFloat printString.
+	(1.0 uncheckedDivide:0) asShortFloat printString.
+	(0.0 uncheckedDivide:0) asShortFloat printString.
+	self pi printString.
 
-        DecimalPointCharacterForPrinting := $,.
-        1.234 asShortFloat printString.
-        1.0 asShortFloat printString.
-        1e10 asShortFloat printString.
-        1.2e3 asShortFloat printString.
-        1.2e30 asShortFloat printString.
-        (1.0 uncheckedDivide:0) asShortFloat printString.
-        (0.0 uncheckedDivide:0) asShortFloat printString.
-        DecimalPointCharacterForPrinting := $.
+	DecimalPointCharacterForPrinting := $,.
+	1.234 asShortFloat printString.
+	1.0 asShortFloat printString.
+	1e10 asShortFloat printString.
+	1.2e3 asShortFloat printString.
+	1.2e30 asShortFloat printString.
+	(1.0 uncheckedDivide:0) asShortFloat printString.
+	(0.0 uncheckedDivide:0) asShortFloat printString.
+	DecimalPointCharacterForPrinting := $.
     "
 !
 
@@ -1084,23 +1150,23 @@
     int len;
 
     if (__isStringLike(formatString)) {
-        /*
-         * 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__
+	/*
+	 * 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__
 
-        len = snprintf(buffer, sizeof(buffer), __stringVal(formatString), __shortFloatVal(self));
+	len = snprintf(buffer, sizeof(buffer), __stringVal(formatString), __shortFloatVal(self));
 
-        __END_PROTECT_REGISTERS__
+	__END_PROTECT_REGISTERS__
 
-        if (len < 0) goto fail;
+	if (len < 0) goto fail;
 
-        s = __MKSTRING_L(buffer, len);
-        if (s != nil) {
-            RETURN (s);
-        }
+	s = __MKSTRING_L(buffer, len);
+	if (s != nil) {
+	    RETURN (s);
+	}
     }
 fail: ;
 %}.
@@ -1141,23 +1207,23 @@
     __END_PROTECT_REGISTERS__
 
     if (len >= 0 && len < sizeof(buffer)-3) {
-        /*
-         * 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 == ',') || (*cp == 'E') || (*cp == 'e')) break;
-        }
-        if (!*cp && (cp[-1] >= '0') && (cp[-1] <= '9')) {
-            *cp++ = '.';
-            *cp++ = '0';
-            *cp = '\0';
-        }
+	/*
+	 * 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 == ',') || (*cp == 'E') || (*cp == 'e')) break;
+	}
+	if (!*cp && (cp[-1] >= '0') && (cp[-1] <= '9')) {
+	    *cp++ = '.';
+	    *cp++ = '0';
+	    *cp = '\0';
+	}
 
-        s = __MKSTRING(buffer);
-        if (s != nil) {
-            RETURN (s);
-        }
+	s = __MKSTRING(buffer);
+	if (s != nil) {
+	    RETURN (s);
+	}
     }
 %}.
     "
@@ -1170,26 +1236,26 @@
     ^ ObjectMemory allocationFailureSignal raise.
 
     "
-        1.0 asShortFloat storeString
-        1.234 asShortFloat storeString
-        1e10 asShortFloat storeString
-        1.2e3 asShortFloat storeString
-        1.2e30 asShortFloat storeString
-        Float pi asShortFloat storeString
-        (1.0 uncheckedDivide:0) asShortFloat storeString
-        (0.0 uncheckedDivide:0) asShortFloat storeString
+	1.0 asShortFloat storeString
+	1.234 asShortFloat storeString
+	1e10 asShortFloat storeString
+	1.2e3 asShortFloat storeString
+	1.2e30 asShortFloat storeString
+	Float pi asShortFloat storeString
+	(1.0 uncheckedDivide:0) asShortFloat storeString
+	(0.0 uncheckedDivide:0) asShortFloat storeString
 
      notice that the storeString is NOT affected by DecimalPointCharacterForPrinting:
 
-        DecimalPointCharacterForPrinting := $,.
-        1.234 asShortFloat storeString.
-        1.0 asShortFloat storeString.
-        1e10 asShortFloat storeString.
-        1.2e3 asShortFloat storeString.
-        1.2e30 asShortFloat storeString.
-        (1.0 uncheckedDivide:0) asShortFloat storeString.
-        (0.0 uncheckedDivide:0) asShortFloat storeString.
-        DecimalPointCharacterForPrinting := $.
+	DecimalPointCharacterForPrinting := $,.
+	1.234 asShortFloat storeString.
+	1.0 asShortFloat storeString.
+	1e10 asShortFloat storeString.
+	1.2e3 asShortFloat storeString.
+	1.2e30 asShortFloat storeString.
+	(1.0 uncheckedDivide:0) asShortFloat storeString.
+	(0.0 uncheckedDivide:0) asShortFloat storeString.
+	DecimalPointCharacterForPrinting := $.
     "
 ! !
 
@@ -1201,12 +1267,12 @@
      Therefore, this method should be used strictly private.
 
      Notice:
-        the need to redefine this method here is due to the
-        inability of many machines to store floats in non-double aligned memory.
-        Therefore, on some machines, the first 4 bytes of a float are left unused,
-        and the actual float is stored at index 5 .. 12.
-        To hide this at one place, this method knows about that, and returns
-        values as if this filler wasnt present."
+	the need to redefine this method here is due to the
+	inability of many machines to store floats in non-double aligned memory.
+	Therefore, on some machines, the first 4 bytes of a float are left unused,
+	and the actual float is stored at index 5 .. 12.
+	To hide this at one place, this method knows about that, and returns
+	values as if this filler wasnt present."
 
 %{  /* NOCONTEXT */
 
@@ -1219,11 +1285,11 @@
      * and SmallInteger
      */
     if (__isSmallInteger(index)) {
-        indx = __intVal(index) - 1;
-        if (((unsigned)(indx)) < sizeof(float)) {
-            cp = (unsigned char *)(& (__ShortFloatInstPtr(self)->f_floatvalue));
-            RETURN ( __mkSmallInteger(cp[indx] & 0xFF) );
-        }
+	indx = __intVal(index) - 1;
+	if (((unsigned)(indx)) < sizeof(float)) {
+	    cp = (unsigned char *)(& (__ShortFloatInstPtr(self)->f_floatvalue));
+	    RETURN ( __mkSmallInteger(cp[indx] & 0xFF) );
+	}
     }
 %}.
     ^ self indexNotIntegerOrOutOfBounds:index
@@ -1235,12 +1301,12 @@
      Therefore, this method should be used strictly private.
 
      Notice:
-        the need to redefine this method here is due to the
-        inability of many machines to store floats in non-double aligned memory.
-        Therefore, on some machines, the first 4 bytes of a float are left unused,
-        and the actual float is stored at index 5 .. 12.
-        To hide this at one place, this method knows about that, and returns
-        values as if this filler wasnt present."
+	the need to redefine this method here is due to the
+	inability of many machines to store floats in non-double aligned memory.
+	Therefore, on some machines, the first 4 bytes of a float are left unused,
+	and the actual float is stored at index 5 .. 12.
+	To hide this at one place, this method knows about that, and returns
+	values as if this filler wasnt present."
 
 %{  /* NOCONTEXT */
     register int indx, val;
@@ -1252,28 +1318,28 @@
      * and SmallInteger
      */
     if (__bothSmallInteger(index, value)) {
-        val = __intVal(value);
-        if ((val & ~0xFF) == 0 /* i.e. (val >= 0) && (val <= 255) */) {
-            indx = __intVal(index) - 1;
-            if (((unsigned)(indx)) < sizeof(float)) {
-                cp = (unsigned char *)(& (__ShortFloatInstPtr(self)->f_floatvalue));
-                cp[indx] = val;
-                RETURN ( value );
-            }
-        }
+	val = __intVal(value);
+	if ((val & ~0xFF) == 0 /* i.e. (val >= 0) && (val <= 255) */) {
+	    indx = __intVal(index) - 1;
+	    if (((unsigned)(indx)) < sizeof(float)) {
+		cp = (unsigned char *)(& (__ShortFloatInstPtr(self)->f_floatvalue));
+		cp[indx] = val;
+		RETURN ( value );
+	    }
+	}
     }
 %}.
     value isInteger ifFalse:[
-        "
-         the object to store should be an integer number
-        "
-        ^ self elementNotInteger
+	"
+	 the object to store should be an integer number
+	"
+	^ self elementNotInteger
     ].
     (value between:0 and:255) ifFalse:[
-        "
-         the object to store must be a bytes value
-        "
-        ^ self elementBoundsError:value
+	"
+	 the object to store must be a bytes value
+	"
+	^ self elementBoundsError:value
     ].
     ^ self indexNotIntegerOrOutOfBounds:index
 ! !
@@ -1587,14 +1653,14 @@
 
 %{  /* NOCONTEXT */
 
-    double modf();
-    double frac, trunc;
+    float modff(float, float*);
+    float frac, trunc;
 
     __threadErrno = 0;
-    frac = modf((double)(__shortFloatVal(self)), &trunc);
+    frac = modff(__shortFloatVal(self), &trunc);
     if (! isnan(frac)) {
 	if (__threadErrno == 0) {
-	    RETURN (__MKSFLOAT((float)frac));
+	    RETURN (__MKSFLOAT(frac));
 	}
     }
 %}.
@@ -1609,12 +1675,12 @@
      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
+     1.0 asShortFloat fractionPart
+     0.5 asShortFloat fractionPart
+     0.25 asShortFloat fractionPart
+     3.14159 asShortFloat fractionPart
+     12345673.14159 asShortFloat fractionPart
+     123456731231231231.14159 asShortFloat fractionPart
     "
 !
 
@@ -1785,10 +1851,10 @@
 !ShortFloat class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/ShortFloat.st,v 1.109 2012-12-17 18:28:33 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/ShortFloat.st,v 1.115 2013-01-26 15:03:23 cg Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/ShortFloat.st,v 1.109 2012-12-17 18:28:33 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/ShortFloat.st,v 1.115 2013-01-26 15:03:23 cg Exp $'
 ! !