Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes to conversions between Float and String. Includes tests. Thanks…
… Andrés for the suggestion.
- Loading branch information
Showing
2 changed files
with
217 additions
and
5 deletions.
There are no files selected for viewing
141 changes: 141 additions & 0 deletions
141
CoreUpdates/3452-FloatStringConversionFixes-JuanVuletich-2018Sep24-09h04m-jmv.2.cs.st
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
'From Cuis 5.0 of 7 November 2016 [latest update: #3451] on 24 September 2018 at 11:00:42 am'! | ||
|
||
!Number class methodsFor: 'instance creation' stamp: 'jmv 9/24/2018 11:00:21'! | ||
readRemainderOf: integerPart from: aStream base: base withSign: sign | ||
"Read optional fractional part and exponent, and return the final result" | ||
| value fraction fracpos peekChar exp scale | | ||
|
||
value := integerPart. | ||
(aStream peekFor: $.) | ||
ifTrue: [ "<integer>.<fraction>" | ||
(aStream atEnd not and: [ aStream peek digitValue between: 0 and: base - 1 ]) | ||
ifTrue: [ | ||
fracpos := aStream position. | ||
fraction := Integer readFrom: aStream base: base. | ||
fraction := fraction / (base raisedToInteger: aStream position - fracpos). | ||
value := value asFloat + fraction] | ||
ifFalse: [ | ||
"oops - just <integer>." | ||
aStream skip: -1. | ||
"un-gobble the period" | ||
^ value * sign"Number readFrom: '3r-22.2'"]]. | ||
peekChar := aStream peek. | ||
peekChar = $e | (peekChar = $d) | (peekChar = $q) | ||
ifTrue: [ "<number>(e|d|q)<exponent>>" | ||
aStream next. | ||
(aStream atEnd not and: [ (aStream peek digitValue between: 0 and: 9) or: [ aStream peek = $- ]]) | ||
ifTrue: [ | ||
exp := Integer readFrom: aStream. | ||
scale := base raisedToInteger: exp. | ||
value := (value isFloat and: [ scale asFloat < Float fminNormalized ]) | ||
ifTrue: [ | ||
"Avoid Float arithmetic to allow stuff like | ||
12345678901234567890.0e-330 | ||
(Float fminNormalized / 10) storeString asNumber = ((Float fminNormalized / 10)) | ||
" | ||
(value asTrueFraction * scale) asFloat ] | ||
ifFalse: [ value * scale ] ] | ||
ifFalse: [ | ||
"oops - just <number>." | ||
aStream skip: -1.]]. | ||
^(value isFloat | ||
and: [ value = 0.0 and: [ sign = -1 ]]) | ||
ifTrue: [ Float negativeZero ] | ||
ifFalse: [ value * sign ]! ! | ||
|
||
|
||
!Float methodsFor: 'printing' stamp: 'jmv 9/24/2018 10:31:30'! | ||
absPrintExactlyOn: aStream base: base | ||
"Print my value on a stream in the given base. Assumes that my value is strictly | ||
positive; negative numbers, zero, and NaNs have already been handled elsewhere. | ||
Based upon the algorithm outlined in: | ||
Robert G. Burger and R. Kent Dybvig | ||
Printing Floating Point Numbers Quickly and Accurately | ||
ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation | ||
June 1996. | ||
This version guarantees that the printed representation exactly represents my value | ||
by using exact integer arithmetic." | ||
|
||
| significand exp baseExpEstimate r s mPlus mMinus scale roundingIncludesLimits d tc1 tc2 fixedFormat decPointCount slowbit shead | | ||
self isInfinite ifTrue: [aStream nextPutAll: 'Infinity'. ^ self]. | ||
significand := self significandAsInteger. | ||
roundingIncludesLimits := significand even. | ||
exp := (self exponent - 52) max: MinValLogBase2. | ||
baseExpEstimate := (self exponent * base asFloat reciprocalLogBase2 - 1.0e-10) ceiling. | ||
exp >= 0 | ||
ifTrue: | ||
[significand ~= 16r10000000000000 | ||
ifTrue: | ||
[r := significand bitShift: 1 + exp. | ||
s := 2. | ||
mPlus := mMinus := 1 bitShift: exp] | ||
ifFalse: | ||
[r := significand bitShift: 2 + exp. | ||
s := 4. | ||
mPlus := 2 * (mMinus := 1 bitShift: exp)]] | ||
ifFalse: | ||
[(exp = MinValLogBase2 or: [significand ~= 16r10000000000000]) & false | ||
ifTrue: | ||
"jmv 2018-9-24. Deactivated. Makes the following false (See Tests package):" | ||
" | ||
| float | | ||
float _ (Float fminNormalized / 2) successor. | ||
float storeString asNumber = float | ||
" | ||
[r := significand bitShift: 1. | ||
s := 1 bitShift: 1 - exp. | ||
mPlus := mMinus := 1] | ||
ifFalse: | ||
[r := significand bitShift: 2. | ||
s := 1 bitShift: 2 - exp. | ||
mPlus := 2. | ||
mMinus := 1]]. | ||
baseExpEstimate >= 0 | ||
ifTrue: [s := s * (base raisedToInteger: baseExpEstimate)] | ||
ifFalse: | ||
[scale := base raisedToInteger: baseExpEstimate negated. | ||
r := r * scale. | ||
mPlus := mPlus * scale. | ||
mMinus := mMinus * scale]. | ||
((r + mPlus < s) not and: [roundingIncludesLimits or: [r + mPlus > s]]) | ||
ifTrue: [baseExpEstimate := baseExpEstimate + 1] | ||
ifFalse: | ||
[r := r * base. | ||
mPlus := mPlus * base. | ||
mMinus := mMinus * base]. | ||
(fixedFormat := baseExpEstimate between: -3 and: 6) | ||
ifTrue: | ||
[decPointCount := baseExpEstimate. | ||
baseExpEstimate <= 0 | ||
ifTrue: [aStream nextPutAll: ('0.000000' truncateTo: 2 - baseExpEstimate)]] | ||
ifFalse: | ||
[decPointCount := 1]. | ||
slowbit := 1 - s lowBit . | ||
shead := s bitShift: slowbit. | ||
[d := (r bitShift: slowbit) // shead. | ||
r := r - (d * s). | ||
(tc1 := (r > mMinus) not and: [roundingIncludesLimits or: [r < mMinus]]) | | ||
(tc2 := (r + mPlus < s) not and: [roundingIncludesLimits or: [r + mPlus > s]])] whileFalse: | ||
[aStream nextPut: (Character digitValue: d). | ||
r := r * base. | ||
mPlus := mPlus * base. | ||
mMinus := mMinus * base. | ||
decPointCount := decPointCount - 1. | ||
decPointCount = 0 ifTrue: [aStream nextPut: $.]]. | ||
tc2 ifTrue: | ||
[(tc1 not or: [r * 2 >= s]) ifTrue: [d := d + 1]]. | ||
aStream nextPut: (Character digitValue: d). | ||
decPointCount > 0 | ||
ifTrue: | ||
[decPointCount - 1 to: 1 by: -1 do: [:i | aStream nextPut: $0]. | ||
aStream nextPutAll: '.0']. | ||
fixedFormat ifFalse: | ||
[aStream nextPut: $e. | ||
aStream nextPutAll: (baseExpEstimate - 1) printString]! ! | ||
|
||
!Float methodsFor: 'printing' stamp: 'jmv 9/24/2018 10:56:53'! | ||
absPrintOn: aStream base: base | ||
"In Cuis, print Floats with enough digits to be able to recover later exactly the same Float." | ||
|
||
self absPrintExactlyOn: aStream base: base! ! | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters