--- a/LimitedPrecisionReal.st Tue May 08 09:05:13 2018 +0200
+++ b/LimitedPrecisionReal.st Tue May 08 10:40:28 2018 +0200
@@ -1249,7 +1249,6 @@
! !
-
!LimitedPrecisionReal methodsFor:'queries'!
decimalPrecision
@@ -1426,7 +1425,6 @@
^ 0
! !
-
!LimitedPrecisionReal methodsFor:'testing'!
isFinite
@@ -1557,6 +1555,97 @@
"
0.4 asLongFloat truncatedAsFloat
"
+!
+
+truncatedToPrecision
+ "truncates to the precision of the float.
+ This is slightly different from truncated.
+ Taking for example 1e32,
+ the printed representation will be 1e32,
+ but the actual value, when truncating to an integer
+ would be 100000003318135351409612647563264.
+
+ This is due to the inaccuracy in the least significant bits,
+ and the way the print-converter compensates for this.
+ This method tries to generate an integer value which corresponds
+ to what is seen in the float's printString.
+
+ Here, a slow fallback (generating and rescanning the printString)
+ is provided, which should work on any float number.
+ Specialized versions in subclasses may be added for more performance
+ (however, this is probably only used rarely)"
+
+ |pow10 printString intVal s sign nFract ch expSign exp pI|
+
+ pow10 := #(10 100 1000 10000 100000 1000000 10000000 100000000 1000000000).
+
+ printString := self printString.
+ intVal := 0.
+ sign := 1.
+ nFract := 0.
+ exp := 0.
+
+ "/ fetch the mantissa
+ s := printString readStream.
+ s peek == $- ifTrue:[
+ sign := -1.
+ s next.
+ ].
+ intVal := s nextDecimalInteger.
+ s peek == $. ifTrue:[
+ s next.
+ [(ch := s peek) notNil and:[ch isDigit]] whileTrue:[
+ intVal := intVal * 10 + (s next digitValue).
+ nFract := nFract + 1.
+ ].
+ ].
+ ('eEdDqQ' includes:s peek) ifTrue:[
+ expSign := 1.
+ s next.
+ (ch := s peek) == $- ifTrue:[
+ expSign := -1.
+ s next.
+ ] ifFalse:[
+ ch == $+ ifTrue:[
+ s next.
+ ].
+ ].
+ exp := s nextDecimalInteger.
+ exp := exp * expSign.
+ ].
+ exp := exp - nFract.
+ exp < 0 ifTrue:[
+ [exp < 0] whileTrue:[
+ pI := (exp negated) min:pow10 size.
+ intVal := intVal / (pow10 at:pI).
+ exp := exp + pI.
+ ].
+ intVal := intVal asInteger.
+ ] ifFalse:[
+ [exp > 0] whileTrue:[
+ pI := exp min:pow10 size.
+ intVal := intVal * (pow10 at:pI).
+ exp := exp - pI.
+ ].
+ ].
+ ^ intVal
+
+ "
+ 1e32 asShortFloat truncated
+ 1e32 asShortFloat truncatedToPrecision
+ 1.234e10 asShortFloat truncatedToPrecision
+ 1234e-1 asShortFloat truncatedToPrecision
+
+ 1e32 truncated
+ 1e32 truncatedToPrecision
+ 1.234e10 truncatedToPrecision
+ 1234e-1 truncatedToPrecision
+
+ 1e32 asLongFloat truncated
+ 1e32 asLongFloat truncatedToPrecision
+ 1.234e10 asLongFloat truncatedToPrecision
+ 1234e-1 asLongFloat truncatedToPrecision
+ "
! !
!LimitedPrecisionReal methodsFor:'visiting'!