!=========================================================================
! Copyright (C) VMware, Inc. 1986-2011.  All Rights Reserved.
!
! $Id: number.gs,v 1.20 2008-01-09 22:50:12 stever Exp $
!
! Superclass Hierarchy:
!   Number, Magnitude, Object.
!
!=========================================================================

removeallmethods Number
removeallclassmethods Number

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

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

txt := (GsDocText new) details:
'Number is an abstract superclass that establishes protocol for all GemStone
 Smalltalk numbers.  Concrete subclasses include Float, SmallInteger, and
 Fraction.'.
doc documentClassWith: txt.

txt := (GsDocText new) details:
'You may not create new instances of Number.'.
doc documentCategory: #'Instance Creation' with: txt.

txt := (GsDocText new) details:
'When using any of the methods in this category, your GemStone Smalltalk code
 will run more efficiently when the argument is a literal block (enclosed in
 square brackets), rather than a variable.  For more information about blocks,
 see the GemStone Programming Guide.'.
doc documentCategory: #'Flow of Control' with: txt.

self description: doc.
%

category: 'Instance Creation'
classmethod: Number
new

"Disallowed."

"The following is a kludge for doing Fraction [C] | new until such time that
 private methods for instance creation are installed for all numerical
 classes."

(self == Fraction)
   ifFalse: [ self shouldNotImplement: #new ]
   ifTrue: [ ^super new ]
%

category: 'Instance Creation'
classmethod: Number
migrateNew

"Override default migrateNew behavior with #_basicNew."

^ self _basicNew
%

category: 'Instance Creation'
classmethod: Number
new: anInteger

"Disallowed."

self shouldNotImplement: #new:
%

category: 'Error Handling'
method: Number
_errorDivideByZero

"Generates a divide by 0 error."

^ self _error: #numErrIntDivisionByZero
%

category: 'Accessing'
method: Number
denominator

"(Subclass responsibility.)  Returns the denominator of a Fraction representing
 the receiver."

Number subclassResponsibility: #denominator
%

category: 'Accessing'
method: Number
numerator

"(Subclass responsibility.)  Returns the numerator of a Fraction representing
 the receiver."

Number subclassResponsibility: #numerator
%

category: 'Accessing'
method: Number
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 > 0)
   ifTrue: [^1].
(self < 0)
   ifTrue: [^-1].
^0
%

category: 'Testing'
method: Number
negative

"Returns true if the receiver is less than zero, false if the receiver is zero
 or greater."

^self < 0
%

category: 'Testing'
method: Number
positive

"Returns true if the receiver is greater than or equal to zero, false if the
 receiver is less than zero."

^self >= 0
%

category: 'Testing'
method: Number
strictlyPositive

"Returns true if the receiver is greater than zero and false if it is less than
 or equal to zero."

^ self > 0
%

category: 'Converting'
method: Number
asDecimalFloat

"(Subclass responsibility.)  Returns a DecimalFloat representing the receiver."

Number subclassResponsibility: #asDecimalFloat

%

category: 'Converting'
method: Number
asFloat

"(Subclass responsibility.)  Returns a SmallDouble or Float representing the receiver."

Number subclassResponsibility: #asFloat
%

category: 'Converting'
method: Number
asSmallFloat

"SmallFloat is deprecated.
 This method returns a SmallDouble or Float equal to the receiver."

^ self asFloat 
%

category: 'Converting'
method: Number
asScaledDecimal: scale

"Returns a ScaledDecimal representing the receiver."

^ self asFraction asScaledDecimal: scale.
%

category: 'Converting'
method: Number
asFraction

"(Subclass responsibility.)  Returns a Fraction that represents the receiver."

Number subclassResponsibility: #asFraction
%

category: 'Converting'
method: Number
asInteger

"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 truncated
%

category: 'Converting'
method: Number
_coerce: aNumber

"(Subclass responsibility.)  Returns aNumber as an instance of the class of the
 receiver, or an instance of any subclass of the receiver.  This method must be
 defined by all subclasses of Number."

Number subclassResponsibility: #_coerce
%

category: 'Converting'
method: Number
_generality

"(Subclass responsibility.)  Returns the integer that represents the ordering
 of the receiver in the generality hierarchy."

"     Class           result of _generality
	SmallInteger     20
	Integer		 40
        ScaledDecimal    60
	Fraction 	 70
	SmallFloat       80
        SmallDouble      85
        Float            90
	DecimalFloat 	100
"

Number subclassResponsibility: #_generality
%

category: 'Converting'
method: Number
_retry: aSelector coercing: aNumber

"A difference in representation between the receiver and aNumber has prevented
 aSelector from being executed.  Coerce either the receiver or aNumber to the
 higher of their generalities and attempt to execute the method represented by
 aSelector again."

"This is the basis of the type coercion logic for all Numbers."
| gen argGen |
aSelector == #= ifTrue:[
  (aNumber isKindOf: Number) ifFalse:[
    ^false
  ]
] ifFalse:[
  aSelector == #~=  ifTrue:[
    (aNumber isKindOf: Number) ifFalse:[
      ^true
    ]
  ]
].
gen := self _generality .
argGen := aNumber _generality .
(gen < argGen ) ifTrue: [
  ^ (aNumber _coerce: self) perform: aSelector with: aNumber
].
(gen > argGen ) ifTrue: [
  ^self perform: aSelector with: (self _coerce: aNumber)
].
self _uncontinuableError.  "coercion failed"
%

category: 'Truncation and Rounding'
method: Number
ceiling

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

"the actual implementation of this method is in bomlast.gs"

 self _uncontinuableError
%

category: 'Truncation and Rounding'
method: Number
floor

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

|result|

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

category: 'Truncation and Rounding'
method: Number
rounded

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

^(self + (self sign / 2)) truncated
%

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

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

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

category: 'Truncation and Rounding'
method: Number
truncated

"(Subclass responsibility.)  Returns the integer nearest in value to
 the receiver, in the direction toward zero."

Number subclassResponsibility: #truncated
%

category: 'Truncation and Rounding'
method: Number
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."

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

category: 'Arithmetic'
method: Number
* aNumber

"(Subclass responsibility.)  Returns the result of multiplying the receiver by
 aNumber."

Number subclassResponsibility: #*
%

category: 'Arithmetic'
method: Number
+ aNumber

"(Subclass responsibility.)  Returns the sum of the receiver and aNumber."

Number subclassResponsibility: #+
%

category: 'Arithmetic'
method: Number
- aNumber

"(Subclass responsibility.)  Returns the difference between the receiver and
 aNumber."

Number subclassResponsibility: #-
%

category: 'Arithmetic'
method: Number
/ aNumber

"(Subclass responsibility.)  Returns the result of dividing the receiver by
 aNumber."

Number subclassResponsibility: #/
%

category: 'Arithmetic'
method: Number
// 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."

^ (self / aNumber) floor
%

category: 'Arithmetic'
method: Number
abs

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

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

category: 'Arithmetic'
method: Number
negated

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

^0 - self
%

category: 'Arithmetic'
method: Number
quo: aNumber

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

 -9 quo: 4 = -2
 -0.9 quo: 0.4 = -2

 The selector rem: returns the remainder from this division."

^(self / aNumber) truncated
%

category: 'Arithmetic'
method: Number
reciprocal

"Returns 1 divided by the receiver.  Generates an error if the receiver is 0."

(self = 0)
    ifTrue:[^self _errorDivideByZero].  "division by zero error"
^ 1 / self
%

category: 'Arithmetic'
method: Number
rem: aNumber

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

^ (self - ((self quo: aNumber) * aNumber)) truncated
%

category: 'Arithmetic'
method: Number
\\ aNumber

"Returns the modulo remainder defined in terms of //.  Returns a Number with
 the same sign as the argument aNumber.  For example,

 9 \\ 4 = 1
 -9 \\ 4 = 3
 9 \\ -4 = -3
 0.9 \\ 0.4 = 0.1"

^ self - (self // aNumber * aNumber)
%

category: 'Backward Compatibility'
method: Number
_sqrt

"For compatibility with GemStone 3.2"

^ self sqrt
%

category: 'Arithmetic'
method: Number
squared

"Returns the multiplicative product of the receiver and itself."

^ self * self
%

category: 'Testing'
method: Number
even

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

^self \\ 2 == 0
%

category: 'Testing'
method: Number
odd

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

^ self even == false
%

category: 'Arithmetic'
method: Number
sqrt

"Returns the square root of the receiver.  This method currently returns a
 Float.  This will eventually change, so that exact squares of Integers and
 Fractions return Integers and Fractions, for instance."

^ self asFloat sqrt
%

category: 'Formatting'
method: Number
printString

"Returns a String whose contents are a displayable representation of the
 receiver."

^self asString
%

category: 'Formatting'
method: Number
printOn: aStream

"Appends a printable representation of the receiver to aStream and returns 
 the receiver."

aStream nextPutAll: (self asString).
^ self.
%

! deleted _idxCompareLessThan: v2.0

! deleted _idxCompareLessThanOrEqual: v2.0

! deleted _idxCompareGreaterThan: v2.0

! deleted _idxCompareGreaterThanOrEqual: v2.0

category: 'Indexing Support'
method: Number
_isNaN

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

^ false
%

category: 'Arithmetic'
method: Number
ln

"Returns the natural logarithm of the receiver."

^ self asFloat ln
%

category: 'Arithmetic'
method: Number
log: x

"Returns the base x logarithm of the receiver."

^ self ln / x ln
%

category: 'Arithmetic'
method: Number
floorLog: x

"Returns an Integer that is the floor of the receiver's log base x."

^ (self log: x) floor.
%

category: 'Arithmetic'
method: Number
exp

"Returns e raised to the power of the receiver."

^ self asFloat exp
%

category: 'Arithmetic'
method: Number
arcCos

"Returns the arc-cosine of the receiver in radians."

^ self asFloat arcCos
%

category: 'Arithmetic'
method: Number
arcSin

"Returns the arc-sine of the receiver in radians."

^ self asFloat arcSin
%

category: 'Arithmetic'
method: Number
arcTan

"Returns the arc-tangent of the receiver in radians."

^ self asFloat arcTan
%

category: 'Arithmetic'
method: Number
cos

"Returns the cosine of the receiver which is treated as an
 angle expressed in radians."

^ self asFloat cos
%

category: 'Arithmetic'
method: Number
sin

"Returns the sine of the receiver which is treated as an
 angle expressed in radians."

^ self asFloat sin
%

category: 'Arithmetic'
method: Number
tan

"Returns the tangent of the receiver which is treated as an
 angle expressed in radians."

^ self asFloat tan
%

category: 'Arithmetic'
method: Number
degreesToRadians

"Assuming the receiver represents an angle in degrees, returns
 the angle in radians."

"The actual implementation of this method is in bomlast.gs"

self _uncontinuableError
%

category: 'Arithmetic'
method: Number
radiansToDegrees

"Assuming the receiver represents an angle in radians, returns
 the angle in degrees."

"The actual implementation of this method is in bomlast.gs"

self _uncontinuableError
%

category: 'Arithmetic'
method: Number
raisedTo: aNumber

"Returns the receiver raised to the power of the argument."

^ self asFloat raisedTo: aNumber
%

category: 'Arithmetic'
method: Number
raisedToInteger: aNumber

"Returns the receiver raised to the power of the argument.
 aNumber must be a kind of Integer."

| prod |
(aNumber isKindOf: Integer) ifFalse:[
  aNumber _validateClass: Integer
].
prod := 1 .
aNumber abs timesRepeat:[
  prod := prod * self .
].
aNumber < 0 ifTrue:[
 prod := 1 / prod
].
^ prod
%


! radiansToDegrees,

category: 'Accessing'
method: Number
_getKind

"Returns the kind of the receiver based on the list in Number/kind.  Only floats
 have a kind other than 1."

^ 1
%

category: 'Accessing'
method: Number
kind

"Returns a Symbol from the following list:

   #normal
   #subnormal
   #infinity
   #zero
   #quietNaN
   #signalingNaN

 The symbol tells what kind of floating-point number the receiver is.
 Refer to IEEE standards 754 and 854 for more information.  Numbers that
 are not instances of a floating point class are always normal."

^Number _kindList at: (self _getKind)
%

category: 'Private'
classmethod: Number
_kindList

""

"   1       2          3          4      5              6 "
^ #(#normal #subnormal #infinity #zero #quietNaN #signalingNaN)
%

category: 'Decompiling without Sources'
method: Number
_asSource

""

^ self asString
%

category: 'Comparing'
method: Number
hash

"Returns a SmallInteger related to the value of the receiver."

"Two Numbers for which = is true, must have the same hash value."

"This method should be reimplemented in Float and SmallInteger."

^ self asFloat hash
%

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

"Converts the receiver to its passive form and writes that information on
 passiveObj."
    
passiveObj nextPutAll: self describe.
passiveObj space
%

category: 'Flow of Control'
method: Number
downTo: aNumber
by: stepValue
do: aBlock

"Iteratively evaluates the one-argument block aBlock, using the block's single
 argument as the iteration control variable.  Initially, that control variable
 is set to the receiver.  The argument stepValue must be a strictly positive
 kind of Integer, and aNumber must be a kind of Integer.

 The block is evaluated while the control variable is greater than or equal to
 aNumber.  After each evaluation, the control variable is decremented by
 stepValue.  If the receiver is less than aNumber, the block is not evaluated
 at all.  Returns the receiver."

| j |
j := self .
stepValue > 0 ifFalse:[ stepValue _error: #rtErrArgNotPositive ].
[ j >= aNumber ] whileTrue:[ 
   aBlock value: j . 
   j := j - stepValue 
   ] 
%

category: 'Flow of Control'
method: Number
downTo: aNumber
do: aBlock

"Iteratively evaluates the one-argument block aBlock, using the block's single
 argument as the iteration control variable.  Initially, that control variable
 is set to the receiver.  The block is evaluated while the control variable is
 greater than or equal to aNumber (which must be a kind of Integer).  After each
 evaluation, the control variable is decremented by 1.  If the receiver is less
 than aNumber, the block is not evaluated at all.  Returns the receiver."

self downTo: aNumber by: 1 do: aBlock
%

category: 'Flow of Control'
method: Number
timesRepeat: aBlock

"(Reserved selector.)  If the receiver is greater than zero, evaluates the
 zero-argument block aBlock the number of times represented by the receiver.
 (If the receiver is zero or negative, aBlock is not executed.).

 A method which sends timesRepeat: will have a step point generated for
 the send of the timesRepeat:  and a step point for the loop index increment
 and test instructions."

"The following is a control structure optimization, not a recursive send."

self timesRepeat: [aBlock value]
%

category: 'Flow of Control'
method: Number
to: aNumber by: stepValue do: aBlock

"(Reserved selector.)  Iteratively evaluates the one-argument block aBlock,
 using the block's single argument as the iteration control variable.
 Initially, that control variable is set to the receiver.  The argument
 stepValue must be a strictly positive kind of Integer, and aNumber must be a
 kind of Integer.

 The block is evaluated while the control variable is less than or equal to
 aNumber.  After each evaluation, the control variable is incremented by
 stepValue.  If the receiver is greater than aNumber, the block is not
 evaluated at all.  Returns the receiver.

 A method which sends to:by:do: will have a step point generated for the send of
 the to:by:do: and a step point for the loop index increment and test."

"The following is a control structure optimization, not a recursive send."

self to: aNumber
     by: stepValue
     do: [:i | aBlock value: i]
%

category: 'Intervals'
method: Number
to: aNumber by: stepValue

"Returns an Interval for the numbers between the receiver and aNumber, where 
 each number is the previous number plus stepValue."

^ Interval from: self to: aNumber by: stepValue.
%

category: 'Flow of Control'
method: Number
to: aNumber do: aBlock

"(Reserved selector.)  Iteratively evaluates the one-argument block aBlock,
 using the block's single argument as the iteration control variable.
 Initially, that control variable is set to the receiver.  The block is
 evaluated while the control variable is less than or equal to aNumber (which
 must be a kind of Integer).  After each evaluation, the control variable is
 incremented by 1.  If the receiver is greater than aNumber, the block is not
 evaluated at all.  Returns the receiver.

 A method which sends to:do: will have a step point generated for the send of
 the to:do: and a step point for the loop index increment and test."

"The following is a control structure optimization, not a recursive send."

self to: aNumber
     do: [:i | aBlock value: i]
%

category: 'Intervals'
method: Number
to: aNumber

"Returns an Interval for the numbers between the receiver and aNumber, where 
 each number is the previous number plus 1."

^ Interval from: self to: aNumber.
%

category: 'Generality'
method: Number
moreGeneralThan: anOperand

"Returns true if the receiver has higher generality than anOperand, 
 false otherwise."

^ self _generality > anOperand _generality
%

category: 'Generality'
method: Number
lessGeneralThan: anOperand

"Returns true if the receiver has lower generality than anOperand, 
 false otherwise."

^ self _generality < anOperand _generality
%

category: 'New Indexing Comparison'
method: Number
_classSortOrdinal

^ 90
%
category: 'New Indexing Comparison'
method: Number
_idxForCompareEqualTo: arg

""

^arg _idxForCompareEqualToNumber: self
%
category: 'New Indexing Comparison'
method: Number
_idxForSortEqualTo: arg

""

^arg _idxForSortEqualToNumber: self
%
category: 'New Indexing Comparison'
method: Number
_idxForSortGreaterThan: arg

""

^arg _idxForSortNumberGreaterThanSelf: self
%
category: 'New Indexing Comparison'
method: Number
_idxForSortGreaterThanOrEqualTo: arg

""

^arg _idxForSortNumberGreaterThanOrEqualToSelf: self
%
category: 'New Indexing Comparison'
method: Number
_idxForSortLessThan: arg

""

^arg _idxForSortNumberLessThanSelf: self
%
category: 'New Indexing Comparison'
method: Number
_idxForSortLessThanOrEqualTo: arg

""

^arg _idxForSortNumberLessThanOrEqualToSelf: self
%

category: 'New Indexing Comparison'
method: Number
_idxForSortNotEqualTo: arg

""

^arg _idxForSortNotEqualToNumber: self
%

category: 'New Indexing Comparison - for Sort'
method: Number
_idxForSortEqualToNumber: aNumber

""

( self _isNaN _and: [ aNumber _isNaN ] ) ifTrue: [ ^ true ].
^ self = aNumber
%
category: 'New Indexing Comparison - for Sort'
method: Number
_idxForSortNumberGreaterThanOrEqualToSelf: aNumber

""

( self _isNaN _and: [ aNumber _isNaN ] ) ifTrue: [ ^ true ].
aNumber _isNaN ifTrue: [ ^ true ].
self _isNaN ifTrue: [ ^ false ].
^aNumber >= self
%
category: 'New Indexing Comparison - for Sort'
method: Number
_idxForSortNumberGreaterThanSelf: aNumber

""

( self _isNaN _and: [ aNumber _isNaN ] ) ifTrue: [ ^ false ].
aNumber _isNaN ifTrue: [ ^ true ].
self _isNaN ifTrue: [ ^ false ].
^aNumber > self
%
category: 'New Indexing Comparison - for Sort'
method: Number
_idxForSortNumberLessThanOrEqualToSelf: aNumber

""

( self _isNaN _and: [ aNumber _isNaN ] ) ifTrue: [ ^ true ].
aNumber _isNaN ifTrue: [ ^ false ].
self _isNaN ifTrue: [ ^ true ].
^aNumber <= self
%
category: 'New Indexing Comparison - for Sort'
method: Number
_idxForSortNumberLessThanSelf: aNumber

""

( self _isNaN _and: [ aNumber _isNaN ] ) ifTrue: [ ^ false ].
aNumber _isNaN ifTrue: [ ^ false ].
self _isNaN ifTrue: [ ^ true ].
^aNumber < self
%

category: 'New Indexing Comparison - for Sort'
method: Number
_idxForSortNotEqualToNumber: aNumber

""

( self _isNaN _and: [ aNumber _isNaN ] ) ifTrue: [ ^ false ].
^ self ~= aNumber
%

category: 'New Indexing Comparison - for Compare'
method: Number
_idxForCompareEqualToNumber: aNumber

""

^aNumber = self
%

! REMINDER: you must filein bomlast.gs to get methods with float literals

