"======================================================================
|
|   Integer Method Definitions
|
|   $Revision: 1.7.5$
|   $Date: 2000/05/28 16:56:52$
|   $Author: pb$
|
 ======================================================================"


"======================================================================
|
| Copyright 1988-92, 1994-95, 1999, 2000 Free Software Foundation, Inc.
| Written by Steve Byrne.
|
| This file is part of the GNU Smalltalk class library.
|
| The GNU Smalltalk class library is free software; you can redistribute it
| and/or modify it under the terms of the GNU Lesser General Public License
| as published by the Free Software Foundation; either version 2.1, or (at
| your option) any later version.
| 
| The GNU Smalltalk class library is distributed in the hope that it will be
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
| General Public License for more details.
| 
| You should have received a copy of the GNU Lesser General Public License
| along with the GNU Smalltalk class library; see the file COPYING.LESSER.
| If not, write to the Free Software Foundation, 59 Temple Place - Suite
| 330, Boston, MA 02111-1307, USA.  
|
 ======================================================================"


Number subclass: #Integer
       instanceVariableNames: ''
       classVariableNames: ''
       poolDictionaries: ''
       category: 'Language-Data types'
!

Integer comment:
'I am the abstract integer class of the GNU Smalltalk system.  My
subclasses'' instances can represent signed integers of various
sizes (a subclass is picked according to the size), with varying
efficiency.' !


!Integer class methodsFor: 'converting'!

coerce: aNumber
    "Answer aNumber converted to a kind of Integer"
    ^aNumber truncated
! !


!Integer methodsFor: 'Misc math operators'!

hash
    "Answer an hash value for the receiver"
    ^self
! !



!Integer methodsFor: 'Other iterators'!

timesRepeat: aBlock
    "Evaluate aBlock a number of times equal to the receiver's value.
     Compiled in-line for no argument aBlocks without temporaries, and
     therefore not overridable."
    1 to: self do: [ :each | aBlock value ]
! !



!Integer methodsFor: 'bit operators'!

bitAt: index
    "Answer the index-th bit of the receiver (LSB: index = 1"
    ^(self bitShift: (index - 1) negated) bitAnd: 1
!

bitInvert
    "Return the 1's complement of the bits of the receiver"
    ^self bitXor: -1
!

bitClear: aMask 
    "Answer an Integer equal to the receiver, except that all the bits
     that are set in aMask are cleared."

    ^(self bitOr: aMask) bitXor: aMask
!

allMask: anInteger
    "True if all 1 bits in anInteger are 1 in the receiver"
    ^(self bitAnd: anInteger) = anInteger
!

anyMask: anInteger
    "True if any 1 bits in anInteger are 1 in the receiver"
    ^(self bitAnd: anInteger) ~= 0
!

clearBit: index
    "Clear the index-th bit of the receiver and answer a new Integer"
    | bit |
    bit := 1 bitShift: (index - 1).
    ^(self bitOr: bit) bitXor: bit
!

noMask: anInteger
    "True if no 1 bits in anInteger are 1 in the receiver"
    ^(self bitAnd: anInteger) = 0
!

highBit
    "Return the index of the highest order 1 bit of the receiver"
    self = 0 ifTrue: [ ^0 ].

    "??? I don't know what the right value is"
    self < 0 ifTrue: [ ^self negated highBit + 1 ].
    30 to: 0 by: -1 do:
    	[ :i | (self bitAnd: (1 bitShift: i)) ~= 0 ifTrue: [ ^i ] ]
!

isBitSet: index
    "Answer whether the index-th bit of the receiver is set"
    ^((self bitShift: (index - 1) negated) bitAnd: 1) == 1
!

setBit: index
    "Set the index-th bit of the receiver and answer a new Integer"
    ^self bitOr: (1 bitShift: (index - 1))
! !



!Integer methodsFor: 'Math methods'!

factorial
    "Return the receiver's factorial"
    | result |

    self < 0 ifTrue: [ ^self error: 'factorial of a negative number' ].

    result := 1.
    2 to: self do: [ :i | result := result * i ].
    ^result
!

estimatedLog
    "Answer an estimate of (self abs floorLog: 10)"
    ^(self highBit asFloat / Float log10Base2) ceiling
!

floorLog: radix
    "return (self log: radix) floor. Optimized to answer an integer."

    | me answer |

    self < self zero ifTrue: [
       ^self error: 'cannot extract logarithm of a negative number'
    ].

    radix <= radix unity ifTrue: [
	(radix <= radix zero) ifTrue: [ ^self error: 'bad radix' ].
	(radix = radix unity) ifTrue: [ ^self error: 'bad radix' ].
	^(self floorLog: radix reciprocal) negated
    ].
    radix isInteger ifFalse: [
	^(self coerce: radix) floorLog: radix
    ].

    me := self.
    answer := 0.
    [   me >= radix ] whileTrue: [
	me := me // radix.
	answer := answer + 1
    ].
    ^answer
!

gcd: anInteger
    "Return the greatest common divisor (Euclid's algorithm) between the
     receiver and anInteger"
    | a b remainder |
    self negative | anInteger negative ifTrue: [ ^self abs gcd: anInteger abs ].

    self < anInteger
	ifTrue: [ a := anInteger. b := self ]
	ifFalse: [ a := self. b := anInteger ].
    [ b = 0 ] whileFalse: [
	remainder := a \\ b.
	a := b.
	b := remainder. ].
    ^a
!

lcm: anInteger
    "Return the least common multiple between the receiver and anInteger"
    ^((self // (self gcd: anInteger)) * anInteger) abs
!

even
    "Return whether the receiver is even"
    ^(self bitAt: 1) = 0
!

odd
    "Return whether the receiver is odd"
    ^(self bitAt: 1) ~= 0
! !



!Integer methodsFor: 'Coercion methods (heh heh heh)'!

asCharacter
    "Return self as an ascii character"
    ^Character value: self
!

coerce: aNumber
    "Coerce aNumber to the receiver's class"
    ^aNumber truncated
!

ceiling
    "Return the receiver - it's already truncated"
    ^self
!

floor
    "Return the receiver - it's already truncated"
    ^self
!

truncated
    "Return the receiver - it's already truncated"
    ^self
!

rounded
    "Return the receiver - it's already truncated"
    ^self
! !



!Integer methodsFor: 'converting'!

asFraction
    "Return the receiver converted to a fraction"
    ^Fraction numerator: self denominator: 1
! !



!Integer methodsFor: 'printing'!

printOn: aStream base: b
    "Print on aStream the base b representation of the receiver"
    self signedStringBase: b showRadix: false on: aStream
!

storeOn: aStream base: b
    "Print on aStream Smalltalk code compiling to the receiver, 
     represented in base b"
    self signedStringBase: b showRadix: true on: aStream
!

radix: baseInteger
    "Return the base b representation of the receiver, with BBr in
     front of it"
    | str |
    str := WriteStream on: (String new: 10).
    self signedStringBase: baseInteger showRadix: true on: str.
    ^str contents
!

printString: baseInteger
    "Return the base b representation of the receiver"
    | str |
    str := WriteStream on: (String new: 10).
    self signedStringBase: baseInteger showRadix: false on: str.
    ^str contents
!

printOn: aStream
    "Print on aStream the base 10 representation of the receiver"
    self signedStringBase: 10 showRadix: false on: aStream
! !



!Integer methodsFor: 'storing'!

storeOn: aStream
    "Print on aStream the base 10 representation of the receiver"
    self printOn: aStream		"they print and store the same"
! !



!Integer methodsFor: 'private'!

signedStringBase: radix showRadix: showRadix on: str
    "Append to str the base baseInteger representation of the receiver"
    | sign num revStr |
    sign := (self sign = -1).
    num := sign ifTrue: [ self negated ] ifFalse: [ self ].

    showRadix ifTrue:
    	[ radix printOn: str.
	  str nextPut: $r ].
    sign ifTrue: [ str nextPut: $- ].

    revStr := WriteStream on: (String new: 8).
    num reverseStringBase: radix on: revStr.
    revStr contents reverseDo: [ :each | str nextPut: each ].
!

reverseStringBase: b on: revStr
    "Print on str the reversed base b representation of the receiver
     (which is > 0)"

    | num |
    self = 0 ifTrue: [ revStr nextPut: $0. ^1 ].

    num := self.
    [ num = 0 ] whileFalse:
    	[ revStr nextPut: (Character digitValue: (num \\ b)).
	  num := num // b ].

    ^revStr size
! !


!Integer methodsFor: 'testing functionality'!

isRational
    "Answer whether the receiver is rational - true"
    ^true
!

isInteger
    ^true
! !



!Integer methodsFor: 'accessing'!

numerator
    ^self
!

denominator
    ^1
! !