!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: decfloat.gs,v 1.16.2.1 2008-03-14 18:27:02 bretlb Exp $
!
! Superclass Hierarchy:
!   DecimalFloat, Number, Magnitude, Object.
!
! class DecimalFloat created in floatclasses.gs
!=========================================================================

removeallmethods DecimalFloat
removeallclassmethods DecimalFloat

category: 'For Documentation Installation only'
classmethod: DecimalFloat
installDocumentation

| doc txt |
doc := GsClassDocumentation newForClass: self.

txt := (GsDocText new) details:
'This class represents base 10 floating point numbers, as defined in IEEE
 standard 854-1987.

 You may not create subclasses of DecimalFloat.

 Objects of class DecimalFloat have 20 digits of precision, with an exponent in
 the range -15000 to +15000.  The first byte has encoded in it the sign and kind
 of the floating-point number.  Bit 0 is the sign bit (0=positive, 1=negative).
 The values in bits 1 through 3 indicate the kind of DecimalFloat:

 * 001x = normal
 * 010x = subnormal
 * 011x = infinity
 * 100x = zero
 * 101x = quiet NaN
 * 110x = signaling NaN

 Bytes 2 and 3 encode the exponent as a biased 16-bit number (byte 2 is more
 significant).  The actual exponent is calculated by subtracting 15000.  Bytes
 4 through 13 form the mantissa of the number.  Each byte holds two BCD digits,
 with bits 4 through 7 of byte 4 containing the most significant digit.'.
doc documentClassWith: txt.

txt := (GsDocText new) details:
'Float status flags, exception handlers, and non-default rounding modes are
 maintained only for a single GemStone Smalltalk execution, and are cleared
 when a new execution begins.'.
doc documentClassCategory: #'Exception Handling' with: txt.

self description: doc.
%

category: 'Instance Creation'
classmethod: DecimalFloat
fromStream: aStream

"Generates a DecimalFloat from aStream.  Generates an error if an attempt is
 made to read beyond the end of the stream.

 The Stream must contain a legal DecimalFloat, as defined by the following BNF
 construction:

 DecimalFloat = ( Integer '.' Digit {Digit} [ E Integer ] ) |
         ( Integer E Integer )
 Integer = [ ('+' | '-') ] Digit {Digit}
 Point = ( '.' | ',' ) depending on Locale
 E = ( 'E' | 'e')

 Note that the syntax does not allow certain valid DecimalFloats (such as
 DecimalPlusInfinity and MinusInfinity) to be read."

| ch s getDigits getChar getSign |

self _checkReadStream: aStream forClass: CharacterCollection.

ch := aStream next.
[ ch isEquivalent: $ ]
whileTrue:
  [ ch := aStream next ].
aStream position: (aStream position - 1).
s := aStream contents class new.

getDigits := [ (aStream atEnd _or: [ aStream peek isDigit not])
               ifTrue:
                 [ self _errIncorrectFormat: aStream ].
               [ aStream atEnd not _and: [ aStream peek isDigit ] ]
               whileTrue:
                 [ s add: aStream next ].
             ].

getChar := [ :c |
             (aStream peek isEquivalent: c)
             ifTrue:
               [ s add: aStream next ]
           ].

getSign := [ (getChar value: $-) == nil
              ifTrue:
                [ getChar value: $+ ].
           ].

getSign value.
getDigits value.

(getChar value: (Locale decimalPoint at: 1))  ~~ nil
ifTrue:
  [ getDigits value ].

((getChar value: $e) ~~ nil)
ifTrue:
  [ getSign value.
    getDigits value.
  ].

^ self fromString: s
%

category: 'Instance Creation'
classmethod: DecimalFloat
new

"Returns a PlusSignalingNaN.  You can use this method to
 define a DecimalFloat without specifying its value."

^ self _oneArgPrim: 0 arg: nil
%

category: 'Exception Handling'
classmethod: DecimalFloat
_raiseInvalidOperationException

"This method sets the invalid operation exception of the floating point
 processor."

DecimalPlusSignalingNaN + 3.0F0 .
^self
%

category: 'Exception Handling'
classmethod: DecimalFloat
clearException: aString

"Clears the raised exception type defined by aSymbol 
 (#divideByZero, #inexactResult, #invalidOperation, #overflow, #underflow).  
 If aSymbol is
 not one of these exception types, an error is generated.  Raised exceptions
 are set by GemStone during floating point operations, and must be explicitly
 cleared with this method."

|state kind aSymbol|
aSymbol := aString asSymbol .
kind := self _exceptionKind: aSymbol.
state := self status.
state at: self _exceptionList size + kind put: $0.
self status: state.
%

category: 'Exception Handling'
classmethod: DecimalFloat
clearAllExceptions

"Clears all raised exceptions."

self _exceptionList do: [:each | self clearException: each]
%

category: 'Exception Handling'
classmethod: DecimalFloat
raisedExceptions

"Returns a list of all raised exceptions."

|result|

result := Array new.
self _exceptionList do: [:each|
  (self raisedException: each) ifTrue: [
    result add: each]].
^result
%

category: 'Exception Handling'
classmethod: DecimalFloat
_setException: anException to: aBool

"Turns on (or off) a floating point exception.  Returns the previous state."

|state kind|
kind := self _exceptionKind: anException.
state := self status.
state at: self _exceptionList size * 2 + kind
     put: (aBool ifTrue: [$1] ifFalse: [$0]).
self status: state
%

category: 'Exception Handling'
classmethod: DecimalFloat
_exceptionFor: aSymbol

"Returns exception installed on given symbol, else nil."

|this desired|

this := Exception _staticExceptions.
desired := ErrorSymbols at: #numErrFltException.

[this == nil] whileFalse: [
  (this category == GemStoneError _and: [
      this number == desired _and: [
      this subtype == aSymbol]]) ifTrue: [ ^this ].
  this := this next].
^nil
%

category: 'Exception Handling'
classmethod: DecimalFloat
on: aString do: aBlock

"Has no effect in GemStone V5.0."

"The argument aString defines the exception type ( #divideByZero,
 #inexactResult, #invalidOperation, #overflow, #underflow).  If aString is
 not one of these, an error is generated.

 The three-argument block aBlock is evaluated when the specified exception
 occurs.  The three arguments to aBlock are:

 1.  The category of the exception (always GemStoneError)
 2.  The number of the exception (always rtErrFltException)
 3.  an Array containing arguments to the exception, to wit:
    1.  The type of exception (a Symbol, such as #divideByZero)
    2.  The selector of the offending operation,
    3.  The default result that would be returned,
    4.  The first operand to the operation,
    5.  The second operand to the operation, if any.

 The value that the block returns becomes the result of the floating point
 operation.

 Note that underflow and overflow pass an unusual result to the
 trap handler if the exception is enabled.  In particular, the
 correct result is biased by a factor of 10 to the 22500 power to
 bring it into the representable range of a DecimalFloat.

 If you do not want to field the exception specified by aSymbol,
 leave aBlock nil.  If aBlock is neither a block nor nil,
 an error is generated.  Returns the receiver."

^ self 
"unused code:
| oldException aSymbol |
aSymbol := aString asSymbol .

oldException := self _exceptionFor: aSymbol.
oldException ~~ nil ifTrue: [ Exception removeStaticException: oldException].

aBlock ~~nil ifTrue: [
    aBlock numberArgs ~= 3 ifTrue: [
      ^aBlock _error: #rtErrBadBlockArgCount args: #[aBlock numberArgs, 3].
      ].
    self _setException: aSymbol to: true.
    self _installException: aBlock on: aSymbol.
  ]
  ifFalse: [
    self _setException: aSymbol to: false.
  ]
end unused code"
%

category: 'Exception Handling'
classmethod: DecimalFloat
_installException: aBlock on: aSymbol

"Install given block as a static exception."

Exception installStaticException:
      [:theException :cat :num :args |
            (args at: 1) = theException subtype ifFalse: [
              theException resignal: cat number: num args: args].
            aBlock value: cat value: num value: args]
        category: GemStoneError
        number: (ErrorSymbols at: #numErrFltException)
        subtype: aSymbol
%

category: 'Exception Handling'
classmethod: DecimalFloat
operationException: aString

"Returns true if the specified exception has occurred in the current operation.
 Otherwise, returns false.  The argument aString defines the exception type
 (#divideByZero, #inexactResult, #invalidOperation, #overflow,
 #underflow).  
 If aSymbol is not one of these, an error is generated."

|status kind aSymbol|
aSymbol := aString asSymbol .
status := DecimalFloat status.
kind := DecimalFloat _exceptionKind: aSymbol.
^(status at: kind) == $1
%

category: 'Exception Handling'
classmethod: DecimalFloat
operationExceptions

"Returns a list of all exceptions raised by the last floating point operation."

|result|

result := Array new.
self _exceptionList do: [:each|
  (self operationException: each) ifTrue: [
    result add: each]].
^result
%

category: 'Exception Handling'
classmethod: DecimalFloat
_exceptionList

"Returns the list of available exceptions, in order."

^ #(#divideByZero #invalidOperation #overflow #underflow #inexactResult ).
%

category: 'Exception Handling'
classmethod: DecimalFloat
_exceptionKind: aSymbol

"Use a String indicating a type of exception 
 (#divideByZero, #inexactResult, #invalidOperation, #overflow,
 #underflow).  
 Returns an offset to be used analyzing a DecimalFloat status string."

|list|

list := self _exceptionList.
1 to: list size do: [:i | (list at: i) == aSymbol ifTrue: [^i]].
^ aSymbol _error: #numErrArgNotFltException
%

category: 'Exception Handling'
classmethod: DecimalFloat
raisedException: aString

"Returns true if the specified exception has occurred since the last
 clearException: operation.  Otherwise, returns false.  The argument aSymbol
 defines the exception type 
 (#divideByZero, #inexactResult, #invalidOperation, #overflow, #underflow).  
 If aSymbol is not one of these, an error is generated.

 The occurrence of a floating point exception that is not trapped by
 on:do: causes that exception to be raised."

|status kind aSymbol |
aSymbol := aString asSymbol .
status := DecimalFloat status.
kind := DecimalFloat _exceptionKind: aSymbol.
^(status at: self _exceptionList size + kind) == $1
%

category: 'Exception Handling'
classmethod: DecimalFloat
status

"Returns a six-element Array.  The first element of the Array is a String
 representing the status of the floating point processor, including the
 operation exceptions, raised exceptions, rounding mode, and the enabled traps.
 The next five elements of the Array are the blocks associated with each of the
 enabled traps, in this order: divideByZero, inexactResult, invalidOperation,
 overflow, underflow.

 Any method that modifies the trap handlers should first save the status
 using this method.  After the method has modified the trap handlers, it
 should use status: to restore the status."

<primitive: 134>
^ self _primitiveFailed: #floatStatus
%

category: 'Exception Handling'
classmethod: DecimalFloat
status: aString

"Restores the status of the floating point processor to the previously saved
 status represented by aSymbol.  The argument aSymbol is the first element of
 the Array that DecimalFloat | status returns."

^ self _oneArgPrim:1 arg: aString asSymbol

%

category: 'Private'
classmethod: DecimalFloat
_oneArgPrim: opcode arg: anArg

"Private."

"opcode function
      0 new
      1 status:
      2 fromString:
      3 fromStringLocaleC:
"

<primitive: 135>
anArg _validateClass: String .
opcode == 0 ifTrue:[ anArg _error: #numErrArgNotFltStatus ] .
self _primitiveFailed: #_oneArgPrim:arg:
%

category: 'Exception Handling'
classmethod: DecimalFloat
trapEnabled: aString

"Returns true if a trap handler has been defined for the specified exception
 Otherwise, returns false."

|status kind|

status := DecimalFloat status.
kind := DecimalFloat _exceptionKind: aString asSymbol.
^(status at: self _exceptionList size * 2 + kind) == $1
%

category: 'Exception Handling'
classmethod: DecimalFloat
enabledExceptions

"Returns a list of all raised exceptions."

|result|

result := Array new.
self _exceptionList do: [:each|
  (self trapEnabled: each) ifTrue: [
    result add: each]].
^result
%

category: 'Truncation and Rounding'
classmethod: DecimalFloat
roundingMode

"Returns the current rounding mode ('nearestEven', 'towardMinusInfinity',
 'towardPlusInfinity', 'towardZero')."

|state mode|

state := DecimalFloat status.
mode := state at: 16.
mode == $E ifTrue: [ ^ #nearestEven].
mode == $N ifTrue: [ ^ #towardMinusInfinity].
mode == $P ifTrue: [ ^ #towardPlusInfinity].
mode == $Z ifTrue: [ ^ #towardZero].
^ #unknown "should never occur!"
%

category: 'Truncation and Rounding'
classmethod: DecimalFloat
roundingMode: aString

"The argument aString defines the rounding mode ('nearestEven',
 'towardMinusInfinity', 'towardPlusInfinity', 'towardZero').  If aString is not
 one of these, an error is generated."

|status newChar aSymbol|
aSymbol := aString asSymbol .
newChar := nil.
aSymbol == #nearestEven
  ifTrue: [newChar := $E]
  ifFalse: [
    aSymbol == #towardMinusInfinity
      ifTrue: [newChar := $N]
      ifFalse: [
        aSymbol == #towardPlusInfinity
          ifTrue: [newChar := $P]
	  ifFalse: [
            aSymbol == #towardZero
              ifTrue: [newChar := $Z]
            ]
        ]
    ].
newChar == nil ifTrue: [^ aString _error: #numErrArgNotRoundingMode].
status := DecimalFloat status.
status at: 16 put: newChar.
DecimalFloat status: status.
%

category: 'Accessing'
method: DecimalFloat
denominator

"Returns the denominator of a Fraction representing the receiver."

   "If an infinite or quiet NaN, returns self"
((self kind = #infinity) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self ].

   "If a signaling NaN, raises a floating point exception & returns self"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException.
             ^self _makeQuietNaN ].

^ (self asFraction) denominator
%

category: 'Accessing'
method: DecimalFloat
numerator

"Returns the numerator of a Fraction representing the receiver."

   "If an infinite or quiet NaN, returns self"
((self kind = #infinity) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self ].

   "If a signaling NaN, raises a floating point exception & returns self"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException.
             ^self _makeQuietNaN ].

^ (self asFraction) numerator
%

category: 'Accessing'
method: DecimalFloat
sign

"Returns 1 if the receiver is greater than zero, -1 if the receiver is
 less than zero, and zero if the receiver is zero."

^ self _zeroArgPrim: 1
%

category: 'Accessing'
method: DecimalFloat
at: anIndex put: aValue

"Disallowed.  You may not change the value of a DecimalFloat."

self shouldNotImplement: #at:put:
%

category: 'Accessing'
method: DecimalFloat
size: anInteger

"Disallowed.  You may not change the size of a DecimalFloat."

self shouldNotImplement: #size:
%

category: 'Formatting'
method: DecimalFloat
asString

"Returns a String corresponding to the receiver.  Where applicable, returns one
 of the following Strings: 'PlusInfinity', 'MinusInfinity', 'PlusQuietNaN',
 'MinusQuietNaN', 'PlusSignalingNaN', or 'MinusSignalingNaN'.

                                    Note:
 GemStone currently formats DecimalFloats independently.  Specifically, it does
 not adjust the style of representation according to locale (decimal notation
 is not internationalized).  Under some circumstances, string representation of
 DecimalFloats may be inconsistent with those of Floats (which do
 internationalize by adjusting to locale)."

^ self _zeroArgPrim: 2
%

category: 'Formatting'
method: DecimalFloat
asStringLocaleC

"Same as asString, but result always uses  $.  for decimal point."

^ self _zeroArgPrim: 4
%

category: 'Formatting'
method: DecimalFloat
asStringUsingFormat: anArray

"Returns a String corresponding to the receiver, using the format specified by
 anArray.  The Array contains three elements: two Integers and a Boolean.
 Generates an error if any element of the Array is missing or is of the wrong
 class.

 The first element of the Array (an Integer) specifies a minimum number of
 Characters in the result String (that is, the 'width' of the string).  If this
 element is positive, the resulting String is padded with blanks to the right
 of the receiver.  If this element is negative, the blanks are added to the
 left of the receiver.  If the value of this element is not large enough to
 completely represent the DecimalFloat, a longer String will be generated.

 The second element of the Array (also an Integer) specifies the maximum number
 of digits to display to the right of the decimal point.  If the value of this
 element exceeds the number of digits required to completely specify the
 DecimalFloat, only the required number of digits are actually displayed.
 If the value of this element is insufficient to completely specify the
 DecimalFloat, the value of the DecimalFloat is rounded up or down before
 it is displayed.

 The third element of the Array (a Boolean) indicates whether or not to display
 the magnitude using exponential notation.  (The value true indicates
 exponential notation and false indicates decimal notation.)

 For example, the number 12.3456 displayed with two different format Arrays
 would appear as follows:

 Format          Output
 #(10 5 true)    ' 1.23456E1'
 #(10 2 false)   '12.34'

                                    Note:
 GemStone currently formats DecimalFloats independently.  Specifically, it does
 not adjust the style of representation according to locale (decimal notation
 is not internationalized).  Under some circumstances, string representation of
 DecimalFloats may be inconsistent with those of Floats (which do
 internationalize by adjusting to locale)."

| value tempString count result width decimalWidth scientific
  decimalIndex expIndex intVal fractVal expVal fractString |

anArray _validateClass: Array.
(anArray size == 3)
ifFalse:
  [ ^ self _error: #rtErrBadFormatSpec args: #[anArray] ].

(anArray at: 1) _validateClass: Integer.
(anArray at: 2) _validateClass: Integer.
(anArray at: 3) _validateClass: Boolean.

width := anArray at: 1.

(#(#infinity #signalingNaN #quietNaN) includesValue: self kind)
ifTrue:
  [ result := self asString ]
ifFalse:
  [ decimalWidth := anArray at: 2.
    scientific := anArray at: 3.
    value := self abs.
    result := String new.
    self negative
    ifTrue:
      [ result add: $- ].

    scientific
    ifTrue:
      [ tempString := value asString.
        decimalIndex := tempString findString: '.' startingAt: 1.
        expIndex := tempString findString: 'E' startingAt: decimalIndex.
        intVal := Integer fromString:
                (tempString copyFrom: 1 to: decimalIndex - 1).
        fractVal := DecimalFloat fromString:
                '1.' , (tempString copyFrom: decimalIndex + 1 to: expIndex - 1).
        expVal := Integer fromString:
                (tempString copyFrom: expIndex + 1 to: tempString size).
      ]
    ifFalse:
      [ intVal := value integerPart.
        fractVal := 1.0F0 + value fractionPart.
        expVal := 0.
      ].

    count := 0.
    [ (count < decimalWidth) & (fractVal fractionPart ~= 0.0F0 ) ]
    whileTrue:
      [ fractVal := fractVal * 10.0F0 .
        count := count + 1.
      ].
    fractVal := fractVal + 0.5F0 .

    fractString := fractVal integerPart asString.
    ((fractString at: 1) = $1)
    ifFalse:
      [ intVal := intVal + 1 ].
    (scientific _and: [ intVal = 10 ])
    ifTrue:
      [ intVal := 1.
        expVal := expVal + 1.
      ].
    fractString removeFrom: 1 to: 1.
    (fractString size == 0) & (decimalWidth > 0)
    ifTrue:
      [ fractString := '0' ].

    result addAll: intVal asString;
           add: Locale decimalPoint;
           addAll: fractString.

    scientific
    ifTrue:
      [ result add: $E; addAll: expVal asString ].
  ].

^ result width: width
%

category: 'Converting'
method: DecimalFloat
asDecimalFloat

"Returns the receiver."

^ self
%

!"This method should be optimized, but it does work eventually.
! We should add a primitive to get the mantissa and the exponent
! of the float and work with those to get the answer."
category: 'Converting'
method: DecimalFloat
asFraction

"Returns a Fraction that represents the receiver.  If the receiver is a NaN,
 or Infinity, returns the receiver."

| num numerator denominator |

   "If an infinite or quiet NaN, returns self"
((self kind = #infinity) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self ].

   "If a signaling NaN, raises a floating point exception & returns self"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException.
             ^self _makeQuietNaN ].

num := self.
denominator := 1.

[ num fractionPart = 0 ]
whileFalse:
  [ denominator := denominator * 10.
    num := num * 10.0F0 .
  ].

numerator := num truncated.

^ Fraction numerator: numerator denominator: denominator
%

category: 'Converting'
method: DecimalFloat
_coerce: aNumber

"Returns an instance of DecimalFloat with the same value as 'aNumber'."

"This method must be defined by all subclasses of Number."

^aNumber asDecimalFloat
%

category: 'Converting'
method: DecimalFloat
_generality

"Returns the integer that represents the ordering of the receiver in the
 generality hierarchy."

"Reimplemented from Number"

^ 100
%

category: 'Converting'
method: DecimalFloat
_makeQuietNaN

"This method returns a quiet NaN with the same sign as the input NaN.  If the
 input is not a NaN, this method returns the receiver."

   "Is the receiver a NaN?"
((self kind = #quietNaN) _or: [self kind = #signalingNaN])
   ifFalse: [ ^self ]
   ifTrue: [ ^ PlusQuietNaN ]
%

category: 'Comparing'
method: DecimalFloat
_compare: aNumber opcode: opcode

"Private."

"opcode 0 means = , 1 means ~=, 2 means < , 3 means <= "

<primitive: 117>
(opcode <= 1) ifTrue:[
  (aNumber isKindOf: Number)
     ifTrue:[ ^ self _compare: aNumber asDecimalFloat opcode: opcode ] .
  ^ opcode == 1
  ].
aNumber _validateClass: Number .
^ self _compare: aNumber asDecimalFloat opcode: opcode
%

category: 'Comparing'
method: DecimalFloat
~= aNumber

"Returns true if the receiver is not equal to aNumber, and false otherwise."

^ self _compare: aNumber opcode: 1
%

category: 'Comparing'
method: DecimalFloat
< aNumber

"Returns true if the receiver is less than aNumber, and false otherwise."

^ self _compare: aNumber opcode: 2
%

category: 'Comparing'
method: DecimalFloat
<= aNumber

"Returns true if the receiver is less than or equal to a aNumber,
 and false otherwise."

^ self _compare: aNumber opcode: 3
%

category: 'Comparing'
method: DecimalFloat
= aNumber

"Returns true if the receiver is equal to aNumber, and false otherwise."

^ self _compare: aNumber opcode: 0
%

category: 'Comparing'
method: DecimalFloat
>= aNumber

"Returns true if the receiver is greater than or equal to aNumber,
 and false otherwise."

"Reimplemented from Magnitude to handle NaNs correctly."

^ aNumber <= self
%

! hash inherited from Number
! >=  inherited from Magnitude
! >  inherited from Magnitude
! ~=  inherited from Magnitude

category: 'Truncation and Rounding'
method: DecimalFloat
ceiling

"Returns the integer that is closest to the receiver, on the same side
 of the receiver as positive infinity."

   "If a signaling NaN, raise a floating point exception"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException ].

   "If a NaN, returns correct sign of self"
((self kind = #signalingNaN) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self _makeQuietNaN ].

(self <= 0.0F0)
   ifTrue: [^self truncated]
   ifFalse: [^self negated floor negated truncated]
%

category: 'Truncation and Rounding'
method: DecimalFloat
floor

"Returns the integer that is closest to the receiver, on the same side
 of the receiver as negative infinity."

|result|

   "If a signaling NaN, raise a floating point exception"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException ].

   "If a NaN, returns correct sign of self"
((self kind = #signalingNaN) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self _makeQuietNaN ].

result := self truncated.
(self >= 0)
   ifTrue: [^result].
(self = result)
   ifTrue: [^result]
   ifFalse: [^ (result - 1) truncated]
%

category: 'Truncation and Rounding'
method: DecimalFloat
fractionPart

"Returns the decimal part of the receiver."

^ self - self truncated asDecimalFloat
%

category: 'Truncation and Rounding'
method: DecimalFloat
integerPart

"Returns an integer representing the receiver truncated toward zero."

^ self truncated
%

category: 'Truncation and Rounding'
method: DecimalFloat
rounded

"Returns the integer nearest in value to the receiver."

   "If a signaling NaN, raise a floating point exception"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException ].

   "If a NaN, returns correct sign of self"
((self kind = #signalingNaN) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self _makeQuietNaN ].

self >= 0.0F0 ifTrue: [^(self + 0.5F0) truncated]
            ifFalse:[^(self - 0.5F0) truncated]
%

category: 'Truncation and Rounding'
method: DecimalFloat
roundTo: aNumber

"Returns the multiple of aNumber that is nearest in value to the receiver."

   "If a signaling NaN, raise a floating point exception"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException ].

   "If a NaN, returns correct sign of self"
((self kind = #signalingNaN) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self _makeQuietNaN ].

aNumber = 0
  ifTrue: [^0]
  ifFalse: [^(self / aNumber) rounded * aNumber]
%

category: 'Private'
method: DecimalFloat
_zeroArgPrim: opcode

"Private."

"opcode
  0 = truncated
  1 = sign
  2 = asString
  3 = sqrt
  4 = asStringLocaleC
"

<primitive: 128>
^ self _primitiveFailed: #_zeroArgPrim:
%

category: 'Truncation and Rounding'
method: DecimalFloat
truncated

"Returns the integer that is closest to the receiver, on the same side
 of the receiver as zero is located.  In particular, returns the receiver
 if the receiver is an integer."

^ self _zeroArgPrim: 0
%

category: 'Truncation and Rounding'
method: DecimalFloat
truncateTo: aNumber

"Returns the multiple of aNumber that is closest to the receiver, on the
 same side of the receiver as zero is located.  In particular, returns
 the receiver if the receiver is a multiple of aNumber."

   "If a signaling NaN, raise a floating point exception"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException ].

   "If a NaN, returns correct sign of self"
((self kind = #signalingNaN) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self _makeQuietNaN ].

aNumber = 0
  ifTrue: [^0]
  ifFalse: [^(self quo: aNumber) * aNumber]
%

category: 'Arithmetic'
method: DecimalFloat
* aNumber

"Returns the result of multiplying the receiver by aNumber."

<primitive: 126>
aNumber _validateClass: Number.
^ self * aNumber asDecimalFloat
%

category: 'Arithmetic'
method: DecimalFloat
+ aNumber

"Returns the sum of the receiver and aNumber."

<primitive: 124>
aNumber _validateClass: Number.
^ self + aNumber asDecimalFloat
%

category: 'Arithmetic'
method: DecimalFloat
- aNumber

"Returns the difference between the receiver and aNumber."

<primitive: 125>
aNumber _validateClass: Number.
^ self - aNumber asDecimalFloat
%

category: 'Arithmetic'
method: DecimalFloat
/ aNumber

"Returns the result of dividing the receiver by aNumber."

<primitive: 127>
aNumber _validateClass: Number.
^ self / aNumber asDecimalFloat
%

category: 'Arithmetic'
method: DecimalFloat
// aNumber

"Divides the receiver by aNumber.  Returns the integer quotient, with
 truncation toward negative infinity.  For example,

 9//4 = 2
 -9//4 = -3
 -0.9//0.4 = -3

 The selector \\ returns the remainder from this division."

   "If a signaling NaN, raise a floating point exception"
(self kind = #signalingNaN)
   ifTrue: [ DecimalFloat _raiseInvalidOperationException ].

   "If a NaN, returns correct sign of self"
((self kind = #signalingNaN) _or: [ self kind = #quietNaN ])
   ifTrue: [ ^self _makeQuietNaN ].

^ (self / aNumber) floor
%

category: 'Arithmetic'
method: DecimalFloat
abs

"Returns a Number that is the absolute value of the receiver."

   "If a NaN, raises invalid operation exception and returns quiet NaN"
((self kind = #signalingNaN) _or: [ self kind = #quietNaN ])
   ifTrue: [ DecimalFloat _raiseInvalidOperationException.
             ^self _makeQuietNaN ].

(self < 0)
   ifTrue: [^self negated].
^self
%

category: 'Arithmetic'
method: DecimalFloat
negated

"Returns a Number that is the negation of the receiver."

^ (0.0F0 - self)
%

category: 'Arithmetic'
method: DecimalFloat
rem: aNumber

"Returns the integer remainder defined in terms of quo: (division of the
 receiver by aNumber, with truncation toward zero)."

  "x rem: y | x=infinity or y=0 are invalid floating point
   operations and returns quiet NaNs"

(aNumber sign = 0) "0.0/0.0 is also invalid"
   ifTrue: [ ^ (aNumber asDecimalFloat) / (aNumber asDecimalFloat)].
(self kind = #infinity) "infinity/infinity is also invalid"
   ifTrue: [ ^ self / self ].
^ super rem: aNumber
%

category: 'Arithmetic'
method: DecimalFloat
sqrt

"Returns the square root of the receiver."

"Reimplemented from Number"

^ self _zeroArgPrim: 3
%

! deleted _idxCompareLessThan: v2.0

! deleted _idxCompareLessThanOrEqual: v2.0

! deleted _idxCompareGreaterThan: v2.0

! deleted _idxCompareGreaterThanOrEqual: v2.0

! deleted _idxCompareForSortEqualTo: v2.0

! deleted _idxCompareEqualTo: v2.0

! deleted _idxCompareNotEqualTo: v2.0

category: 'Indexing Support'
method: DecimalFloat
_isNaN

"Returns whether the receiver is quiet NaN or a signaling NaN.
 This method is only to be used by the indexing subsystem."

^ self _getKind > 4
%

category: 'Accessing'
method: DecimalFloat
_getKind

"Returns an integer, 1...6, for the kind of the receiver."

<primitive: 133>

^ self _primitiveFailed: #_getKind
%

category: 'Testing'
method: DecimalFloat
even

"Returns true if the receiver is an even integer, false otherwise."

 self fractionPart = 0.0F0 ifFalse:[ ^ false ] .
 ^ (self / 2.0F0 ) = 0.0F0
%

category: 'Testing'
method: DecimalFloat
odd

"Returns true if the receiver is an odd integer, false otherwise."

 self fractionPart = 0.0F0 ifFalse:[ ^ false ] .
 ^ (self / 2.0F0 ) ~= 0.0F0
%

category: 'Arithmetic'
classmethod: DecimalFloat
pi

"Returns the value of pi, accurate to twenty decimal places."

^ 3.14159265358979323846F0
%

category: 'Converting'
classmethod: DecimalFloat
fromString: aString

"Returns an instance of DecimalFloat, constructed from aString.  The String
 must contain only Characters representing the object to be created, although
 leading and trailing blanks are permitted.

 The exponent notation, if present may start with any one of $e, $E, $f, or $F."

^ self _oneArgPrim: 2 arg: aString
%

category: 'Converting'
classmethod: DecimalFloat
fromStringLocaleC: aString

"Same as fromString: except that  $.  is always used as the decimal point."

^ self _oneArgPrim: 3 arg: aString
%

category: 'Converting'
method: DecimalFloat
asFloat

"Returns a SmallDouble or Float whose value is represented by the receiver."

 | aString kind |

 kind := self _getKind .
 kind > 2 ifTrue:[
   kind == 4 ifTrue:[ ^ 0.0e0 ] .
   kind == 3 ifTrue:[
     self sign < 0 ifTrue:[ ^ MinusInfinity ]
                  ifFalse:[ ^ PlusInfinity ].
     ].
   kind == 5 ifTrue:[ ^ PlusQuietNaN ].
   ^ PlusSignalingNaN
   ].

 aString := self asString .
 ^ Float fromString: aString
%

category: 'Decompiling without Sources'
method: DecimalFloat
_asSource

""

| result |
result := self asString .
result at: (result indexOf: $E startingAt: 1) put: $F .
^ result
%

category: 'Arithmetic'
method: DecimalFloat
factorial

"Returns the factorial of the integer part of the receiver.
 Returns 1 if the receiver is less than or equal to 1."

| x result |
result := 1.0F0  .
x := result .
self asInteger timesRepeat:[ result := result * x .  x := x + 1.0F0 ] .
^ result .
%

category: 'Storing and Loading'
classmethod: DecimalFloat
loadFrom: passiveObj

"Reads from passiveObj the passive form of an object.  Converts the object to
 its active form by loading the information into a new instance of the receiver.
 Returns the new instance."

| inst |

inst := self fromStringLocaleC:  passiveObj upToSeparator .
passiveObj hasRead: inst.
^inst
%

category: 'Storing and Loading'
method: DecimalFloat
writeTo: passiveObj

"Converts the receiver to its passive form and writes that information on
 passiveObj."

passiveObj writeClass: self class;
      nextPutAll: self asStringLocaleC;
      space
%
