Number.st
author claus
Mon, 08 May 1995 05:31:14 +0200
changeset 339 e8658d38abfb
parent 329 f14fc5ac11b7
child 345 cf2301210c47
permissions -rw-r--r--
.

"
 COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

ArithmeticValue subclass:#Number
       instanceVariableNames:''
       classVariableNames:''
       poolDictionaries:''
       category:'Magnitude-Numbers'
!

Number comment:'
COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

$Header: /cvs/stx/stx/libbasic/Number.st,v 1.16 1995-05-08 03:29:56 claus Exp $
'!

!Number class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

version
"
$Header: /cvs/stx/stx/libbasic/Number.st,v 1.16 1995-05-08 03:29:56 claus Exp $
"
!

documentation
"
    abstract superclass for all kinds of numbers
"
! !

! Number methodsFor:'coercing & converting'!

@ aNumber
    "return a Point with the receiver as x-coordinate and the argument
     as y-coordinate"

%{  /* NOCONTEXT */

    /*
     * I cannot tell if this special code is worth anything
     */
    if (_CanDoQuickNew(sizeof(struct __point))) {
	OBJ newPoint;
	int spc;

	_qCheckedAlignedNew(newPoint, sizeof(struct __point));
	_InstPtr(newPoint)->o_class = Point;
	_PointInstPtr(newPoint)->p_x = self;
	_PointInstPtr(newPoint)->p_y = aNumber;
	spc = __qSpace(newPoint);
	__STORE_SPC(newPoint, aNumber, spc);
	__STORE_SPC(newPoint, self, spc);
	RETURN ( newPoint );
    }
%}
.
    ^ Point x:self y:aNumber
!

asPoint
    "return a new Point with the receiver as all coordinates;  
     often used to supply the same value in two dimensions, as with 
     symmetrical gridding or scaling."

%{  /* NOCONTEXT */

    if (_CanDoQuickNew(sizeof(struct __point))) {
	OBJ newPoint;

	_qCheckedAlignedNew(newPoint, sizeof(struct __point));
	_InstPtr(newPoint)->o_class = Point;
	_PointInstPtr(newPoint)->p_x = self;
	_PointInstPtr(newPoint)->p_y = self;
	__STORE(newPoint, self);
	RETURN ( newPoint );
    }
%}
.
    ^ Point x:self y:self
!

degreesToRadians
    "interpreting the receiver as radians, return the degrees"

    ^ (self * (Float pi)) / 180.0
!

radiansToDegrees
    "interpreting the receiver as degrees, return the radians"

    ^ (self * 180.0) / (Float pi)
!

coerce:aNumber
    "return aNumber converted into receivers type"

    ^ self subclassResponsibility
!

generality
    "return the generality value - see ArithmeticValue>>retry:coercing:"

    ^ 40
!

retry:aSymbol coercing:aNumber
    "Arithmetic represented by the binary operator, aSymbol,
    could not be performed with the receiver and the argument,
    aNumber, because of the differences in representation.  Coerce either
    the receiver or the argument, depending on which has higher generality, and
    try again.  If the operation is comapre for same value (=), return false if
    the argument is not a Number. 
    If the generalities are the same, create an error message."

    |myGenerality otherGenerality|

    (aSymbol == #=) ifTrue:[
	(aNumber respondsTo:#generality) ifFalse:[^ false]
    ] ifFalse:[
	(aNumber respondsTo:#generality) ifFalse:[
	    self error:'retry:coercing: argument is not a number'.
	    ^ self
	]
    ].
    myGenerality := self generality.
    otherGenerality := aNumber generality.
    (myGenerality > otherGenerality) ifTrue:[
	^ self perform:aSymbol with:(self coerce:aNumber)
    ].
    (myGenerality < otherGenerality) ifTrue:[
	^ (aNumber coerce:self) perform:aSymbol with:aNumber
    ].
    self error:'retry:coercing: oops - same generality'
! !

!Number methodsFor:'testing'!

isLiteral
    "return true, if the receiver can be used as a literal
     (i.e. can be used in constant arrays)"

    ^ true
!

isNumber
    "return true, if the receiver is a kind of number"

    ^ true
!

isZero
    ^ self = 0
! !

!Number methodsFor:'printing & storing'!

storeString
    "return a string for storing 
     - since numbers are literals, they store as they print."

    ^ self printString
!

storeOn:aStream
    "append a string for storing the receiver onto the argument,
     aStream - since numbers are literals,they store as they print."

    ^ self printOn:aStream
! !

!Number methodsFor:'intervals'!

to:stop
    "return an interval from receiver up to the argument, incrementing by 1"

    ^ Interval from:self to:stop
!

to:stop by:step
    "return an interval from receiver up to the argument, incrementing by step"

    ^ Interval from:self to:stop by:step
! !

!Number methodsFor:'iteration'!

timesRepeat:aBlock
    "evaluate the argument, aBlock self times"

    |count|

    count := self.
    [count > 0] whileTrue:[
	aBlock value.
	count := count - 1
    ]
!

to:stop do:aBlock
    "For each element of the interval from the receiver up to the argument stop,
     evaluate aBlock, passing the number as argument."

    |tmp|

    tmp := self.
    [tmp <= stop] whileTrue:[
	aBlock value:tmp.
	tmp := tmp+1
    ]
!

to:stop by:incr do:aBlock
    "For each element of the interval from the receiver up to the argument stop, incrementing
     by step, evaluate aBlock passing the element as argument."

    |tmp|

    tmp := self.
    (incr > 0) ifTrue:[
	[tmp <= stop] whileTrue:[
	    aBlock value:tmp.
	    tmp := tmp+incr
	]
    ] ifFalse:[
	[tmp >= stop] whileTrue:[
	    aBlock value:tmp.
	    tmp := tmp+incr
	]
    ]
! !

!Number class methodsFor:'private'!

readMantissaFrom:aStream radix:radix
    "helper for readFrom: -
     return the mantissa from the (character-)stream aStream;
     no whitespace-skipping; error if no number available"

    |nextChar value factor|

    value := 0.0.
    factor := 1.0 / radix.
    nextChar := aStream peek.
    [nextChar notNil and:[nextChar isDigitRadix:radix]] whileTrue:[
	value := value + (nextChar digitValue * factor).
	factor := factor / radix.
	nextChar := aStream nextPeek
    ].
    ^ value
! !

!Number class methodsFor:'instance creation'!

readFrom:aStream onError:exceptionBlock
    "return the next Number from the (character-)stream aStream;
     skipping all whitespace first; return the value of exceptionBlock,
     if no number can be read."

    |nextChar radix value negative signExp freakOut|

    Object errorSignal handle:[:ex |
	^ exceptionBlock value
    ] do:[
	nextChar := aStream skipSeparators.
	nextChar isNil ifTrue:[^ exceptionBlock value].

	freakOut := [^ exceptionBlock value].

	(nextChar == $-) ifTrue:[
	    negative := true.
	    nextChar := aStream nextPeek
	] ifFalse:[
	    negative := false.
	    (nextChar == $+) ifTrue:[
		nextChar := aStream nextPeek
	    ]
	].
	nextChar isDigit ifFalse:[
	    ^ exceptionBlock value.
"/          value := super readFrom:aStream.
"/          negative ifTrue:[value := value negated].
"/          ^ value
	].
	value := Integer readFrom:aStream radix:10 onError:freakOut.
	nextChar := aStream peek.
	((nextChar == $r) or:[ nextChar == $R]) ifTrue:[
	    aStream next.
	    radix := value.
	    value := Integer readFrom:aStream radix:radix onError:freakOut.
	] ifFalse:[
	    radix := 10
	].
	(nextChar == $.) ifTrue:[
	    nextChar := aStream nextPeek.
	    (nextChar notNil and:[nextChar isDigitRadix:radix]) ifTrue:[
		value := value asFloat 
			 + (Number readMantissaFrom:aStream radix:radix).
		nextChar := aStream peek
	    ]
	].
	((nextChar == $e) or:[nextChar == $E]) ifTrue:[
	    nextChar := aStream nextPeek.
	    signExp := 1.
	    (nextChar == $+) ifTrue:[
		nextChar := aStream nextPeek
	    ] ifFalse:[
		(nextChar == $-) ifTrue:[
		    nextChar := aStream nextPeek.
		    signExp := -1
		]
	    ].
	    (nextChar notNil and:[(nextChar isDigitRadix:radix)]) ifTrue:[
		value := value asFloat 
			 * (10.0 raisedToInteger:
				    ((Integer readFrom:aStream radix:radix onError:freakOut) * signExp))
	    ]
	].
	negative ifTrue:[
	    ^ value negated
	].
	^ value
    ]

    "
     Number readFrom:(ReadStream on:'54.32e-01')      
     Number readFrom:(ReadStream on:'12345678901234567890') 
     Number readFrom:(ReadStream on:'16rAAAAFFFFAAAAFFFF') 
     '+00000123.45' asNumber  
    "
!

readSmalltalkSyntaxFrom:aStream
    "ST-80 compatibility (thanks to a note from alpha testers)
     read and return the next Number in smalltalk syntax from the 
     (character-)stream aStream."

    ^ Compiler evaluate:aStream compile:false "/ self readFrom:aStream.

    "
     Number readSmalltalkSyntaxFrom:(ReadStream on:'54.32e-01')    
     Number readSmalltalkSyntaxFrom:(ReadStream on:'12345678901234567890')
     Number readSmalltalkSyntaxFrom:(ReadStream on:'16rAAAAFFFFAAAAFFFF')
     Number readSmalltalkSyntaxFrom:(ReadStream on:'(1/10)') 
     Number readFrom:(ReadStream on:'(1/10)') 
     Number readSmalltalkSyntaxFrom:(ReadStream on:'+00000123.45')  
     Number readFrom:(ReadStream on:'+00000123.45')  
    "
! !