--- 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 $'
! !