201 to bothe VisualWorks and other Smalltalks, which use C-doubles for the Float class |
201 to bothe VisualWorks and other Smalltalks, which use C-doubles for the Float class |
202 (i.e. VisualST and V'Age). |
202 (i.e. VisualST and V'Age). |
203 Thus, STX's Float precision is not worse than that of other ST's. |
203 Thus, STX's Float precision is not worse than that of other ST's. |
204 |
204 |
205 WARNING: |
205 WARNING: |
206 The layout of shortFloat instances is known by the runtime system and the compiler; |
206 The layout of shortFloat instances is known by the runtime system and the compiler; |
207 you may not add instance variables here. |
207 you may not add instance variables here. |
208 Also, subclassing is complicated by the fact, that the VM creates floats/shortFloats, |
208 Also, subclassing is complicated by the fact, that the VM creates floats/shortFloats, |
209 and does some of its float-checks by an identity compare with the ShortFloat-class. |
209 and does some of its float-checks by an identity compare with the ShortFloat-class. |
210 (i.e. your subclasses instances may not be recognized as float-like objects, |
210 (i.e. your subclasses instances may not be recognized as float-like objects, |
211 thus mixed mode arithmetic will always coerce them, effectively slowing things down). |
211 thus mixed mode arithmetic will always coerce them, effectively slowing things down). |
212 This may be changed, to use a flag bit in the class. |
212 This may be changed, to use a flag bit in the class. |
213 |
213 |
214 Mixed mode arithmetic: |
214 Mixed mode arithmetic: |
215 shortFloat op shortFloat -> shortFloat |
215 shortFloat op shortFloat -> shortFloat |
216 shortFloat op fix -> shortFloat |
216 shortFloat op fix -> shortFloat |
217 shortFloat op fraction -> shortFloat |
217 shortFloat op fraction -> shortFloat |
218 shortFloat op integer -> shortFloat |
218 shortFloat op integer -> shortFloat |
219 shortFloat op longFloat -> longFloat |
219 shortFloat op longFloat -> longFloat |
220 shortFloat op float -> float |
220 shortFloat op float -> float |
221 shortFloat op complex -> complex |
221 shortFloat op complex -> complex |
222 |
222 |
223 Representation: |
223 Representation: |
224 32bit single precision IEEE floats |
224 32bit single precision IEEE floats |
225 23 bit mantissa + 1 hidden bit, providing a precision of 24bits, |
225 23 bit mantissa + 1 hidden bit, providing a precision of 24bits, |
226 8 bit exponent, |
226 8 bit exponent, |
227 6 decimal digits (approx.) |
227 6 decimal digits (approx.) |
228 |
228 |
229 Range and Precision of Storage Formats: see LimitedPrecisionReal >> documentation |
229 Range and Precision of Storage Formats: see LimitedPrecisionReal >> documentation |
230 |
230 |
231 [author:] |
231 [author:] |
232 Claus Gittinger |
232 Claus Gittinger |
233 |
233 |
234 [see also:] |
234 [see also:] |
235 Number |
235 Number |
236 Float LongFloat Fraction FixedPoint Integer Complex |
236 Float LongFloat Fraction FixedPoint Integer Complex |
237 FloatArray DoubleArray |
237 FloatArray DoubleArray |
238 " |
238 " |
239 ! ! |
239 ! ! |
240 |
240 |
241 !ShortFloat class methodsFor:'instance creation'! |
241 !ShortFloat class methodsFor:'instance creation'! |
242 |
242 |
262 No spaces are skipped. |
262 No spaces are skipped. |
263 Raises an exception, if the startIndex is not valid. |
263 Raises an exception, if the startIndex is not valid. |
264 Returns garbage if the argument string is not a valid float number. |
264 Returns garbage if the argument string is not a valid float number. |
265 |
265 |
266 This is a specially tuned entry (using a low-level C-call to atof). |
266 This is a specially tuned entry (using a low-level C-call to atof). |
267 It has been added to allow high speed string decomposition |
267 It has been added to allow high speed string decomposition |
268 into numbers, especially for mass-data (reading millions of floats)." |
268 into numbers, especially for mass-data (reading millions of floats)." |
269 |
269 |
270 %{ /* NOCONTEXT */ |
270 %{ /* NOCONTEXT */ |
271 if (__isStringLike(aString) && __isSmallInteger(startIndex)) { |
271 if (__isStringLike(aString) && __isSmallInteger(startIndex)) { |
272 char *cp = (char *)(__stringVal(aString)); |
272 char *cp = (char *)(__stringVal(aString)); |
273 int idx = __intVal(startIndex) - 1; |
273 int idx = __intVal(startIndex) - 1; |
274 |
274 |
275 if ((unsigned)idx < __stringSize(aString)) { |
275 if ((unsigned)idx < __stringSize(aString)) { |
276 #ifndef NO_STRTOF |
276 #ifndef NO_STRTOF |
277 float strtof(const char *, char**); |
277 float strtof(const char *, char**); |
278 float val = strtof(cp+idx, NULL); |
278 float val = strtof(cp+idx, NULL); |
279 #else |
279 #else |
280 double atof(const char *); |
280 # ifndef NO_STRTOD |
281 double val = atof(cp + idx); |
281 double strtod(const char *, char**); |
282 #endif |
282 double val = strtod(cp+idx, NULL); |
283 RETURN (__MKSFLOAT(val)); |
283 # else |
284 } |
284 double atof(const char *); |
|
285 double val = atof(cp + idx); |
|
286 # endif |
|
287 #endif |
|
288 RETURN (__MKSFLOAT(val)); |
|
289 } |
285 } |
290 } |
286 %}. |
291 %}. |
287 self primitiveFailed. |
292 self primitiveFailed. |
288 |
293 |
289 " |
294 " |
1226 * (see the message send at the bottom) |
1231 * (see the message send at the bottom) |
1227 */ |
1232 */ |
1228 |
1233 |
1229 INT32 ulpDiff; |
1234 INT32 ulpDiff; |
1230 union { |
1235 union { |
1231 float f; |
1236 float f; |
1232 INT32 i; |
1237 INT32 i; |
1233 } myself, otherFloat; |
1238 } myself, otherFloat; |
1234 int nEpsilon; |
1239 int nEpsilon; |
1235 float scaledEpsilon; |
1240 float scaledEpsilon; |
1236 |
1241 |
1237 if (!__isSmallInteger(nE)) { |
1242 if (!__isSmallInteger(nE)) { |
1238 goto tryHarder; |
1243 goto tryHarder; |
1239 } |
1244 } |
1240 |
1245 |
1241 nEpsilon = __intVal(nE); |
1246 nEpsilon = __intVal(nE); |
1242 scaledEpsilon = nEpsilon *__shortFloatVal(@global(Epsilon)); |
1247 scaledEpsilon = nEpsilon *__shortFloatVal(@global(Epsilon)); |
1243 |
1248 |
1244 if (__isSmallInteger(aNumber)) { |
1249 if (__isSmallInteger(aNumber)) { |
1245 otherFloat.f = (float)(__intVal(aNumber)); |
1250 otherFloat.f = (float)(__intVal(aNumber)); |
1246 } else if (aNumber == nil) { |
1251 } else if (aNumber == nil) { |
1247 RETURN(false) |
1252 RETURN(false) |
1248 } else if (__qIsFloatLike(aNumber)) { |
1253 } else if (__qIsFloatLike(aNumber)) { |
1249 otherFloat.f = (float)(__floatVal(aNumber)); |
1254 otherFloat.f = (float)(__floatVal(aNumber)); |
1250 } else if (__qIsShortFloat(aNumber)) { |
1255 } else if (__qIsShortFloat(aNumber)) { |
1251 otherFloat.f = __shortFloatVal(aNumber); |
1256 otherFloat.f = __shortFloatVal(aNumber); |
1252 // } else if (__qIsLongFloat(aNumber)) { |
1257 // } else if (__qIsLongFloat(aNumber)) { |
1253 // otherFloat.f = (float)(__longFloatVal(aNumber)); |
1258 // otherFloat.f = (float)(__longFloatVal(aNumber)); |
1254 } else { |
1259 } else { |
1255 goto tryHarder; |
1260 goto tryHarder; |
1256 } |
1261 } |
1257 |
1262 |
1258 myself.f = __shortFloatVal(self); |
1263 myself.f = __shortFloatVal(self); |
1259 |
1264 |
1260 // Check if the numbers are really close -- needed |
1265 // Check if the numbers are really close -- needed |
1261 // when comparing numbers near zero (ULP method below fails for numbers near 0!). |
1266 // when comparing numbers near zero (ULP method below fails for numbers near 0!). |
1262 # ifdef NO_ABSF |
1267 # ifdef NO_ABSF |
1263 if (fabs((double)(myself.f - otherFloat.f)) <= scaledEpsilon) { |
1268 if (fabs((double)(myself.f - otherFloat.f)) <= scaledEpsilon) { |
1264 RETURN(true); |
1269 RETURN(true); |
1265 } |
1270 } |
1266 # else |
1271 # else |
1267 // fprintf(stderr, "%.10f %.10f\n", fabsf(myself.f - otherFloat.f), scaledEpsilon); |
1272 // fprintf(stderr, "%.10f %.10f\n", fabsf(myself.f - otherFloat.f), scaledEpsilon); |
1268 if (fabsf(myself.f - otherFloat.f) <= scaledEpsilon) { |
1273 if (fabsf(myself.f - otherFloat.f) <= scaledEpsilon) { |
1269 RETURN(true); |
1274 RETURN(true); |
1270 } |
1275 } |
1271 #endif |
1276 #endif |
1272 |
1277 |
1273 // if the signs differ, the numbers are different |
1278 // if the signs differ, the numbers are different |
1274 if ((myself.f >= 0) != (otherFloat.f >= 0)) { |
1279 if ((myself.f >= 0) != (otherFloat.f >= 0)) { |
1275 RETURN(false); |
1280 RETURN(false); |
1276 } |
1281 } |
1277 |
1282 |
1278 // compute the difference of the 'units in the last place" ULP |
1283 // compute the difference of the 'units in the last place" ULP |
1279 // (if ulpDiff == 1, two floats are adjecant) |
1284 // (if ulpDiff == 1, two floats are adjecant) |
1280 ulpDiff = myself.i - otherFloat.i; |
1285 ulpDiff = myself.i - otherFloat.i; |
1281 if (ulpDiff < 0) ulpDiff = -ulpDiff; |
1286 if (ulpDiff < 0) ulpDiff = -ulpDiff; |
1282 if (ulpDiff <= nEpsilon) { |
1287 if (ulpDiff <= nEpsilon) { |
1283 RETURN(true); |
1288 RETURN(true); |
1284 } else { |
1289 } else { |
1285 RETURN(false) |
1290 RETURN(false) |
1286 } |
1291 } |
1287 |
1292 |
1288 tryHarder:; |
1293 tryHarder:; |
1289 %}. |
1294 %}. |
1290 ^ aNumber isAlmostEqualToFromShortFloat:self nEpsilon:nE |
1295 ^ aNumber isAlmostEqualToFromShortFloat:self nEpsilon:nE |
1291 |
1296 |
1292 " |
1297 " |
1293 67329.234 asShortFloat isAlmostEqualTo:67329.23401 asShortFloat nEpsilon:1 |
1298 67329.234 asShortFloat isAlmostEqualTo:67329.23401 asShortFloat nEpsilon:1 |
1294 1.0 asShortFloat isAlmostEqualTo:1.0000001 asShortFloat nEpsilon:1 |
1299 1.0 asShortFloat isAlmostEqualTo:1.0000001 asShortFloat nEpsilon:1 |
1295 1.0 asShortFloat isAlmostEqualTo:1.0000001 nEpsilon:1 |
1300 1.0 asShortFloat isAlmostEqualTo:1.0000001 nEpsilon:1 |
1296 1.0 asShortFloat isAlmostEqualTo:-1.0 nEpsilon:1 |
1301 1.0 asShortFloat isAlmostEqualTo:-1.0 nEpsilon:1 |
1297 1.0 asShortFloat isAlmostEqualTo:1 nEpsilon:1 |
1302 1.0 asShortFloat isAlmostEqualTo:1 nEpsilon:1 |
1298 0.0 asShortFloat isAlmostEqualTo:0.0000001 asShortFloat nEpsilon:1 |
1303 0.0 asShortFloat isAlmostEqualTo:0.0000001 asShortFloat nEpsilon:1 |
1299 0.0 asShortFloat isAlmostEqualTo:0.000001 asShortFloat nEpsilon:1 |
1304 0.0 asShortFloat isAlmostEqualTo:0.000001 asShortFloat nEpsilon:1 |
1300 0.0 asShortFloat isAlmostEqualTo:self epsilon nEpsilon:1 |
1305 0.0 asShortFloat isAlmostEqualTo:self epsilon nEpsilon:1 |
1301 0.0 asShortFloat - 1.192093e-07 asShortFloat |
1306 0.0 asShortFloat - 1.192093e-07 asShortFloat |
1302 " |
1307 " |
1303 |
1308 |
1304 "Modified: / 10-05-2018 / 00:47:22 / stefan" |
1309 "Modified: / 10-05-2018 / 00:47:22 / stefan" |
1305 ! |
1310 ! |
1306 |
1311 |
1712 char buffer[256]; |
1717 char buffer[256]; |
1713 OBJ s; |
1718 OBJ s; |
1714 int len; |
1719 int len; |
1715 |
1720 |
1716 if (__isStringLike(formatString)) { |
1721 if (__isStringLike(formatString)) { |
1717 /* |
1722 /* |
1718 * actually only needed on sparc: since thisContext is |
1723 * actually only needed on sparc: since thisContext is |
1719 * in a global register, which gets destroyed by printf, |
1724 * in a global register, which gets destroyed by printf, |
1720 * manually save it here - very stupid ... |
1725 * manually save it here - very stupid ... |
1721 */ |
1726 */ |
1722 __BEGIN_PROTECT_REGISTERS__ |
1727 __BEGIN_PROTECT_REGISTERS__ |
1723 |
1728 |
1724 len = snprintf(buffer, sizeof(buffer), __stringVal(formatString), __shortFloatVal(self)); |
1729 len = snprintf(buffer, sizeof(buffer), __stringVal(formatString), __shortFloatVal(self)); |
1725 |
1730 |
1726 __END_PROTECT_REGISTERS__ |
1731 __END_PROTECT_REGISTERS__ |
1727 |
1732 |
1728 if (len < 0) goto fail; |
1733 if (len < 0) goto fail; |
1729 if (len >= sizeof(buffer)) goto fail; |
1734 if (len >= sizeof(buffer)) goto fail; |
1730 |
1735 |
1731 s = __MKSTRING_L(buffer, len); |
1736 s = __MKSTRING_L(buffer, len); |
1732 if (s != nil) { |
1737 if (s != nil) { |
1733 RETURN (s); |
1738 RETURN (s); |
1734 } |
1739 } |
1735 } |
1740 } |
1736 fail: ; |
1741 fail: ; |
1737 #endif /* not __SCHTEAM__ */ |
1742 #endif /* not __SCHTEAM__ */ |
1738 %}. |
1743 %}. |
1739 ^ super printfPrintString:formatString |
1744 ^ super printfPrintString:formatString |
2356 float fVal; |
2361 float fVal; |
2357 |
2362 |
2358 fVal = __shortFloatVal(self); |
2363 fVal = __shortFloatVal(self); |
2359 #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) |
2364 #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) |
2360 if (fVal < 0.0) { |
2365 if (fVal < 0.0) { |
2361 fVal = ceilf(fVal - (float)0.5); |
2366 fVal = ceilf(fVal - (float)0.5); |
2362 } else { |
2367 } else { |
2363 fVal = floorf(fVal + (float)0.5); |
2368 fVal = floorf(fVal + (float)0.5); |
2364 } |
2369 } |
2365 #else |
2370 #else |
2366 if (fVal < 0.0) { |
2371 if (fVal < 0.0) { |
2367 fVal = (float)ceil((double)fVal - 0.5); |
2372 fVal = (float)ceil((double)fVal - 0.5); |
2368 } else { |
2373 } else { |
2369 fVal = (float)floor((double)fVal + 0.5); |
2374 fVal = (float)floor((double)fVal + 0.5); |
2370 } |
2375 } |
2371 #endif |
2376 #endif |
2372 /* |
2377 /* |
2373 * ST-80 (and X3J20) return integer. |
2378 * ST-80 (and X3J20) return integer. |
2374 */ |
2379 */ |
2375 if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) { |
2380 if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) { |
2376 RETURN ( __mkSmallInteger( (INT) fVal ) ); |
2381 RETURN ( __mkSmallInteger( (INT) fVal ) ); |
2377 } |
2382 } |
2378 __qMKSFLOAT(val, fVal); |
2383 __qMKSFLOAT(val, fVal); |
2379 %}. |
2384 %}. |
2380 ^ val asInteger |
2385 ^ val asInteger |
2381 |
2386 |
2444 float fVal; |
2449 float fVal; |
2445 |
2450 |
2446 fVal = __shortFloatVal(self); |
2451 fVal = __shortFloatVal(self); |
2447 #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) |
2452 #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) |
2448 if (fVal < 0.0) { |
2453 if (fVal < 0.0) { |
2449 fVal = ceilf(fVal); |
2454 fVal = ceilf(fVal); |
2450 } else { |
2455 } else { |
2451 fVal = floorf(fVal); |
2456 fVal = floorf(fVal); |
2452 } |
2457 } |
2453 #else |
2458 #else |
2454 if (fVal < 0.0) { |
2459 if (fVal < 0.0) { |
2455 fVal = (float)ceil((double)fVal); |
2460 fVal = (float)ceil((double)fVal); |
2456 } else { |
2461 } else { |
2457 fVal = (float)floor((double)fVal); |
2462 fVal = (float)floor((double)fVal); |
2458 } |
2463 } |
2459 #endif |
2464 #endif |
2460 /* |
2465 /* |
2461 * ST-80 (and X3J20) returns integer. |
2466 * ST-80 (and X3J20) returns integer. |
2462 */ |
2467 */ |
2463 if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) { |
2468 if ((fVal >= (float)_MIN_INT) && (fVal <= (float)_MAX_INT)) { |
2464 RETURN ( __mkSmallInteger( (INT) fVal ) ); |
2469 RETURN ( __mkSmallInteger( (INT) fVal ) ); |
2465 } |
2470 } |
2466 __qMKSFLOAT(val, fVal); |
2471 __qMKSFLOAT(val, fVal); |
2467 %}. |
2472 %}. |
2468 ^ val asInteger |
2473 ^ val asInteger |
2469 |
2474 |