exponential notation for ScaledDecimal fromString:

VA Smalltalk is a "100% VisualAge compatible" IDE that includes the original VisualAge technology and the popular VA Assist and WidgetKit add-ons.

Moderators: Eric Clayberg, wembley, tc, Diane Engles, solveig

exponential notation for ScaledDecimal fromString:

Postby jkoepp » Thu Apr 07, 2011 6:02 am

The exponential notation from Float printString e.g. (1/3) asFloat printString is not understood by the responsible method for reading: ScaledDecimal class>>#fromString: - only the Smalltalk-Compiler is able to understand e.g. 1.2e-1 !

So here is my version for this case. I avoided changing scale and precision. Only simple multiplication with the exponent. The new part is at the end of the (current) code.

Code: Select all
ScaledDecimal class

fromString: aString
   "Answer an instance of a ScaledDecimal that is described by aString.
   
    aString may be in
      Float format (1.2e-1)
      legacy format (23.76d4.2),
      ANSI format (23.76s2)
       or common format (23.76).
   
   ScaledDecimal fromString: '1.2e-1'
   ScaledDecimal fromString: '1.2e-2'
   ScaledDecimal fromString: (1/3) asFloat printString
   ScaledDecimal fromString: 1234567890123450.0 printString"
   
   | index number sign precision scale specifiedPrecision specifiedScale |
   
   ##PR = ##'1G1JPMF'.

   "Initialize our variables."

   index := 1.
   number := 0.
   sign := 1.
   scale := 0.
   precision := 0.

   "Consume leading spaces."
   [index <= aString size and: [(aString at: index) == $ ]] whileTrue: [index := index + 1].

   "Check for sign."
   index <= aString size ifTrue: [
      (aString at: index) == $- ifTrue: [
         sign := -1.
         index := index + 1]
      ifFalse: [
         (aString at: index) == $+ ifTrue: [index := index + 1]]].

   "Collect digits before the decimal place."
   [index <= aString size and: [(aString at: index) isDigit]] whileTrue: [
      number := (number * 10) + (aString at: index) digitValue.
      precision := precision + 1.
      index := index + 1].

   "Ensure we don't answer precision = scale"
   precision == 0
      ifTrue: [precision := 1].

   "Deal with digits after the decimal place."
   (index <= aString size and: [(aString at: index) == $.]) ifTrue: [
      index := index + 1.
      [index <= aString size and: [(aString at: index) isDigit]] whileTrue: [
         number := (number * 10) + (aString at: index) digitValue.
         precision := precision + 1.
         scale := scale + 1.
         index := index + 1]].

   (index <= aString size and: [(aString at: index) == $s]) ifTrue: [   "ANSI format"
      index := index + 1.
      (index <= aString size and: [(aString at: index) isDigit])
         ifTrue: [
            specifiedScale := 0.
            [index <= aString size and: [(aString at: index) isDigit]] whileTrue: [
               specifiedScale := (specifiedScale * 10) + (aString at: index) digitValue.
               index := index + 1]]
         ifFalse: [specifiedScale := scale].
      specifiedPrecision := precision - scale + specifiedScale.
      ^ ScaledDecimal
         fromUnscaled: number
         sign: sign
         scale: scale
         coerceToPrecision: specifiedPrecision
         scale: specifiedScale].

   (index <= aString size and: [(aString at: index) == $d]) ifTrue: [   "Legacy format"
      specifiedPrecision := 0.
      specifiedScale := scale.
      index := index + 1.

      (index <= aString size and: [(aString at: index) isDigit]) ifTrue: [
          "Get the specified precision."
         [
            specifiedPrecision := (specifiedPrecision * 10) + (aString at: index) digitValue.
            index := index + 1.
            index <= aString size and: [(aString at: index) isDigit]]
               whileTrue.

         "Get the specified scale."
         (index <= aString size and: [(aString at: index) == $.]) ifTrue: [
            index := index + 1.
            specifiedScale := 0.
            [index <= aString size and: [(aString at: index) isDigit]] whileTrue: [
               specifiedScale := (specifiedScale * 10) + (aString at: index) digitValue.
               index := index + 1]].
      ^ ScaledDecimal
         fromUnscaled: number
         sign: sign
         scale: scale
         coerceToPrecision: specifiedPrecision
         scale: specifiedScale]].
   
   "*** new ***"
   (index <= aString size and: [(aString at: index) == $e]) ifTrue: [   "Float format"
      | exponentSign exponent |
      index := index + 1.
      exponentSign := 1.
      "Check for sign."
      index <= aString size ifTrue: [
         (aString at: index) == $- ifTrue: [
            exponentSign := -1.
            index := index + 1] ].
      (index <= aString size and: [(aString at: index) isDigit])
         ifTrue: [
            exponent := 0.
            [index <= aString size and: [(aString at: index) isDigit]] whileTrue: [
               exponent := (exponent * 10) + (aString at: index) digitValue.
               index := index + 1].
            exponent := exponent * exponentSign]
         ifFalse: [exponent := 0].
      ^(exponent power: 10) * ((ScaledDecimal fromUnscaled: number sign: sign scale: scale) precision: precision)].
      
   ^(ScaledDecimal fromUnscaled: number sign: sign scale: scale) precision: precision


Juergen
jkoepp
 
Posts: 9
Joined: Mon Mar 31, 2008 4:40 am

Re: exponential notation for ScaledDecimal fromString:

Postby jkoepp » Mon Apr 11, 2011 6:01 am

The intention was avoiding errors like

Float fromString: '1.0e-1' -> 1.0 instead 0.1
Float fromString: 1234567890123450.0 printString -> 1.23456789012345

so we can replace
8.2 asScaledDecimal -> 8.199999999999999s15
by
8.2 printString asScaledDecimal -> 8.2s1
without risking the type of error from above. This is not really clean code, but I guess there is still a lot of code using one or the other workaround of this style. In one case a company mastered the "e-X" problem but was not aware of the possibility of positive exponents. This big numbers are of course rare at the moment.

The general recommendation for financial applications is to avoid Floats. But even then it is not acceptable to have errors like
ScaledDecimal fromString: '1.23456789012345e15' --> 1.23456789012345
in a programming language. Smalltalk should throw at least an error if it is not able to understand the scientific notation! The compiler already understands it.

Juergen
jkoepp
 
Posts: 9
Joined: Mon Mar 31, 2008 4:40 am

Re: exponential notation for ScaledDecimal fromString:

Postby wembley » Mon Apr 11, 2011 10:01 am

Case 48376 opened -- we'll try to get this into V8.5 ...
John O'Keefe [|], Principal Smalltalk Architect, Instantiations Inc.
wembley
Moderator
 
Posts: 405
Joined: Mon Oct 16, 2006 3:01 am
Location: Durham, NC


Return to VA Smalltalk 7.0, 7.5 & 8.0

Who is online

Users browsing this forum: No registered users and 1 guest

cron