[squeak-dev] The Trunk: Collections-ul.607.mcz

Levente Uzonyi leves at elte.hu
Thu Apr 2 13:06:34 UTC 2015


I don't see any senders of #nextFloat in my image, so I think we can 
safely trade performance for quality here.

Levente

On Thu, 2 Apr 2015, Nicolas Cellier wrote:

> Just a side note: nextFloat is broken in the sense that it will fail to answer the nearest floating point value to the specified decimal value.
> 
> OK, it's reasonably fast, but the comments should mention the trade offs.
> 
> Also in 32 bits VM, nextFloat might be slower than NumberParser when numbers are specified with many decimal digits.
> 
> Nicolas
> 
> 2015-04-02 0:08 GMT+02:00 <commits at source.squeak.org>:
>       Levente Uzonyi uploaded a new version of Collections to project The Trunk:
>       http://source.squeak.org/trunk/Collections-ul.607.mcz
>
>       ==================== Summary ====================
>
>       Name: Collections-ul.607
>       Author: ul
>       Time: 2 April 2015, 12:07:14.622 am
>       UUID: 607c7a3f-c462-454c-8e18-02c49e4ae91a
>       Ancestors: Collections-ul.606
>
>       Simplified CharacterSet class>>separators.
>       Fixed ReadStream >> #nextFloat, when collection is not a ByteString.
>
>       =============== Diff against Collections-ul.606 ===============
>
>       Item was changed:
>         ----- Method: CharacterSet class>>separators (in category 'accessing') -----
>         separators
>               "return a set containing just the whitespace characters"
>
>       +       ^Separators ifNil: [ Separators := self newFrom: Character separators ]!
>       -       ^Separators ifNil: [
>       -               Separators := self new
>       -                       addAll: Character separators;
>       -                       yourself ]!
>
>       Item was changed:
>         ----- Method: ReadStream>>nextFloat (in category 'accessing') -----
>         nextFloat
>               "Read a floating point value from the receiver. This method is highly optimized for cases
>               where many floating point values need to be read subsequently. And if this needs to go
>               even faster, look at the inner loops fetching the characters - moving those into a plugin
>               would speed things up even more."
>               | buffer count sign index cc value digit fraction exp startIndex anyDigit digitNeeded |
>               buffer := collection.
>               count := readLimit.
>               index := position+1.
>
>               "Skip separators"
>       +       index := ByteString findFirstInString: buffer inSet: CharacterSet nonSeparators byteArrayMap startingAt: index.
>       -       index := buffer indexOfAnyOf: CharacterSet nonSeparators startingAt: index.
>               index = 0 ifTrue:[self setToEnd. ^nil].
>
>               "check for sign"
>               digitNeeded := false.
>               sign := 1. cc := buffer byteAt: index.
>               cc = 45 "$- asciiValue"
>                       ifTrue:[sign := -1. index := index+1. digitNeeded := true]
>                       ifFalse:[cc =  43 "$+ asciiValue" ifTrue:[index := index+1. digitNeeded := true]].
>
>               "Read integer part"
>               startIndex := index.
>               value := 0.
>               [index <= count and:[
>                       digit := (buffer byteAt: index) - 48. "$0 asciiValue"
>                       digit >= 0 and:[digit <= 9]]] whileTrue:[
>                               value := value * 10 + digit.
>                               index := index + 1.
>               ].
>               anyDigit := index > startIndex.
>               index > count ifTrue:[
>                       (digitNeeded and:[anyDigit not]) ifTrue:[^self error: 'At least one digit expected'].
>                       self setToEnd. ^value asFloat * sign].
>
>               (buffer byteAt: index) = 46 "$. asciiValue" ifTrue:["<integer>.<fraction>"
>                       index := index+1.
>                       startIndex := index.
>                       "NOTE: fraction and exp below can overflow into LargeInteger range. If they do, then things slow down horribly due to the relatively slow LargeInt -> Float
>       conversion. This can be avoided by changing fraction and exp to use floats to begin with (0.0 and 1.0 respectively), however, this will give different results to Float>>readFrom:
>       and it is not clear if that is acceptable here."
>                       fraction := 0. exp := 1.
>                       [index <= count and:[
>                               digit := (buffer byteAt: index) - 48. "$0 asciiValue"
>                               digit >= 0 and:[digit <= 9]]] whileTrue:[
>                                       fraction := fraction * 10 + digit.
>                                       exp := exp * 10.
>                                       index := index + 1.
>                       ].
>                       value := value + (fraction asFloat / exp asFloat).
>                       anyDigit := anyDigit or:[index > startIndex].
>               ].
>               value := value asFloat * sign.
>
>               "At this point we require at least one digit to avoid allowing:
>                       - . ('0.0' without leading digits)
>                       - e32 ('0e32' without leading digits)
>                       - .e32 ('0.0e32' without leading digits)
>               but these are currently allowed:
>                       - .5 (0.5)
>                       - 1. ('1.0')
>                       - 1e32 ('1.0e32')
>                       - 1.e32 ('1.0e32')
>                       - .5e32 ('0.5e32')
>               "
>               anyDigit ifFalse:["Check for NaN/Infinity first"
>                       (count - index >= 2 and:[(buffer copyFrom: index to: index+2) = 'NaN'])
>                               ifTrue:[position := index+2. ^Float nan * sign].
>                       (count - index >= 7 and:[(buffer copyFrom: index to: index+7) = 'Infinity'])
>                               ifTrue:[position := index+7. ^Float infinity * sign].
>                       ^self error: 'At least one digit expected'
>               ].
>
>               index > count ifTrue:[self setToEnd. ^value asFloat].
>
>               (buffer byteAt: index) = 101 "$e asciiValue" ifTrue:["<number>e[+|-]<exponent>"
>                       index := index+1. "skip e"
>                       sign := 1. cc := buffer byteAt: index.
>                       cc = 45 "$- asciiValue"
>                               ifTrue:[sign := -1. index := index+1]
>                               ifFalse:[cc = 43 "$+ asciiValue" ifTrue:[index := index+1]].
>                       startIndex := index.
>                       exp := 0. anyDigit := false.
>                       [index <= count and:[
>                               digit := (buffer byteAt: index) - 48. "$0 asciiValue"
>                               digit >= 0 and:[digit <= 9]]] whileTrue:[
>                                       exp := exp * 10 + digit.
>                                       index := index + 1.
>                       ].
>                       index> startIndex ifFalse:[^self error: 'Exponent expected'].
>                       value := value * (10.0 raisedToInteger: exp * sign).
>               ].
>
>               position := index-1.
>               ^value!
> 
> 
> 
> 
>


More information about the Squeak-dev mailing list