"======================================================================
|
|   Float 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 variableByteSubclass: #Float
       instanceVariableNames: ''
       classVariableNames: ''
       poolDictionaries: ''
       category: 'Language-Data types'
!

Float comment: 
'My instances represent floating point numbers that have 64 bits of 
precision (well, less than that in precision; they are precisely the same
as C''s "double" datatype).  Besides the standard numerical operations,
I provide transcendental operations too.'  !


!Float class methodsFor: 'converting'!

coerce: aNumber
    "Answer aNumber converted to a Float"
    ^aNumber asFloat
! !


!Float class methodsFor: 'byte-order dependancies'!

leastSignificantMantissaByte
    "Answer the least significant byte in the receiver among those that
     contain the mantissa"
    ^Bigendian ifTrue: [ 2 ] ifFalse: [ 7 ]
!

exponentByte
    "Answer the byte of the receiver that contains the exponent"
    ^Bigendian ifTrue: [ 1 ] ifFalse: [ 8 ]
! !


!Float class methodsFor: 'basic'!

e
    "Returns the value of e. Hope is that it is precise enough"
    ^2.7182818284590452353602874713527
!

mantissaBits
    "Answer the number of bits in the mantissa. 1 + (2^-mantissaBits) = 1"
    ^53
!

smallestAbs
    "Return the smallest normalized Float that is > 0"
    ^CDoubleMin
!

largest
    "Return the largest normalized Float that is not infinite."
    ^CDoubleMax
!

smallest
    "Return the smallest normalized Float that is not infinite."
    ^CDoubleMax negated
!

epsilon
    "Return the smallest Float x for which is 1 + x ~= 1"
    ^2.0 timesTwoPower: self mantissaBits negated
!

log10Base2
    "Returns the value of log2 10. Hope is that it is precise enough"
    ^3.3219280948873623478703194294894
!

ln10
    "Returns the value of ln 10. Hope is that it is precise enough"
    ^2.3025850929940456840179914546844
!

infinity
    "Return a Float that represents positive infinity. I hope that it is big
    enough, IEEE 8 byte floating point values (C doubles) overflow at 1e308."
    ^1.0e10000
!

negativeInfinity
    "Return a Float that represents negative infinity. I hope that it is big
    enough, IEEE 8 byte floating point values (C doubles) overflow at -1e308."

    ^-1.0e10000
!

nan
    "Return a Float that represents a mathematically indeterminate value
     (e.g. Inf - Inf, Inf / Inf) "
    ^1.0e10000 - 1.0e10000
!

pi
    "Returns the value of pi. Hope is that it is precise enough"
    ^3.14159265358979323846264338327950288
! !



!Float methodsFor: 'arithmetic'!

// aNumber
    "Return the integer quotient of dividing the receiver by aNumber with
    truncation towards negative infinity."
    ^(self / aNumber) floor
!

\\ aNumber
    "Return the remainder of dividing the receiver by aNumber with
    truncation towards negative infinity."
    ^(self < 0) == (aNumber < 0)
	ifTrue: [ self rem: aNumber ]
	ifFalse: [ (self rem: aNumber) + aNumber ]
!

integerPart
    "Return the receiver's integer part"
    ^self - self fractionPart
! !


!Float methodsFor: 'testing'!

isNaN
    "Answer whether the receiver represents a NaN"
    ^self ~= self
!

isInfinite
    "Answer whether the receiver represents positive or negative infinity"
    ^self = Float infinity or: [ self = Float negativeInfinity ]
!

negative
    "Answer whether the receiver is negative"
    ^(self at: self class exponentByte) > 127
!

strictlyPositive
    "Answer whether the receiver is > 0"
    ^(self at: self class exponentByte) < 128 and: [ self ~= 0.0 ]
!

positive
    "Answer whether the receiver is positive"
    ^(self at: self class exponentByte) < 128
!

sign
    "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0."

    self = 0.0 ifTrue: [^0].
    ^self < 0 ifTrue: [-1] ifFalse: [1]
! !



!Float methodsFor: 'coercing'!

zero
    "Coerce 0 to the receiver's class"
    ^0.0
!

unity
    "Coerce 1 to the receiver's class"
    ^1.0
!

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

generality
    "Answer the receiver's generality"
    ^400
!

asExactFraction
    "Convert the receiver into a fraction with optimal approximation,
     but with usually huge terms."

    self checkCoercion.

    ^(self   timesTwoPower:  self exponent + Float mantissaBits) truncated /
     (1      bitShift:       self exponent + Float mantissaBits)
!

asFraction
    "Convert the receiver into a fraction with a good (but undefined)
     approximation"

    | a x n2 d2 n1 d1 n0 d0 eps |

    self checkCoercion.

    "This uses an algorithm based on the theory of continued fractions!!!
      n2/d2 = numerator and denominator of the fraction two steps ago
      n1/d1 = numerator and denominator of the fraction a steps ago
      n0/d0 = numerator and denominator of the fraction at the current step"

    n1  := d0 := 0.
    n0  := d1 := 1.
    x   := self abs.
    eps := Float epsilon * 1024.0 .

    [   a := x truncated.
	n2 := n1. d2 := d1.
	n1 := n0. d1 := d0.
	n0 := n1 * a + n2.
	d0 := d1 * a + d2.
	(n0 asFloat / d0 asFloat - self) abs < eps	"Number out of a hat"
    ]   whileFalse: [
	x := 1.0 / x fractionPart
    ].

    ^Fraction
	numerator: (self < 0 ifTrue: [ n0 negated ] ifFalse: [ n0 ])
	denominator: d0
!


estimatedLog
    "Answer an estimate of (self abs floorLog: 10)"
    ^(self exponent + 1) asFloat / Float log10Base2
!

asFloat
    "Just defined for completeness.  Return the receiver."
    ^self
! !


!Float methodsFor: 'printing'!

printOn: aStream
    "Print a representation of the receiver on aStream"
    self
	printOn: aStream
	special: #('Inf' '-Inf' 'NaN')
! !



!Float methodsFor: 'storing'!

storeOn: aStream
    "Print a representation of the receiver on aStream"
    self
	printOn: aStream
	special: #('Float infinity' 'Float negativeInfinity' 'Float nan')
! !



!Float methodsFor: 'private'!

checkCoercion
    "Private - Fail if the receiver is only representable as a Float"

    self isInfinite ifTrue: [self error: 'Infinity can only be a Float'].
    self isNaN ifTrue: [self error: 'Not-a-Number can only be a Float'].
!

printOn: aStream special: whatToPrintArray
    "Private - Print a decimal representation of the receiver on aStream,
     printing one of the three elements of whatToPrintArray if it is
     infinity, negative infinity, or a NaN"
    self > Float largest
	ifTrue: [ ^aStream nextPutAll: (whatToPrintArray at: 1) ].
    self < Float smallest
	ifTrue: [ ^aStream nextPutAll: (whatToPrintArray at: 2) ].
    self isNaN
	ifTrue: [ ^aStream nextPutAll: (whatToPrintArray at: 3) ].

    self printFloatOn: aStream
!

printFloatOn: aStream
    "Private - Print a decimal representation of the receiver on aStream"
    | num str intDigits exp |
    num := self.
    num < 0.0 ifTrue:
    	[ aStream nextPut: $-.
	  num := num negated. ].

    exp := 0.
    (self exponent between: -50 and: 49) ifFalse: [
	num abs < 1.0
	    ifTrue: [
		[ num := num * 10.0. exp := exp - 1. num abs < 10.0 ] whileTrue
	    ]
	    ifFalse: [
		[ num := num / 10.0. exp := exp + 1. num abs >= 10.0] whileTrue
	    ]
    ].
    
    intDigits := num printIntegerPartOn: aStream.
    aStream nextPut: $..

    " produce the digits, up to a maximum of 14 = -1 + log10 (2^52)
      We use 14 (not 15) because the last is a guard digit."
    (num printFracPartOn: aStream decimals: 14 - intDigits)
	ifFalse: [ aStream nextPut: $0 ].

    exp = 0 ifFalse: [
	aStream nextPut: $e.
	exp printOn: aStream ]
!

printIntegerPartOn: aStream
    "Private - Print a representation of the receiver's integer part
     on aStream"
    | num str twoDigits |
    self < 1.0
    	ifTrue: [ aStream nextPut: $0. ^0 ].

    str := WriteStream on: (String new: 10).

    num := self integerPart.
    [ num = 0.0 ] whileFalse: [
	"Get two digits instead of one to avoid rounding problems"
    	twoDigits := ((num / 100.0) fractionPart * 100.0) rounded.
	str nextPut: (Character digitValue: twoDigits \\ 10).
	num := (num / 10.0) integerPart.
    ].
    str contents reverseDo: [ :each | aStream nextPut: each ].
    ^str size
!

printFracPartOn: aStream decimals: digitLimit
    "Private - Print a representation of the receiver's fractional part
     on aStream, removing trailing zeros. Answer whether at least a
     digit was printed"

    | num zeroCount digit |
    num := self fractionPart.
    num := 5.0 * (0.1 raisedToInteger: digitLimit + 1) + num.
    zeroCount := 0.

    digitLimit timesRepeat: [
    	num := num * 10.0.
	digit := num floor.
	digit = 0		"for trailing zero suppression"
	    ifTrue: [ zeroCount := zeroCount + 1 ]
	    ifFalse: [ aStream next: zeroCount put: $0.
    	    	       aStream nextPut: (Character value: 48 + digit).
	    	       zeroCount := 0 ].
	num := num fractionPart.
    ].
    ^zeroCount < digitLimit
! !


!Float methodsFor: 'testing functionality'!

isFloat
    ^true
! !

