Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
6919 lines (5631 sloc) 231 KB
ArithmeticError subclass: #ZeroDivide instanceVariableNames: 'dividend' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!ZeroDivide commentStamp: 'SvenVanCaekenberghe 4/21/2011 12:36' prior: 0!I am ZeroDivide, an ArithmeticError that may be signaled when a mathematical division by 0 is attempted.!!ZeroDivide methodsFor: 'exceptionbuilder' stamp: 'pnm 8/16/2000 15:05'!dividend: argument "Specify the number that was being divided by zero." dividend := argument! !!ZeroDivide methodsFor: 'exceptiondescription' stamp: 'tfei 6/5/1999 17:29'!dividend "Answer the number that was being divided by zero." ^dividend! !!ZeroDivide methodsFor: 'exceptiondescription' stamp: 'pnm 8/16/2000 15:05'!isResumable "Determine whether an exception is resumable." ^true! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!ZeroDivide class instanceVariableNames: ''!!ZeroDivide class methodsFor: 'exceptioninstantiator' stamp: 'bf 9/27/1999 17:26'!dividend: argument ^self new dividend: argument; yourself! !!ZeroDivide class methodsFor: 'signaling' stamp: 'GabrielOmarCotelli 6/6/2009 17:12'!signalWithDividend: aDividend ^(self dividend: aDividend) signal! ! Object subclass: #NumberParser instanceVariableNames: 'sourceStream base neg integerPart fractionPart exponent scale nDigits lastNonZero requestor failBlock' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!NumberParser commentStamp: 'nice 2/13/2010 00:31' prior: 0!NumberParser is an abstract class for parsing and building numbers from string/stream.It offers a framework with utility methods and exception handling.Number syntax is not defined and should be subclassResponsibility.Instance variables:sourceStream <Stream> the stream of characters from which the number is readbase <Integer> the radix in which to interpret digitsneg <Boolean> true in case of minus signintegerPart <Integer> the integer part of the numberfractionPart <Integer> the fraction part of the number if anyexponent <Integer> the exponent used in scientific notation if anyscale <Integer> the scale used in case of ScaledDecimal number if anynDigits <Integer> number of digits read to form an IntegerlasNonZero <Integer> position of last non zero digit, starting at 1 from left, 0 if all digits are zerorequestor <?> could eventually be used to insert an error message in a text editorfailBlock <BlockClosure> Block to execute whenever an error occurs!!NumberParser methodsFor: 'accessing' stamp: 'nice 2/12/2010 23:56'!allowPlusSign "return a boolean indicating if plus sign is allowed or not" ^self subclassResponsibility! !!NumberParser methodsFor: 'accessing' stamp: 'nice 2/12/2010 23:56'!allowPlusSignInExponent "return a boolean indicating if plus sign is allowed or not in exponent" ^self allowPlusSign! !!NumberParser methodsFor: 'accessing' stamp: 'nice 2/12/2010 23:55'!exponentLetters "answer the list of possible exponents for Numbers." ^self subclassResponsibility! !!NumberParser methodsFor: 'accessing' stamp: 'nice 5/1/2006 01:58'!failBlock: aBlockOrNil failBlock := aBlockOrNil! !!NumberParser methodsFor: 'accessing' stamp: 'nice 5/1/2006 01:59'!requestor: anObjectOrNil requestor := anObjectOrNil! !!NumberParser methodsFor: 'error' stamp: 'nice 2/25/2010 02:39'!expected: aString | errorString | errorString := aString , ' expected'. requestor isNil ifFalse: [requestor notify: errorString at: sourceStream position + 1 in: sourceStream]. failBlock ifNotNil: [^failBlock cull: errorString cull: sourceStream position + 1]. self error: 'Reading a number failed: ' , errorString! !!NumberParser methodsFor: 'error' stamp: 'NikoSchwarz 10/17/2009 10:45'!fail failBlock ifNotNil: [^failBlock value]. self error: 'Reading a number failed'! !!NumberParser methodsFor: 'initialize-release' stamp: 'damiencassou 5/30/2008 10:56'!on: aStringOrStream sourceStream := aStringOrStream isString ifTrue: [ aStringOrStream readStream ] ifFalse: [ aStringOrStream ]. base := 10. neg := false. integerPart := fractionPart := exponent := scale := 0. requestor := failBlock := nil! !!NumberParser methodsFor: 'parsing-large int' stamp: 'nice 8/31/2008 23:00'!nextElementaryLargeIntegerBase: aRadix "Form an unsigned integer with incoming digits from sourceStream. Return this integer, or zero if no digits found. Stop reading if end of digits or if a LargeInteger is formed. Count the number of digits and the position of lastNonZero digit and store them in instVar" | value digit | value := 0. nDigits := 0. lastNonZero := 0. aRadix <= 10 ifTrue: ["Avoid using digitValue which is awfully slow" [value isLarge or: [sourceStream atEnd or: [digit := sourceStream next charCode - 48. (0 > digit or: [digit >= aRadix]) and: [sourceStream skip: -1. true]]]] whileFalse: [nDigits := nDigits + 1. 0 = digit ifFalse: [lastNonZero := nDigits]. value := value * aRadix + digit]] ifFalse: [ [value isLarge or: [sourceStream atEnd or: [digit := sourceStream next digitValue. (0 > digit or: [digit >= aRadix]) and: [sourceStream skip: -1. true]]]] whileFalse: [nDigits := nDigits + 1. 0 = digit ifFalse: [lastNonZero := nDigits]. value := value * aRadix + digit]]. ^value! !!NumberParser methodsFor: 'parsing-large int' stamp: 'nice 7/26/2009 00:24'!nextLargeIntegerBase: aRadix nPackets: nPackets "Form a Large integer with incoming digits from sourceStream. Return this integer, or zero if no digits found. Stop reading when no more digits or when nPackets elementary LargeInteger have been encountered. Count the number of digits and the lastNonZero digit and store them in instVar" | high nDigitsHigh low nDigitsLow halfPackets | halfPackets := nPackets bitShift: -1. halfPackets = 0 ifTrue: [^self nextElementaryLargeIntegerBase: aRadix]. high := self nextLargeIntegerBase: aRadix nPackets: halfPackets. high isLarge ifFalse: [^high]. nDigitsHigh := nDigits. low := self nextLargeIntegerBase: aRadix nPackets: halfPackets. nDigitsLow := nDigits. nDigits := nDigitsHigh + nDigitsLow. lastNonZero = 0 ifFalse: [lastNonZero := lastNonZero + nDigitsHigh]. ^high * (aRadix raisedToInteger: nDigitsLow) + low! !!NumberParser methodsFor: 'parsing-private' stamp: 'nice 7/26/2009 00:22'!makeFloatFromMantissa: m exponent: k base: aRadix "Convert infinite precision arithmetic into Floating point. This alogrithm rely on correct IEEE rounding mode being implemented in Integer>>asFloat and Fraction>>asFloat" ^(k positive ifTrue: [m * (aRadix raisedToInteger: k)] ifFalse: [Fraction numerator: m denominator: (aRadix raisedToInteger: k negated)]) asFloat! !!NumberParser methodsFor: 'parsing-private' stamp: 'nice 10/7/2009 01:40'!makeScaledDecimalWithNumberOfNonZeroFractionDigits: numberOfNonZeroFractionDigits andNumberOfTrailingZeroInFractionPart: numberOfTrailingZeroInFractionPart "at this point integerPart fractionPart and scale have been read out (in inst var). Form a ScaledDecimal. Care of eliminating trailing zeroes from the fractionPart" | decimalMultiplier decimalFraction | decimalMultiplier := base raisedToInteger: numberOfNonZeroFractionDigits. decimalFraction := integerPart * decimalMultiplier + (fractionPart // (base raisedTo: numberOfTrailingZeroInFractionPart)) / decimalMultiplier. neg ifTrue: [decimalFraction := decimalFraction negated]. ^decimalFraction asScaledDecimal: scale! !!NumberParser methodsFor: 'parsing-private' stamp: 'nice 2/12/2010 23:57'!peekSignIsMinus "Peek an optional sign from sourceStream. Answer true if it is minus sign" | isMinus | isMinus := sourceStream peekFor: $-. isMinus ifFalse: [self allowPlusSign ifTrue: [sourceStream peekFor: $+]]. ^isMinus! !!NumberParser methodsFor: 'parsing-private' stamp: 'nice 2/13/2010 16:03'!readExponent "read the exponent if any (stored in instVar). Answer true if found, answer false if none. If exponent letter is not followed by a digit, this is not considered as an error. Exponent are always read in base 10." | eneg epos | exponent := 0. sourceStream atEnd ifTrue: [^ false]. (self exponentLetters includes: sourceStream peek) ifFalse: [^ false]. sourceStream next. eneg := sourceStream peekFor: $-. epos := eneg not and: [self allowPlusSignInExponent and: [sourceStream peekFor: $+]]. exponent := self nextUnsignedIntegerOrNilBase: 10. exponent ifNil: ["Oops, there was no digit after the exponent letter.Ungobble the letter" exponent := 0. sourceStream skip: ((eneg or: [epos]) ifTrue: [-2] ifFalse: [-1]). ^ false]. eneg ifTrue: [exponent := exponent negated]. ^ true! !!NumberParser methodsFor: 'parsing-public' stamp: 'nice 4/2/2010 20:25'!nextIntegerBase: aRadix "Form an integer with following digits. Fail if no digit found" | isNeg value | isNeg := self peekSignIsMinus. value := self nextUnsignedIntegerBase: aRadix. ^isNeg ifTrue: [value negated] ifFalse: [value]! !!NumberParser methodsFor: 'parsing-public' stamp: 'nice 8/27/2010 20:51'!nextIntegerBase: aRadix ifFail: aBlock "Form an integer with optional sign and following digits from sourceStream." | isNeg value | isNeg := self peekSignIsMinus. value := self nextUnsignedIntegerOrNilBase: aRadix. value ifNil: [^aBlock value]. ^isNeg ifTrue: [value negated] ifFalse: [value]! !!NumberParser methodsFor: 'parsing-public' stamp: 'nice 2/12/2010 23:59'!nextNumber "read next number from sourceStream contents" ^self subclassResponsibility! !!NumberParser methodsFor: 'parsing-public' stamp: 'nice 10/16/2008 01:05'!nextUnsignedIntegerBase: aRadix "Form an unsigned integer with incoming digits from sourceStream. Fail if no digit found. Count the number of digits and the lastNonZero digit and store int in instVar " | value | value := self nextUnsignedIntegerOrNilBase: aRadix. value ifNil: [^self expected: ('a digit between 0 and ' copyWith: (Character digitValue: aRadix - 1))]. ^value! !!NumberParser methodsFor: 'parsing-public' stamp: 'nice 10/16/2008 01:05'!nextUnsignedIntegerBase: aRadix ifFail: errorBlock "Form an unsigned integer with incoming digits from sourceStream. Answer this integer, or execute errorBlock if no digit found. Count the number of digits and the position of lastNonZero digit and store them in instVar" | value | value := self nextUnsignedIntegerOrNilBase: aRadix. value ifNil: [^errorBlock value]. ^value! !!NumberParser methodsFor: 'parsing-public' stamp: 'nice 7/26/2009 00:21'!nextUnsignedIntegerOrNilBase: aRadix "Form an unsigned integer with incoming digits from sourceStream. Answer this integer, or nil if no digit found. Count the number of digits and the position of lastNonZero digit and store them in instVar" | nPackets high nDigitsHigh lastNonZeroHigh low | "read no more digits than one elementary LargeInteger" high := self nextElementaryLargeIntegerBase: aRadix. nDigits = 0 ifTrue: [^nil]. "Not enough digits to form a LargeInteger, stop iteration" high isLarge ifFalse: [^high]. "We now have to engage arithmetic with LargeInteger Decompose the integer in a high and low packets of growing size:" nPackets := 1. nDigitsHigh := nDigits. lastNonZeroHigh := lastNonZero. [ low := self nextLargeIntegerBase: aRadix nPackets: nPackets . high := high * (aRadix raisedToInteger: nDigits) + low. lastNonZero = 0 ifFalse: [lastNonZeroHigh := lastNonZero + nDigitsHigh]. nDigitsHigh := nDigitsHigh + nDigits. low isLarge] whileTrue: [nPackets := nPackets * 2]. nDigits := nDigitsHigh. lastNonZero := lastNonZeroHigh. ^high! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!NumberParser class instanceVariableNames: ''!!NumberParser class methodsFor: 'instance creation' stamp: 'nice 5/1/2006 00:45'!on: aStringOrStream ^self new on: aStringOrStream! !!NumberParser class methodsFor: 'instance creation' stamp: 'nice 5/1/2006 02:02'!parse: aStringOrStream ^(self new) on: aStringOrStream; nextNumber! !!NumberParser class methodsFor: 'instance creation' stamp: 'nice 5/1/2006 02:02'!parse: aStringOrStream onError: failBlock ^(self new) on: aStringOrStream; failBlock: failBlock; nextNumber! !!NumberParser class methodsFor: 'instance creation' stamp: 'NikoSchwarz 10/23/2009 13:21'!squeezeNumberOutOfString: stringOrStream "Try and find a number in this string. First, look if the string starts with a number. Then, see if it ends with a number. Then, remove a character from the front and see if the remaining string makes a number. Repeat the process until no characters are left or the number has been found. As soon as a number is found, it is returned. Otherwise, the method fails." ^ self squeezeNumberOutOfString: stringOrStream onError: [self error: 'Reading a number failed']! !!NumberParser class methodsFor: 'instance creation' stamp: 'NikoSchwarz 10/23/2009 13:22'!squeezeNumberOutOfString: stringOrStream onError: errorBlock "Try and find a number in this string. First, look if the string starts with a number. Then, see if it ends with a number. Then, remove a character from the front and see if the remaining string makes a number. Repeat the process until no characters are left or the number has been found. As soon as a number is found, it is returned. Otherwise, the method fails." | block string try | try := self parse: stringOrStream onError: [nil]. try ifNotNil: [^try]. try := self parse: stringOrStream asString copy reversed onError: [nil]. try ifNotNil: [ ^ try asString reversed asNumber]. string := stringOrStream. block := [^ stringOrStream ifEmpty: [^errorBlock value] ifNotEmpty: [string := string allButFirst. self parse: string onError: block]]. block value! ! NumberParser subclass: #SqNumberParser instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!SqNumberParser commentStamp: 'nice 2/13/2010 00:36' prior: 0!SqNumberParser is a NumberParser specialized in reading Number with Squeak syntax.Squeak syntax follows general Smalltalk-80 conventions for integer and floats, extended with scaled decimals.Noticeable differences with st-80 and other Smalltalks are:- allow both 2r-10 and -2r10 and even -2r-10- allow floating point with radix 2r10.011- do not allow single s without following digits as ScaledDecimal- handle special case of Float (NaN Infinity and -0.0 as negative zero)!!SqNumberParser methodsFor: 'accessing' stamp: 'nice 2/13/2010 00:00'!allowPlusSign "return a boolean indicating if plus sign is allowed or not" ^false! !!SqNumberParser methodsFor: 'accessing' stamp: 'nice 4/27/2006 22:57'!exponentLetters "answer the list of possible exponents for Numbers. Note: this parser will not honour precision attached to the exponent. different exponent do not lead to different precisions. only IEEE 754 floating point numbers will be created" ^'edq'! !!SqNumberParser methodsFor: 'parsing-private' stamp: 'nice 10/7/2009 01:30'!makeIntegerOrScaledInteger "at this point, there is no digit, nor fractionPart. maybe it can be a scaled decimal with fraction omitted..." neg ifTrue: [integerPart := integerPart negated]. self readExponent ifTrue: [^integerPart * (base raisedToInteger: exponent)]. self readScale ifTrue: [^integerPart asScaledDecimal: scale]. ^ integerPart! !!SqNumberParser methodsFor: 'parsing-private' stamp: 'nice 2/13/2010 16:34'!readNamedFloatOrFail "This method is used when there is no digit encountered: It try and read a named Float NaN or Infinity. Negative sign for -Infinity has been read before sending this method, and is indicated in the neg inst.var. Fail if no named Float is found" neg ifFalse: [(sourceStream nextMatchAll: 'NaN') ifTrue: [^ Float nan]]. (sourceStream nextMatchAll: 'Infinity') ifTrue: [^ neg ifTrue: [Float infinity negated] ifFalse: [Float infinity]]. ^self expected: 'a digit between 0 and ' , (String with: (Character digitValue: base - 1))! !!SqNumberParser methodsFor: 'parsing-private' stamp: 'nice 7/26/2009 00:45'!readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart "at this stage, sign integerPart and a decimal point have been read. try and form a number with a fractionPart" | numberOfNonZeroFractionDigits numberOfTrailingZeroInFractionPart mantissa value | fractionPart := self nextUnsignedIntegerOrNilBase: base. fractionPart ifNil: ["No fractionPart found,ungobble the decimal point and return the integerPart" sourceStream skip: -1. ^ neg ifTrue: [integerPart negated] ifFalse: [integerPart]]. numberOfNonZeroFractionDigits := lastNonZero. numberOfTrailingZeroInFractionPart := nDigits - lastNonZero. self readExponent ifFalse: [self readScale ifTrue: [^self makeScaledDecimalWithNumberOfNonZeroFractionDigits: numberOfNonZeroFractionDigits andNumberOfTrailingZeroInFractionPart: numberOfTrailingZeroInFractionPart]]. fractionPart isZero ifTrue: [mantissa := integerPart // (base raisedToInteger: numberOfTrailingZeroInIntegerPart). exponent := exponent + numberOfTrailingZeroInIntegerPart] ifFalse: [mantissa := integerPart * (base raisedToInteger: numberOfNonZeroFractionDigits) + (fractionPart // (base raisedToInteger: numberOfTrailingZeroInFractionPart)). exponent := exponent - numberOfNonZeroFractionDigits]. value := self makeFloatFromMantissa: mantissa exponent: exponent base: base. ^ neg ifTrue: [value isZero ifTrue: [Float negativeZero] ifFalse: [value negated]] ifFalse: [value]! !!SqNumberParser methodsFor: 'parsing-private' stamp: 'nice 10/16/2008 02:17'!readScale "read the scale if any (stored in instVar). Answer true if found, answer false if none. If scale letter is not followed by a digit, this is not considered as an error. Scales are always read in base 10, though i do not see why..." scale := 0. sourceStream atEnd ifTrue: [^ false]. (sourceStream peekFor: $s) ifFalse: [^ false]. scale := self nextUnsignedIntegerOrNilBase: 10. scale ifNil: [ scale := 0. sourceStream skip: -1. "ungobble the s" ^ false]. ^ true! !!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 2/24/2010 02:51'!nextNumber "main method for reading a number. This one can read Float Integer and ScaledDecimal" | numberOfTrailingZeroInIntegerPart | base := 10. neg := self peekSignIsMinus. integerPart := self nextUnsignedIntegerOrNilBase: base. integerPart ifNil: [ "This is not a regular number beginning with a digit It is time to check for exceptional condition NaN and Infinity" ^self readNamedFloatOrFail]. numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero. (sourceStream peekFor: $r) ifTrue: ["<base>r<integer>" (base := integerPart) < 2 ifTrue: [ sourceStream skip: -1. ^ self expected: 'an integer greater than 1 as valid radix']. self peekSignIsMinus ifTrue: [neg := neg not]. integerPart := self nextUnsignedIntegerBase: base. numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero]. ^ (sourceStream peekFor: $.) ifTrue: [self readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart] ifFalse: [self makeIntegerOrScaledInteger]! !!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 10/16/2008 00:50'!nextNumberBase: b "Method for reading a number without radix prefix. This one can read Float Integer and ScaledDecimal" | numberOfTrailingZeroInIntegerPart | base := b. neg := sourceStream peekFor: $-. integerPart := self nextUnsignedIntegerOrNilBase: base. integerPart ifNil: [ "This is not a regular number beginning with a digit It is time to check for exceptional condition NaN and Infinity" ^self readNamedFloatOrFail]. numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero. ^ (sourceStream peekFor: $.) ifTrue: [self readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart] ifFalse: [self makeIntegerOrScaledInteger]! !!SqNumberParser methodsFor: 'parsing-public' stamp: 'nice 10/16/2008 00:51'!nextScaledDecimal "Main method for reading a (scaled) decimal number. Good Gracious, do not accept a decimal in another base than 10!! In other words, do not accept radix notation like 2r1.1, even not 10r5.3 Do not accept exponent notation neither, like 1.0e-3" | numberOfNonZeroFractionDigits numberOfTrailingZeroInFractionPart | base := 10. neg := sourceStream peekFor: $-. integerPart := self nextUnsignedIntegerBase: base. (sourceStream peekFor: $.) ifTrue: [fractionPart := self nextUnsignedIntegerOrNilBase: base. fractionPart ifNil: ["Oops, the decimal point seems not part of this number" sourceStream skip: -1. ^ neg ifTrue: [integerPart negated asScaledDecimal: 0] ifFalse: [integerPart asScaledDecimal: 0]]. numberOfNonZeroFractionDigits := lastNonZero. numberOfTrailingZeroInFractionPart := nDigits - lastNonZero. self readScale ifFalse: ["No scale were provided. use number of digits after decimal point as scale" scale := nDigits]. ^self makeScaledDecimalWithNumberOfNonZeroFractionDigits: numberOfNonZeroFractionDigits andNumberOfTrailingZeroInFractionPart: numberOfTrailingZeroInFractionPart]. self readScale. neg ifTrue: [integerPart := integerPart negated]. ^integerPart asScaledDecimal: scale! ! SqNumberParser subclass: #ExtendedNumberParser instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!ExtendedNumberParser commentStamp: 'nice 2/13/2010 00:39' prior: 0!An ExtendedNumberParser is extending Squeak number syntax with these rules- allow partial specification of integer and fraction parts:1.e2 .1e3 are both 100.0- allow plus sign before number and in exponent!!ExtendedNumberParser methodsFor: 'accessing' stamp: 'nice 2/13/2010 00:40'!allowPlusSign ^true! !!ExtendedNumberParser methodsFor: 'parsing-private' stamp: 'nice 2/13/2010 00:57'!readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart "at this stage, sign integerPart and a decimal point have been read. try and form a number with a fractionPart" | numberOfNonZeroFractionDigits numberOfTrailingZeroInFractionPart mantissa value | fractionPart := self nextUnsignedIntegerOrNilBase: base. fractionPart ifNil: [ "No fractionPart found, but can be a 1.e2 syntax" fractionPart := 0. numberOfNonZeroFractionDigits := 0. numberOfTrailingZeroInFractionPart := 0] ifNotNil: [. numberOfNonZeroFractionDigits := lastNonZero. numberOfTrailingZeroInFractionPart := nDigits - lastNonZero]. self readExponent ifFalse: [self readScale ifTrue: [^self makeScaledDecimalWithNumberOfNonZeroFractionDigits: numberOfNonZeroFractionDigits andNumberOfTrailingZeroInFractionPart: numberOfTrailingZeroInFractionPart]]. fractionPart isZero ifTrue: [mantissa := integerPart // (base raisedToInteger: numberOfTrailingZeroInIntegerPart). exponent := exponent + numberOfTrailingZeroInIntegerPart] ifFalse: [mantissa := integerPart * (base raisedToInteger: numberOfNonZeroFractionDigits) + (fractionPart // (base raisedToInteger: numberOfTrailingZeroInFractionPart)). exponent := exponent - numberOfNonZeroFractionDigits]. value := self makeFloatFromMantissa: mantissa exponent: exponent base: base. ^ neg ifTrue: [value isZero ifTrue: [Float negativeZero] ifFalse: [value negated]] ifFalse: [value]! !!ExtendedNumberParser methodsFor: 'parsing-private' stamp: 'nice 2/13/2010 01:55'!readNumberWithoutIntegerPart "at this stage, sign followed by a decimal point have been read, but no intergerPart try and form a number with a fractionPart" ^self readNumberWithoutIntegerPartOrNil ifNil: [ "No integer part, no fractionPart, this does not look like a number..." ^self expected: 'a digit between 0 and 9'].! !!ExtendedNumberParser methodsFor: 'parsing-private' stamp: 'nice 2/13/2010 01:54'!readNumberWithoutIntegerPartOrNil "at this stage, sign followed by a decimal point have been read, but no intergerPart try and form a number with a fractionPart" | numberOfNonZeroFractionDigits numberOfTrailingZeroInFractionPart mantissa value | integerPart := 0. fractionPart := self nextUnsignedIntegerOrNilBase: base. fractionPart ifNil: [ "No integer part, no fractionPart, this does not look like a number..." ^nil]. numberOfNonZeroFractionDigits := lastNonZero. numberOfTrailingZeroInFractionPart := nDigits - lastNonZero. self readExponent ifFalse: [self readScale ifTrue: [^self makeScaledDecimalWithNumberOfNonZeroFractionDigits: numberOfNonZeroFractionDigits andNumberOfTrailingZeroInFractionPart: numberOfTrailingZeroInFractionPart]]. fractionPart isZero ifTrue: [mantissa := 0] ifFalse: [mantissa := (fractionPart // (base raisedToInteger: numberOfTrailingZeroInFractionPart)). exponent := exponent - numberOfNonZeroFractionDigits]. value := self makeFloatFromMantissa: mantissa exponent: exponent base: base. ^ neg ifTrue: [value isZero ifTrue: [Float negativeZero] ifFalse: [value negated]] ifFalse: [value]! !!ExtendedNumberParser methodsFor: 'parsing-public' stamp: 'nice 2/13/2010 02:10'!nextNumber "main method for reading a number. This one can read Float Integer and ScaledDecimal" | numberOfTrailingZeroInIntegerPart | base := 10. neg := self peekSignIsMinus. integerPart := self nextUnsignedIntegerOrNilBase: base. integerPart ifNil: [(sourceStream peekFor: $.) ifTrue: [ "Try .1 syntax" ^self readNumberWithoutIntegerPart] ifFalse: [ "This is not a regular number beginning with a digit It is time to check for exceptional condition NaN and Infinity" ^self readNamedFloatOrFail]]. numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero. (sourceStream peekFor: $r) ifTrue: ["<base>r<integer>" | oldNeg pos | pos := sourceStream position. (base := integerPart) < 2 ifTrue: ["A radix currently need to be greater than 1, ungobble the r and return the integer part" sourceStream skip: -1. ^neg ifTrue: [base negated] ifFalse: [base]]. oldNeg := neg. self peekSignIsMinus ifTrue: [neg := neg not]. integerPart := self nextUnsignedIntegerOrNilBase: base. integerPart ifNil: [ (sourceStream peekFor: $.) ifTrue: [self readNumberWithoutIntegerPartOrNil ifNotNil: [:aNumber | ^aNumber]]. sourceStream position: pos. ^oldNeg ifTrue: [base negated] ifFalse: [base]]. numberOfTrailingZeroInIntegerPart := nDigits - lastNonZero]. ^ (sourceStream peekFor: $.) ifTrue: [self readNumberWithFractionPartNumberOfTrailingZeroInIntegerPart: numberOfTrailingZeroInIntegerPart] ifFalse: [self makeIntegerOrScaledInteger]! ! Object subclass: #Magnitude instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!Magnitude commentStamp: 'sd 9/4/2005 10:14' prior: 0!I'm the abstract class Magnitude that provides common protocol for objects that havethe ability to be compared along a linear dimension, such as dates or times.Subclasses of Magnitude include Date, ArithmeticValue, and Time, as well asCharacter and LookupKey. My subclasses should implement < aMagnitude = aMagnitude hashHere are some example of my protocol: 3 > 4 5 = 6 100 max: 9 7 between: 5 and: 10 !!Magnitude methodsFor: '*Kernel-Extensions-Streaming' stamp: 'kph 9/27/2007 22:10'!putOn: aStream (aStream isBinary ifTrue: [ self asByteArray ] ifFalse: [ self asString]) putOn: aStream ! !!Magnitude methodsFor: 'comparing'!max: aMagnitude "Answer the receiver or the argument, whichever has the greater magnitude." self > aMagnitude ifTrue: [^self] ifFalse: [^aMagnitude]! !!Magnitude methodsFor: 'comparing'!min: aMagnitude "Answer the receiver or the argument, whichever has the lesser magnitude." self < aMagnitude ifTrue: [^self] ifFalse: [^aMagnitude]! !!Magnitude methodsFor: 'comparing'!min: aMin max: aMax ^ (self min: aMin) max: aMax! !!Magnitude methodsFor: 'hash'!hash "Hash must be redefined whenever = is redefined." ^self subclassResponsibility! !!Magnitude methodsFor: 'testing'!< aMagnitude "Answer whether the receiver is less than the argument." ^self subclassResponsibility! !!Magnitude methodsFor: 'testing'!<= aMagnitude "Answer whether the receiver is less than or equal to the argument." ^(self > aMagnitude) not! !!Magnitude methodsFor: 'testing'!= aMagnitude "Compare the receiver with the argument and answer with true if the receiver is equal to the argument. Otherwise answer false." ^self subclassResponsibility! !!Magnitude methodsFor: 'testing'!> aMagnitude "Answer whether the receiver is greater than the argument." ^aMagnitude < self! !!Magnitude methodsFor: 'testing' stamp: 'nice 12/31/2008 04:06'!>= aMagnitude "Answer whether the receiver is greater than or equal to the argument." ^aMagnitude <= self! !!Magnitude methodsFor: 'testing'!between: min and: max "Answer whether the receiver is less than or equal to the argument, max, and greater than or equal to the argument, min." ^self >= min and: [self <= max]! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!Magnitude class instanceVariableNames: ''! Magnitude subclass: #Number instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!Number commentStamp: 'StephaneDucasse 11/1/2010 07:50' prior: 0!Class Number holds the most general methods for dealing with numbers. Subclasses Float, Fraction, and Integer, and their subclasses, provide concrete representations of a numeric quantity.All of Number's subclasses participate in a simple type coercion mechanism that supports mixed-mode arithmetic and comparisons. It works as follows: If self<typeA> op: arg<typeB>fails because of incompatible types, then it is retried in the following guise: (arg adaptTypeA: self) op: arg adaptToTypeA.This gives the arg of typeB an opportunity to resolve the incompatibility, knowing exactly what two types are involved. If self is more general, then arg will be converted, and viceVersa. This mechanism is extensible to any new number classes that one might wish to add to Squeak. The only requirement is that every subclass of Number must support a pair of conversion methods specific to each of the other subclasses of Number.Implementation notes----------------------------------The implementation of #degreeCos and #degreeSin is such that results are exact for any multiple of 90.Care is also taken to evaluate the sine between -90° and 90°, this will avoid #degreesToRadians and i386 FPU sine fonction to accumulate round off errors due to approximate representation of pi.We can thus evaluate 240 degreeCos with at most 1 ulp error. It's not perfect, but better than previous implementation.For cosine, we know that: cosd(x)=cosd(abs(x)) cosd(x)=sind(90-x)thus the trick is to evaluate: cosd(x)=sind(90-abs(x)) after appropriate modulo in [-180,180[This way, we are sure to evaluate the sine between -90° and 90°The #degreesToRadians and #sin are used rather than #degreeSin to avoid cycles.For sine, it would be necessary to evaluate eithersind(x) if abs(x) <=90or sind(180-x) if abs(x) >= 90A possible implementation would be: | x | x := 90 + self \\ 360 - 90. x >= 180 ifTrue: [x := 180 - x]. ^x degreesToRadians sinWe prefer evaluating cosd(90-x) thus providing a branch free implementation.!!Number methodsFor: '*Graphics-Primitives'!@ y "Primitive. Answer a Point whose x value is the receiver and whose y value is the argument. Optional. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 18> ^Point x: self y: y! !!Number methodsFor: '*Tools-Inspector'!defaultLabelForInspector "Answer the default label to be used for an Inspector window on the receiver." ^ super defaultLabelForInspector, ': ', self printString! !!Number methodsFor: 'arithmetic'!* aNumber "Answer the result of multiplying the receiver by aNumber." self subclassResponsibility! !!Number methodsFor: 'arithmetic'!+ aNumber "Answer the sum of the receiver and aNumber." self subclassResponsibility! !!Number methodsFor: 'arithmetic'!- aNumber "Answer the difference between the receiver and aNumber." self subclassResponsibility! !!Number methodsFor: 'arithmetic'!/ aNumber "Answer the result of dividing the receiver by aNumber." self subclassResponsibility! !!Number methodsFor: 'arithmetic'!// aNumber "Integer quotient defined by division with truncation toward negative infinity. 9//4 = 2, -9//4 = -3. -0.9//0.4 = -3. \\ answers the remainder from this division." ^(self / aNumber) floor! !!Number methodsFor: 'arithmetic'!\\ aNumber "modulo. Remainder defined in terms of //. Answer a Number with the same sign as aNumber. e.g. 9\\4 = 1, -9\\4 = 3, 9\\-4 = -3, 0.9\\0.4 = 0.1." ^self - (self // aNumber * aNumber)! !!Number methodsFor: 'arithmetic'!abs "Answer a Number that is the absolute value (positive magnitude) of the receiver." self < 0 ifTrue: [^self negated] ifFalse: [^self]! !!Number methodsFor: 'arithmetic' stamp: 'mk 10/27/2003 21:00'!arg "Answer the argument of the receiver (see Complex | arg)." self isZero ifTrue: [self error: 'Zero (0 + 0 i) does not have an argument.']. 0 < self ifTrue: [^ 0] ifFalse: [^ Float pi]! !!Number methodsFor: 'arithmetic'!negated "Answer a Number that is the negation of the receiver." ^0 - self! !!Number methodsFor: 'arithmetic'!quo: aNumber "Integer quotient defined by division with truncation toward zero. -9 quo: 4 = -2, -0.9 quo: 0.4 = -2. rem: answers the remainder from this division." ^(self / aNumber) truncated! !!Number methodsFor: 'arithmetic' stamp: 'GabrielOmarCotelli 5/23/2009 20:20'!reciprocal "Returns the reciprocal of self. In case self is 0 the / signals ZeroDivide" ^1 / self! !!Number methodsFor: 'arithmetic'!rem: aNumber "Remainder defined in terms of quo:. Answer a Number with the same sign as self. e.g. 9 rem: 4 = 1, -9 rem: 4 = -1. 0.9 rem: 0.4 = 0.1." ^self - ((self quo: aNumber) * aNumber)! !!Number methodsFor: 'comparing' stamp: 'nice 12/26/2009 18:46'!closeTo: num "are these two numbers close?" num isFloat ifTrue: [^ num closeTo: self asFloat]. ^[self = num] ifError: [false]! !!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:43'!adaptToCollection: rcvr andSend: selector "If I am involved in arithmetic with a Collection, return a Collection of the results of each element combined with me in that expression." ^ rcvr collect: [:element | element perform: selector with: self]! !!Number methodsFor: 'converting' stamp: 'nice 1/4/2009 20:31'!adaptToFloat: rcvr andCompare: selector "If I am involved in comparison with a Float, convert rcvr to a Fraction. This way, no bit is lost and comparison is exact." rcvr isFinite ifFalse: [ selector == #= ifTrue: [^false]. selector == #~= ifTrue: [^true]. rcvr isNaN ifTrue: [^ false]. (selector = #< or: [selector = #'<=']) ifTrue: [^ rcvr positive not]. (selector = #> or: [selector = #'>=']) ifTrue: [^ rcvr positive]. ^self error: 'unknow comparison selector']. ^ rcvr asTrueFraction perform: selector with: self! !!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:21'!adaptToFloat: rcvr andSend: selector "If I am involved in arithmetic with a Float, convert me to a Float." ^ rcvr perform: selector with: self asFloat! !!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:44'!adaptToFraction: rcvr andSend: selector "If I am involved in arithmetic with a Fraction, convert us and evaluate exprBlock." ^ self subclassResponsibility! !!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:44'!adaptToInteger: rcvr andSend: selector "If I am involved in arithmetic with a Integer, convert us and evaluate exprBlock." ^ self subclassResponsibility! !!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:44'!adaptToPoint: rcvr andSend: selector "If I am involved in arithmetic with a Point, convert me to a Point." ^ rcvr perform: selector with: self@self! !!Number methodsFor: 'converting' stamp: 'di 11/6/1998 13:45'!adaptToString: rcvr andSend: selector "If I am involved in arithmetic with a String, convert it to a Number." ^ rcvr asNumber perform: selector with: self! !!Number methodsFor: 'converting' stamp: 'ar 5/20/2001 01:40'!asB3DVector3 ^self@self@self! !!Number methodsFor: 'converting' stamp: 'brp 5/13/2003 10:13'!asDuration ^ Duration nanoSeconds: self asInteger ! !!Number methodsFor: 'converting' stamp: 'RAH 4/25/2000 19:49'!asFloatD "Answer a d precision floating-point number approximating the receiver." #Numeric. "add 200/01/19 For ANSI <number> protocol." ^ self asFloat! !!Number methodsFor: 'converting' stamp: 'RAH 4/25/2000 19:49'!asFloatE "Answer a floating-point number approximating the receiver." #Numeric. "add 200/01/19 For ANSI <number> protocol." ^ self asFloat! !!Number methodsFor: 'converting' stamp: 'RAH 4/25/2000 19:49'!asFloatQ "Answer a floating-point number approximating the receiver." #Numeric. "add 200/01/19 For ANSI <number> protocol." ^ self asFloat! !!Number methodsFor: 'converting'!asInteger "Answer an Integer nearest the receiver toward zero." ^self truncated! !!Number methodsFor: 'converting' stamp: 'sw 2/16/1999 18:15'!asNumber ^ self! !!Number methodsFor: 'converting'!asPoint "Answer a Point with the receiver as both coordinates; often used to supply the same value in two dimensions, as with symmetrical gridding or scaling." ^self @ self! !!Number methodsFor: 'converting' stamp: 'dtl 9/25/2004 11:47'!asScaledDecimal "Answer a scaled decimal number approximating the receiver." #Numeric. ^ self asScaledDecimal: 8! !!Number methodsFor: 'converting' stamp: 'nice 5/16/2009 22:46'!asScaledDecimal: scale "Answer the receiver converted to a ScaledDecimal." ^ ScaledDecimal newFromNumber: self scale: scale! !!Number methodsFor: 'converting' stamp: 'sw 9/8/97 16:30'!asSmallAngleDegrees "Return the receiver normalized to lie within the range (-180, 180)" | pos | pos := self \\ 360. pos > 180 ifTrue: [pos := pos - 360]. ^ pos"#(-500 -300 -150 -5 0 5 150 300 500 1200) collect: [:n | n asSmallAngleDegrees]"! !!Number methodsFor: 'converting' stamp: 'nice 10/5/2009 21:28'!asSmallPositiveDegrees "Return the receiver normalized to lie within the range (0, 360)" ^self \\ 360! !!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:12'!day ^ self sign days! !!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:56'!days ^ Duration days: self! !!Number methodsFor: 'converting'!degreesToRadians "The receiver is assumed to represent degrees. Answer the conversion to radians." ^self asFloat degreesToRadians! !!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:28'!hour ^ self sign hours ! !!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:56'!hours ^ Duration hours: self! !!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:26'!milliSecond ^ self sign milliSeconds ! !!Number methodsFor: 'converting' stamp: 'brp 9/25/2003 13:16'!milliSeconds ^ Duration milliSeconds: self ! !!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:16'!minute ^ self sign minutes ! !!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:56'!minutes ^ Duration minutes: self! !!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:27'!nanoSecond ^ self sign nanoSeconds ! !!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 08:52'!nanoSeconds ^ Duration nanoSeconds: self.! !!Number methodsFor: 'converting'!radiansToDegrees "The receiver is assumed to represent radians. Answer the conversion to degrees." ^self asFloat radiansToDegrees! !!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:17'!second ^ self sign seconds ! !!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:57'!seconds ^ Duration seconds: self! !!Number methodsFor: 'converting' stamp: 'brp 1/9/2004 06:19'!week ^ self sign weeks ! !!Number methodsFor: 'converting' stamp: 'brp 5/16/2003 07:57'!weeks ^ Duration weeks: self! !!Number methodsFor: 'intervals'!to: stop "Answer an Interval from the receiver up to the argument, stop, incrementing by 1." ^Interval from: self to: stop by: 1! !!Number methodsFor: 'intervals'!to: stop by: step "Answer an Interval from the receiver up to the argument, stop, incrementing by step." ^Interval from: self to: stop by: step! !!Number methodsFor: 'intervals' stamp: 'tao 1/30/1999 08:58'!to: stop by: step do: aBlock "Normally compiled in-line, and therefore not overridable. Evaluate aBlock for each element of the interval (self to: stop by: step)." | nextValue | nextValue := self. step = 0 ifTrue: [self error: 'step must be non-zero']. step < 0 ifTrue: [[stop <= nextValue] whileTrue: [aBlock value: nextValue. nextValue := nextValue + step]] ifFalse: [[stop >= nextValue] whileTrue: [aBlock value: nextValue. nextValue := nextValue + step]]! !!Number methodsFor: 'intervals'!to: stop do: aBlock "Normally compiled in-line, and therefore not overridable. Evaluate aBlock for each element of the interval (self to: stop by: 1)." | nextValue | nextValue := self. [nextValue <= stop] whileTrue: [aBlock value: nextValue. nextValue := nextValue + 1]! !!Number methodsFor: 'mathematical functions'!arcCos "The receiver is the cosine of an angle. Answer the angle measured in radians." ^self asFloat arcCos! !!Number methodsFor: 'mathematical functions'!arcSin "The receiver is the sine of an angle. Answer the angle measured in radians." ^self asFloat arcSin! !!Number methodsFor: 'mathematical functions'!arcTan "The receiver is the tangent of an angle. Answer the angle measured in radians." ^self asFloat arcTan! !!Number methodsFor: 'mathematical functions' stamp: 'jsp 2/24/1999 15:20'!arcTan: denominator "The receiver is the tangent of an angle. Answer the angle measured in radians." ^(self asFloat) arcTan: denominator.! !!Number methodsFor: 'mathematical functions' stamp: 'Janniklaval 10/23/2010 13:45'!copySignTo: aNumber "Return a number with same magnitude as aNumber and same sign as self." ^ self positive ifTrue: [aNumber abs] ifFalse: [aNumber abs negated].! !!Number methodsFor: 'mathematical functions'!cos "The receiver represents an angle measured in radians. Answer its cosine." ^self asFloat cos! !!Number methodsFor: 'mathematical functions' stamp: 'nice 10/31/2010 22:03'!degreeCos "Answer the cosine of the receiver taken as an angle in degrees." ^ (90 - (180 + self \\ 360 - 180) abs) degreesToRadians sin! !!Number methodsFor: 'mathematical functions' stamp: 'nice 10/31/2010 22:01'!degreeSin "Answer the sine of the receiver taken as an angle in degrees." ^(90 - self) degreeCos! !!Number methodsFor: 'mathematical functions'!exp "Answer the exponential of the receiver as a floating point number." ^self asFloat exp! !!Number methodsFor: 'mathematical functions' stamp: 'jm 3/27/98 06:16'!floorLog: radix "Answer the floor of the log base radix of the receiver." ^ self asFloat floorLog: radix! !!Number methodsFor: 'mathematical functions' stamp: 'ar 8/31/2000 20:05'!interpolateTo: aNumber at: param ^self + (aNumber - self * param)! !!Number methodsFor: 'mathematical functions'!ln "Answer the natural log of the receiver." ^self asFloat ln! !!Number methodsFor: 'mathematical functions' stamp: 'di 9/8/1998 17:10'!log "Answer the base-10 log of the receiver." ^self asFloat log! !!Number methodsFor: 'mathematical functions'!log: aNumber "Answer the log base aNumber of the receiver." ^self ln / aNumber ln! !!Number methodsFor: 'mathematical functions' stamp: 'nice 12/6/2007 21:46'!raisedTo: aNumber "Answer the receiver raised to aNumber." aNumber isInteger ifTrue: ["Do the special case of integer power" ^ self raisedToInteger: aNumber]. self < 0 ifTrue: [ self error: self printString, ' raised to a non-integer power' ]. 0 = aNumber ifTrue: [^ self class one]. "Special case of exponent=0" 1 = aNumber ifTrue: [^ self]. "Special case of exponent=1" 0 = self ifTrue: [ "Special case of self = 0" aNumber < 0 ifTrue: [^ (ZeroDivide dividend: self) signal] ifFalse: [^ self]]. ^ (aNumber * self ln) exp "Otherwise use logarithms"! !!Number methodsFor: 'mathematical functions' stamp: 'GabrielOmarCotelli 5/26/2009 19:49'!raisedToInteger: anInteger "The 0 raisedToInteger: 0 is an special case. In some contexts must be 1 and in others must be handled as an indeterminate form. I take the first context because that's the way that was previously handled. Maybe further discussion is required on this topic." |bitProbe result| anInteger negative ifTrue: [^(self raisedToInteger: anInteger negated) reciprocal]. bitProbe := 1 bitShift: anInteger highBit - 1. result := self class one. [ (anInteger bitAnd: bitProbe) = 0 ifFalse: [result := result * self]. bitProbe := bitProbe bitShift: -1. bitProbe > 0 ] whileTrue: [result := result * result]. ^result! !!Number methodsFor: 'mathematical functions'!sign "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0." self > 0 ifTrue: [^1]. self < 0 ifTrue: [^-1]. ^0! !!Number methodsFor: 'mathematical functions' stamp: 'Janniklaval 10/23/2010 13:47'!sign: aNumber "Return a Number with the same sign as aNumber" ^ aNumber copySignTo: self.! !!Number methodsFor: 'mathematical functions'!sin "The receiver represents an angle measured in radians. Answer its sine." ^self asFloat sin! !!Number methodsFor: 'mathematical functions'!sqrt "Answer the square root of the receiver." ^self asFloat sqrt! !!Number methodsFor: 'mathematical functions'!squared "Answer the receiver multipled by itself." ^self * self! !!Number methodsFor: 'mathematical functions'!tan "The receiver represents an angle measured in radians. Answer its tangent." ^self asFloat tan! !!Number methodsFor: 'printing' stamp: 'sw 6/29/1999 21:10'!isOrAreStringWith: aNoun | result | result := self = 1 ifTrue: [' is one '] ifFalse: [self = 0 ifTrue: [' are no '] ifFalse: [' are ', self printString, ' ']]. result := result, aNoun. self = 1 ifFalse: [result := result, 's']. ^ result"#(0 1 2 98.6) do: [:num | Transcript cr; show: 'There', (num isOrAreStringWith: 'way'), ' to skin a cat']"! !!Number methodsFor: 'printing' stamp: 'laza 3/29/2004 12:53'!printOn: aStream self printOn: aStream base: 10! !!Number methodsFor: 'printing' stamp: 'nice 9/25/2007 02:36'!printOn: aStream base: base "This method should print a representation of the number for the given base, excluding the base prefix (and the letter r for radix)" ^self subclassResponsibility! !!Number methodsFor: 'printing' stamp: 'nice 3/29/2011 21:48'!printOn: aStream showingDecimalPlaces: placesDesired "Print a representation of the receiver on aStream in decimal notation with prescribed number of places after decimal separator." | rounder rounded roundedFractionPart | placesDesired <= 0 ifTrue: [^ self rounded printOn: aStream]. rounder := 10 raisedToInteger: placesDesired. rounded := self roundTo: rounder reciprocal. rounded negative ifTrue: [aStream nextPut: $-]. rounded := rounded abs. rounded integerPart truncated printOn: aStream. aStream nextPut: $.. roundedFractionPart := (rounded fractionPart * rounder) truncated. roundedFractionPart printOn: aStream base: 10 length: placesDesired padded: true! !!Number methodsFor: 'printing' stamp: 'nice 3/29/2011 21:39'!printShowingDecimalPlaces: placesDesired "Print the receiver showing precisely the given number of places desired. If placesDesired is positive, a decimal point and that many digits after the decimal point will always be shown. If placesDesired is zero, a whole number will be shown, without a decimal point." ^String new: placesDesired + 10 streamContents: [:aStream | self printOn: aStream showingDecimalPlaces: placesDesired]"23 printShowingDecimalPlaces: 223.5698 printShowingDecimalPlaces: 2-234.567 printShowingDecimalPlaces: 523.4567 printShowingDecimalPlaces: 023.5567 printShowingDecimalPlaces: 0-23.4567 printShowingDecimalPlaces: 0-23.5567 printShowingDecimalPlaces: 0100000000 printShowingDecimalPlaces: 10.98 printShowingDecimalPlaces: 5-0.98 printShowingDecimalPlaces: 22.567 printShowingDecimalPlaces: 2-2.567 printShowingDecimalPlaces: 20 printShowingDecimalPlaces: 2"! !!Number methodsFor: 'printing' stamp: 'laza 3/30/2004 10:50'!printString ^self printStringBase: 10! !!Number methodsFor: 'printing'!printStringBase: base ^ String streamContents: [:strm | self printOn: strm base: base]! !!Number methodsFor: 'printing' stamp: 'laza 3/29/2004 12:50'!storeOn: aStream self printOn: aStream! !!Number methodsFor: 'printing' stamp: 'nice 9/25/2007 02:35'!storeOn: aStream base: base "This method should print a representation of the number for the given base, including the base prefix (with letter r for radix)" ^self subclassResponsibility! !!Number methodsFor: 'printing'!storeStringBase: base ^ String streamContents: [:strm | self storeOn: strm base: base]! !!Number methodsFor: 'printing' stamp: 'sw 7/1/1998 12:33'!stringForReadout ^ self rounded printString! !!Number methodsFor: 'testing'!even "Answer whether the receiver is an even number." ^self \\ 2 = 0! !!Number methodsFor: 'testing' stamp: 'sw 12/30/1998 13:21'!isDivisibleBy: aNumber aNumber = 0 ifTrue: [^ false]. aNumber isInteger ifFalse: [^ false]. ^ (self \\ aNumber) = 0! !!Number methodsFor: 'testing' stamp: 'tao 4/19/98 23:33'!isInfinite ^ false! !!Number methodsFor: 'testing' stamp: 'tao 10/10/97 16:36'!isNaN ^ false! !!Number methodsFor: 'testing'!isNumber ^ true! !!Number methodsFor: 'testing'!isZero ^self = 0! !!Number methodsFor: 'testing' stamp: 'di 4/23/1998 11:18'!negative "Answer whether the receiver is mathematically negative." ^ self < 0! !!Number methodsFor: 'testing'!odd "Answer whether the receiver is an odd number." ^self even == false! !!Number methodsFor: 'testing' stamp: 'di 4/23/1998 11:17'!positive "Answer whether the receiver is positive or equal to 0. (ST-80 protocol). See also strictlyPositive" ^ self >= 0! !!Number methodsFor: 'testing' stamp: 'di 4/23/1998 11:02'!strictlyPositive "Answer whether the receiver is mathematically positive." ^ self > 0! !!Number methodsFor: 'truncation and round off'!ceiling "Answer the integer nearest the receiver toward positive infinity." self <= 0.0 ifTrue: [^self truncated] ifFalse: [^self negated floor negated]! !!Number methodsFor: 'truncation and round off' stamp: 'di 2/19/98 21:58'!detentBy: detent atMultiplesOf: grid snap: snap "Map all values that are within detent/2 of any multiple of grid to that multiple. Otherwise, if snap is true, return self, meaning that the values in the dead zone will never be returned. If snap is false, then expand the range between dead zones so that it covers the range between multiples of the grid, and scale the value by that factor." | r1 r2 | r1 := self roundTo: grid. "Nearest multiple of grid" (self roundTo: detent) = r1 ifTrue: [^ r1]. "Snap to that multiple..." snap ifTrue: [^ self]. "...or return self" r2 := self < r1 "Nearest end of dead zone" ifTrue: [r1 - (detent asFloat/2)] ifFalse: [r1 + (detent asFloat/2)]. "Scale values between dead zones to fill range between multiples" ^ r1 + ((self - r2) * grid asFloat / (grid - detent))" (170 to: 190 by: 2) collect: [:a | a detentBy: 10 atMultiplesOf: 90 snap: true] (170 to: 190 by: 2) collect: [:a | a detentBy: 10 atMultiplesOf: 90 snap: false] (3.9 to: 4.1 by: 0.02) collect: [:a | a detentBy: 0.1 atMultiplesOf: 1.0 snap: true] (-3.9 to: -4.1 by: -0.02) collect: [:a | a detentBy: 0.1 atMultiplesOf: 1.0 snap: false]"! !!Number methodsFor: 'truncation and round off'!floor "Answer the integer nearest the receiver toward negative infinity." | truncation | truncation := self truncated. self >= 0 ifTrue: [^truncation]. self = truncation ifTrue: [^truncation] ifFalse: [^truncation - 1]! !!Number methodsFor: 'truncation and round off' stamp: 'StephaneDucasse 5/8/2010 17:14'!fractionPart "Added for ANSI compatibility" ^self - self integerPart! !!Number methodsFor: 'truncation and round off' stamp: 'GabrielOmarCotelli 5/26/2009 21:57'!integerPart "Added for ANSI compatibility" ^self truncated! !!Number methodsFor: 'truncation and round off'!reduce "If self is close to an integer, return that integer" ^ self! !!Number methodsFor: 'truncation and round off' stamp: 'StephaneDucasse 5/8/2010 17:13'!roundDownTo: aNumber "Answer the next multiple of aNumber toward negative infinity that is nearest the receiver." ^(self / aNumber) floor * aNumber! !!Number methodsFor: 'truncation and round off' stamp: 'di 10/4/1999 08:08'!roundTo: quantum "Answer the nearest number that is a multiple of quantum." ^(self / quantum) rounded * quantum! !!Number methodsFor: 'truncation and round off' stamp: 'StephaneDucasse 5/8/2010 17:13'!roundUpTo: aNumber "Answer the next multiple of aNumber toward infinity that is nearest the receiver." ^(self / aNumber) ceiling * aNumber! !!Number methodsFor: 'truncation and round off'!rounded "Answer the integer nearest the receiver." ^(self + (self sign / 2)) truncated! !!Number methodsFor: 'truncation and round off' stamp: 'StephaneDucasse 5/8/2010 17:14'!truncateTo: aNumber "Answer the next multiple of aNumber toward zero that is nearest the receiver." ^(self quo: aNumber) * aNumber! !!Number methodsFor: 'truncation and round off'!truncated "Answer an integer nearest the receiver toward zero." ^self quo: 1! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!Number class instanceVariableNames: ''!!Number class methodsFor: '*System-Settings-Browser' stamp: 'alain.plantec 3/18/2009 15:09'!settingInputWidgetForNode: aSettingNode ^ aSettingNode inputWidgetForNumber! !!Number class methodsFor: 'constants' stamp: 'GabrielOmarCotelli 5/23/2009 20:46'!one ^1! !!Number class methodsFor: 'deprecated' stamp: 'dtl 7/3/2006 17:41'!readExponent: baseValue base: base from: aStream "Complete creation of a number, reading exponent from aStream. Answer the number, or nil if parsing fails. <number>(e|d|q)<exponent>>" | sign exp value | ('edq' includes: aStream next) ifFalse: [^ nil]. sign := ((aStream peek) == $-) ifTrue: [aStream next. -1] ifFalse: [1]. (aStream atEnd or: [(aStream peek digitValue between: 0 and: 9) not]) ifTrue: [^ nil]. "Avoid throwing an error" exp := (Integer readFrom: aStream base: 10) * sign. value := baseValue * (base raisedTo: exp). ^ value! !!Number class methodsFor: 'deprecated' stamp: 'dtl 7/4/2006 08:32'!readRemainderOf: integerPart from: aStream base: base withSign: sign "Read optional fractional part and exponent or decimal scale, and return the final result" "Changed 200/01/19 For ANSI Numeric Literals support." "Number readFrom: '3r-22.2'" | value fractionDigits fracpos fractionPart fraction pos v foundDecimal | #Numeric. value := integerPart. fractionDigits := 0. foundDecimal := false. (aStream peekFor: $.) ifTrue: ["<integer>.<fraction>" foundDecimal := true. (aStream atEnd not and: [aStream peek digitValue between: 0 and: base - 1]) ifTrue: [fracpos := aStream position. fractionPart := Integer readFrom: aStream base: base. fraction := fractionPart asFloat / (base raisedTo: aStream position - fracpos). fractionDigits := aStream position - fracpos. value := value asFloat + fraction]]. pos := aStream position. (v := self readScaledDecimal: integerPart fractionPart: fractionPart digits: fractionDigits base: base sign: sign from: aStream) ifNil: [aStream position: pos] ifNotNil: [^ v "<number>s<scale>>"]. pos := aStream position. (v := self readExponent: value base: base from: aStream) ifNil: [aStream position: pos. (foundDecimal and: [fractionDigits = 0]) ifTrue: ["oops - just <integer>." aStream skip: -1. "un-gobble the period" ^ value * sign]] ifNotNil: [value := v "<number>(e|d|q)<exponent>>"]. (value isFloat and: [value = 0.0 and: [sign = -1]]) ifTrue: [^ Float negativeZero] ifFalse: [^ value * sign]! !!Number class methodsFor: 'deprecated' stamp: 'nice 5/16/2009 22:11'!readScaledDecimal: integerPart fractionPart: fractionPart digits: fractionDigits base: base sign: sign from: aStream "Complete creation of a ScaledDecimal, reading scale from aStream. Answer a ScaledDecimal, or nil if parsing fails. <number>s[<scale>]" | scale decimalMultiplier decimalFraction | aStream atEnd ifTrue: [^ nil]. (aStream next == $s) ifFalse: [^ nil]. "<number>s<scale>" (aStream atEnd not and: [aStream peek digitValue between: 0 and: 9]) ifTrue: [scale := Integer readFrom: aStream] ifFalse: [^ nil]. scale isNil ifTrue: ["<number>s" fractionDigits = 0 ifTrue: ["<integer>s" scale := 0] ifFalse: ["<integer>.<fraction>s" scale := fractionDigits]]. fractionPart isNil ifTrue: [^integerPart * sign asScaledDecimal: scale] ifFalse: [decimalMultiplier := base raisedTo: fractionDigits. decimalFraction := integerPart * decimalMultiplier + fractionPart * sign / decimalMultiplier. ^decimalFraction asScaledDecimal: scale]! !!Number class methodsFor: 'instance creation' stamp: 'nice 10/22/2009 18:46'!readFrom: stringOrStream "Answer a number as described on aStream. The number may be any accepted Smalltalk literal Number format. It can include a leading radix specification, as in 16rFADE. It can as well be NaN, Infinity or -Infinity for conveniency. If stringOrStream does not start with a valid number description, fail." ^(SqNumberParser on: stringOrStream) nextNumber! !!Number class methodsFor: 'instance creation' stamp: 'GuillermoPolito 8/24/2010 18:50'!readFrom: stringOrStream base: base "Answer a number as described on aStream in the given number base. If stringOrStream does not start with a valid number description, answer 0 for backward compatibility. This is not clever and should better be changed." ^(SqNumberParser on: stringOrStream) nextNumberBase: base! !!Number class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 00:42'!readFrom: stringOrStream ifFail: aBlock "Answer a number as described on aStream. The number may be any accepted Smalltalk literal Number format. It can include a leading radix specification, as in 16rFADE. It can as well be NaN, Infinity or -Infinity for conveniency. If input does not represent a valid number, then execute fail block and leave the stream positioned before offending character" ^(SqNumberParser on: stringOrStream) failBlock: aBlock; nextNumber! !!Number class methodsFor: 'instance creation' stamp: 'NikoSchwarz 10/23/2009 13:18'!squeezeNumberOutOfString: stringOrStream "Try and find a number in this string. First, look if the string starts with a number. Then, see if it ends with a number. Then, remove a character from the front and see if the remaining string makes a number. Repeat the process until no characters are left or the number has been found. As soon as a number is found, it is returned. Otherwise, the method fails." ^ SqNumberParser squeezeNumberOutOfString: stringOrStream! !!Number class methodsFor: 'instance creation' stamp: 'NikoSchwarz 10/23/2009 13:19'!squeezeNumberOutOfString: stringOrStream ifFail: aBlock "Try and find a number in this string. First, look if the string starts with a number. Then, see if it ends with a number. Then, remove a character from the front and see if the remaining string makes a number. Repeat the process until no characters are left or the number has been found. As soon as a number is found, it is returned. Otherwise, the method fails." ^ SqNumberParser squeezeNumberOutOfString: stringOrStream onError: aBlock! ! Number subclass: #Fraction instanceVariableNames: 'numerator denominator' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!Fraction commentStamp: 'VeronicaUquillas 6/11/2010 14:04' prior: 0!Fraction provides methods for dealing with fractions like 1/3 as fractions (not as 0.33333...). All public arithmetic operations answer reduced fractions (see examples).instance variables: 'numerator denominator 'Examples: (note the parentheses required to get the right answers in Smalltalk and Pharo):(2/3) + (2/3)(2/3) + (1/2) "answers shows the reduced fraction" (2/3) raisedToInteger: 5 "fractions also can have exponents"!!Fraction methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:58'!* aNumber "Answer the result of multiplying the receiver by aNumber." | d1 d2 | aNumber isFraction ifTrue: [d1 := numerator gcd: aNumber denominator. d2 := denominator gcd: aNumber numerator. (d2 = denominator and: [d1 = aNumber denominator]) ifTrue: [^ numerator // d1 * (aNumber numerator // d2)]. ^ Fraction numerator: numerator // d1 * (aNumber numerator // d2) denominator: denominator // d2 * (aNumber denominator // d1)]. ^ aNumber adaptToFraction: self andSend: #*! !!Fraction methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:58'!+ aNumber "Answer the sum of the receiver and aNumber." | n d d1 d2 | aNumber isFraction ifTrue: [d := denominator gcd: aNumber denominator. n := numerator * (d1 := aNumber denominator // d) + (aNumber numerator * (d2 := denominator // d)). d1 := d1 * d2. n := n // (d2 := n gcd: d). (d := d1 * (d // d2)) = 1 ifTrue: [^ n]. ^ Fraction numerator: n denominator: d]. ^ aNumber adaptToFraction: self andSend: #+! !!Fraction methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:58'!- aNumber "Answer the difference between the receiver and aNumber." aNumber isFraction ifTrue: [^ self + aNumber negated]. ^ aNumber adaptToFraction: self andSend: #-! !!Fraction methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:58'!/ aNumber "Answer the result of dividing the receiver by aNumber." aNumber isFraction ifTrue: [^self * aNumber reciprocal]. ^ aNumber adaptToFraction: self andSend: #/! !!Fraction methodsFor: 'arithmetic'!negated "Refer to the comment in Number|negated." ^ Fraction numerator: numerator negated denominator: denominator! !!Fraction methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:37'!< aNumber aNumber isFraction ifTrue: [^ numerator * aNumber denominator < (aNumber numerator * denominator)]. ^ aNumber adaptToFraction: self andCompare: #<! !!Fraction methodsFor: 'comparing' stamp: 'nice 1/4/2009 17:34'!<= aNumber aNumber isFraction ifTrue: [^ numerator * aNumber denominator <= (aNumber numerator * denominator)]. ^ aNumber adaptToFraction: self andCompare: #<=! !!Fraction methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:41'!= aNumber aNumber isNumber ifFalse: [^ false]. aNumber isFraction ifTrue: [numerator = 0 ifTrue: [^ aNumber numerator = 0]. ^ (numerator * aNumber denominator) = (aNumber numerator * denominator) "Note: used to just compare num and denom, but this fails for improper fractions"]. ^ aNumber adaptToFraction: self andCompare: #=! !!Fraction methodsFor: 'comparing' stamp: 'nice 1/4/2009 17:35'!> aNumber aNumber isFraction ifTrue: [^ numerator * aNumber denominator > (aNumber numerator * denominator)]. ^ aNumber adaptToFraction: self andCompare: #>! !!Fraction methodsFor: 'comparing' stamp: 'nice 1/4/2009 17:35'!>= aNumber aNumber isFraction ifTrue: [^ numerator * aNumber denominator >= (aNumber numerator * denominator)]. ^ aNumber adaptToFraction: self andCompare: #>=! !!Fraction methodsFor: 'comparing' stamp: 'nice 6/11/2009 02:52'!hash "Hash is reimplemented because = is implemented. Care is taken that a Fraction equal to a Float also have an equal hash" | tmp | denominator isPowerOfTwo ifTrue: [ "If denominator is a power of two, I can be exactly equal to a Float" tmp := self asFloat. tmp isFinite ifTrue: [^tmp hash]]. "Else, I cannot be exactly equal to a Float, use own hash algorithm. (Assume the fraction is already reduced)" ^numerator hash bitXor: denominator hash! !!Fraction methodsFor: 'converting' stamp: 'di 11/6/1998 13:10'!adaptToInteger: rcvr andSend: selector "If I am involved in arithmetic with an Integer, convert it to a Fraction." ^ rcvr asFraction perform: selector with: self! !!Fraction methodsFor: 'converting' stamp: 'nice 1/10/2007 02:07'!asFloat "Answer a Float that closely approximates the value of the receiver. This implementation will answer the closest floating point number to the receiver. It uses the IEEE 754 round to nearest even mode (can happen in case denominator is a power of two)" | a b q r exponent floatExponent n ha hb hq q1 | a := numerator abs. b := denominator abs. ha := a highBit. hb := b highBit. "If both numerator and denominator are represented exactly in floating point number, then fastest thing to do is to use hardwired float division" (ha < 54 and: [hb < 54]) ifTrue: [^numerator asFloat / denominator asFloat]. "Try and obtain a mantissa with 54 bits. First guess is rough, we might get one more bit or one less" exponent := ha - hb - 54. exponent > 0 ifTrue: [b := b bitShift: exponent] ifFalse: [a := a bitShift: exponent negated]. q := a quo: b. r := a - (q * b). hq := q highBit. "check for gradual underflow, in which case we should use less bits" floatExponent := exponent + hq - 1. n := floatExponent > -1023 ifTrue: [54] ifFalse: [54 + floatExponent + 1022]. hq > n ifTrue: [exponent := exponent + hq - n. r := (q bitAnd: (1 bitShift: hq - n) - 1) * b + r. q := q bitShift: n - hq]. hq < n ifTrue: [exponent := exponent + hq - n. q1 := (r bitShift: n - hq) quo: b. q := (q bitShift: n - hq) bitAnd: q1. r := (r bitShift: n - hq) - (q1 * b)]. "check if we should round upward. The case of exact half (q bitAnd: 1) isZero not & (r isZero) will be handled by Integer>>asFloat" ((q bitAnd: 1) isZero or: [r isZero]) ifFalse: [q := q + 1]. ^ (self positive ifTrue: [q asFloat] ifFalse: [q asFloat negated]) timesTwoPower: exponent! !!Fraction methodsFor: 'converting'!asFraction "Answer the receiver itself." ^self! !!Fraction methodsFor: 'converting'!isFraction ^ true! !!Fraction methodsFor: 'mathematical functions' stamp: 'nice 5/28/2010 21:01'!ln "This function is defined because super ln might overflow. Note that < 1 is tested before converting to float in order to avoid precision loss due to gradual underflow." | res int | self < 1 ifTrue: [^self reciprocal ln negated]. self <= 0 ifTrue: [self error: 'ln is only defined for x > 0']. res := super ln. res isFinite ifTrue: [^res]. int := self integerPart. ^int ln + (self / int) ln! !!Fraction methodsFor: 'mathematical functions' stamp: 'nice 6/12/2010 00:40'!log "This function is defined because super log might overflow. Note that < 1 is tested before converting to float in order to avoid precision loss due to gradual underflow." | res int | self < 1 ifTrue: [^self reciprocal log negated]. self <= 0 ifTrue: [self error: 'log is only defined for x > 0']. res := super log. res isFinite ifTrue: [^res]. int := self integerPart. ^int log + (self / int) log! !!Fraction methodsFor: 'mathematical functions' stamp: 'LC 4/22/1998 14:03'!raisedToInteger: anInteger "See Number | raisedToInteger:" anInteger = 0 ifTrue: [^ 1]. anInteger < 0 ifTrue: [^ self reciprocal raisedToInteger: anInteger negated]. ^ Fraction numerator: (numerator raisedToInteger: anInteger) denominator: (denominator raisedToInteger: anInteger)! !!Fraction methodsFor: 'mathematical functions' stamp: 'LC 4/22/1998 14:05'!squared "See Fraction (Number) | squared" ^ Fraction numerator: numerator squared denominator: denominator squared! !!Fraction methodsFor: 'printing'!printOn: aStream aStream nextPut: $(. numerator printOn: aStream. aStream nextPut: $/. denominator printOn: aStream. aStream nextPut: $).! !!Fraction methodsFor: 'printing' stamp: 'laza 3/29/2004 12:56'!printOn: aStream base: base aStream nextPut: $(. numerator printOn: aStream base: base. aStream nextPut: $/. denominator printOn: aStream base: base. aStream nextPut: $).! !!Fraction methodsFor: 'printing' stamp: 'nice 3/29/2011 22:56'!printOn: aStream showingDecimalPlaces: placesDesired "Same as super, but provides a faster implementation by inlining some Fraction protocol thus avoiding intermediate Fraction creation." | roundedFractionPart integerPart scaling | placesDesired <= 0 ifTrue: [self rounded printOn: aStream] ifFalse: [scaling := 10 raisedToInteger: placesDesired. integerPart := numerator abs quo: denominator. roundedFractionPart := (numerator abs - (integerPart * denominator)) * scaling * 2 + denominator quo: denominator * 2. roundedFractionPart = scaling ifTrue: [integerPart := integerPart + 1. roundedFractionPart := 0]. "Don't print minus sign if result is rouded to zero" (numerator negative and: [integerPart > 0 or: [roundedFractionPart > 0]]) ifTrue: [aStream nextPut: $-]. integerPart printOn: aStream. aStream nextPut: $.. roundedFractionPart printOn: aStream base: 10 length: placesDesired padded: true].! !!Fraction methodsFor: 'printing' stamp: 'laza 3/29/2004 13:25'!storeOn: aStream base: base aStream nextPut: $(. numerator storeOn: aStream base: base. aStream nextPut: $/. denominator storeOn: aStream base: base. aStream nextPut: $).! !!Fraction methodsFor: 'self evaluating' stamp: 'apb 4/20/2006 18:41'!isSelfEvaluating ^ true! !!Fraction methodsFor: 'testing' stamp: 'ul 11/29/2010 20:05'!negative ^numerator negative! !!Fraction methodsFor: 'truncation and round off'!truncated "Refer to the comment in Number|truncated." ^numerator quo: denominator! !!Fraction methodsFor: 'private'!denominator ^denominator! !!Fraction methodsFor: 'private'!numerator ^numerator! !!Fraction methodsFor: 'private' stamp: 'GabrielOmarCotelli 5/23/2009 20:36'!reciprocal numerator abs = 1 ifTrue: [^denominator * numerator]. ^self class numerator: denominator denominator: numerator! !!Fraction methodsFor: 'private'!reduced | gcd numer denom | numerator = 0 ifTrue: [^0]. gcd := numerator gcd: denominator. numer := numerator // gcd. denom := denominator // gcd. denom = 1 ifTrue: [^numer]. ^Fraction numerator: numer denominator: denom! !!Fraction methodsFor: 'private' stamp: 'tfei 4/12/1999 12:45'!setNumerator: n denominator: d d = 0 ifTrue: [^(ZeroDivide dividend: n) signal] ifFalse: [numerator := n asInteger. denominator := d asInteger abs. "keep sign in numerator" d < 0 ifTrue: [numerator := numerator negated]]! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!Fraction class instanceVariableNames: ''!!Fraction class methodsFor: 'instance creation' stamp: 'di 8/31/1999 10:16'!numerator: numInteger denominator: denInteger "Answer an instance of me (numInteger/denInteger). NOTE: This primitive initialization method will not reduce improper fractions, so normal usage should be coded as, eg, (Fraction numerator: a denominator: b) reduced or, more simply, as a / b." ^self new setNumerator: numInteger denominator: denInteger! ! Number variableWordSubclass: #Float instanceVariableNames: '' classVariableNames: 'E Epsilon Halfpi Infinity Ln10 Ln2 MaxVal MaxValLn MinValLogBase2 NaN NegativeInfinity NegativeZero Pi RadiansPerDegree Sqrt2 ThreePi Twopi' poolDictionaries: '' category: 'Kernel-Numbers'!!Float commentStamp: 'VeronicaUquillas 6/11/2010 14:51' prior: 0!My instances represent IEEE-754 floating-point double-precision numbers. They have about 16 digits of accuracy and their range is between plus and minus 10^307. Some valid examples are: 8.0 13.3 0.3 2.5e6 1.27e-30 1.27e-31 -12.987654e12Mainly: no embedded blanks, little e for tens power, and a digit on both sides of the decimal point. It is actually possible to specify a radix for Float constants. This is great for teaching about numbers, but may be confusing to the average reader: 3r20.2 --> 6.66666666666667 8r20.2 --> 16.25If you don't have access to the definition of IEEE-754, you can figure out what is going on by printing various simple values in Float hex. It may help you to know that the basic format is... sign 1 bit exponent 11 bits with bias of 1023 (16r3FF) to produce an exponent in the range -1023 .. +1024 - 16r000: significand = 0: Float zero significand ~= 0: Denormalized number (exp = -1024, no hidden '1' bit) - 16r7FF: significand = 0: Infinity significand ~= 0: Not A Number (NaN) representation mantissa 53 bits, but only 52 are stored (20 in the first word, 32 in the second). This is because a normalized mantissa, by definition, has a 1 to the right of its floating point, and IEEE-754 omits this redundant bit to gain an extra bit of precision instead. People talk about the mantissa without its leading one as the FRACTION, and with its leading 1 as the SIGNFICAND.The single-precision format is... sign 1 bit exponent 8 bits, with bias of 127, to represent -126 to +127 - 0x0 and 0xFF reserved for Float zero (mantissa is ignored) - 16r7F reserved for Float underflow/overflow (mantissa is ignored) mantissa 24 bits, but only 23 are storedThis format is used in FloatArray (qv), and much can be learned from the conversion routines, Float asIEEE32BitWord, and Float class fromIEEE32Bit:.Thanks to Rich Harmon for asking many questions and to Tim Olson, Bruce Cohen, Rick Zaccone and others for the answers that I have collected here.!!Float methodsFor: 'accessing' stamp: 'eem 4/19/2009 18:03'!at: index ^self basicAt: index! !!Float methodsFor: 'accessing' stamp: 'eem 4/19/2009 18:03'!at: index put: value ^self basicAt: index put: value! !!Float methodsFor: 'accessing' stamp: 'StephaneDucasse 9/24/2010 20:46'!basicAt: index "Primitive. Assumes receiver is indexable. Answer the value of an indexable element in the receiver. Fail if the argument index is not an Integer or is out of bounds. Essential. Do not override in a subclass. See Object documentation whatIsAPrimitive. This version of basicAt: is specifically for floats, answering the most significant word for index 1 and the least significant word for index 2. This alows the VM to store floats in whatever order it chooses while it appears to the image that they are always in big-endian/PowerPC order." <primitive: 38> ^super basicAt: index. ! !!Float methodsFor: 'accessing' stamp: 'StephaneDucasse 9/24/2010 20:47'!basicAt: index put: value "Primitive. Assumes receiver is indexable. Store the second argument value in the indexable element of the receiver indicated by index. Fail if the index is not an Integer or is out of bounds. Or fail if the value is not of the right type for this kind of collection. Answer the value that was stored. Essential. Do not override in a subclass. See Object documentation whatIsAPrimitive. This version of basicAt: is specifically for floats, answering the most significant word for index 1 and the least significant word for index 2. This alows the VM to store floats in whatever order it chooses while it appears to the image that they are always in big-endian/PowerPC order." <primitive: 39> ^super basicAt: index put: value! !!Float methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:54'!* aNumber "Primitive. Answer the result of multiplying the receiver by aNumber. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 49> ^ aNumber adaptToFloat: self andSend: #*! !!Float methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:22'!+ aNumber "Primitive. Answer the sum of the receiver and aNumber. Essential. Fail if the argument is not a Float. See Object documentation whatIsAPrimitive." <primitive: 41> ^ aNumber adaptToFloat: self andSend: #+! !!Float methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:55'!- aNumber "Primitive. Answer the difference between the receiver and aNumber. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 42> ^ aNumber adaptToFloat: self andSend: #-! !!Float methodsFor: 'arithmetic' stamp: 'GabrielOmarCotelli 6/6/2009 17:12'!/ aNumber "Primitive. Answer the result of dividing receiver by aNumber. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 50> aNumber = 0.0 ifTrue: [ ZeroDivide signalWithDividend: self]. ^aNumber adaptToFloat: self andSend: #/! !!Float methodsFor: 'arithmetic' stamp: 'nice 8/21/2010 22:31'!abs "This is faster than using Number abs and works for negativeZero." self <= 0.0 ifTrue: [^ 0.0 - self] ifFalse: [^ self]! !!Float methodsFor: 'arithmetic'!negated "Answer a Number that is the negation of the receiver." ^0.0 - self! !!Float methodsFor: 'arithmetic' stamp: 'GabrielOmarCotelli 5/23/2009 20:40'!reciprocal "Returns the reciprocal. If self is 0.0 the / signals a ZeroDivide" ^1.0 / self! !!Float methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:36'!< aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is less than the argument. Otherwise return false. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 43> ^ aNumber adaptToFloat: self andCompare: #<! !!Float methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:36'!<= aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is less than or equal to the argument. Otherwise return false. Fail if the argument is not a Float. Optional. See Object documentation whatIsAPrimitive." <primitive: 45> ^ aNumber adaptToFloat: self andCompare: #<=! !!Float methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:36'!= aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is equal to the argument. Otherwise return false. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 47> aNumber isNumber ifFalse: [^ false]. ^ aNumber adaptToFloat: self andCompare: #=! !!Float methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:36'!> aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is greater than the argument. Otherwise return false. Fail if the argument is not a Float. Essential. See Object documentation whatIsAPrimitive." <primitive: 44> ^ aNumber adaptToFloat: self andCompare: #>! !!Float methodsFor: 'comparing' stamp: 'nice 7/10/2009 22:14'!>= aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is greater than or equal to the argument. Otherwise return false. Fail if the argument is not a Float. Optional. See Object documentation whatIsAPrimitive. " <primitive: 46> ^ aNumber adaptToFloat: self andCompare: #>=! !!Float methodsFor: 'comparing' stamp: 'nice 7/19/2009 19:27'!closeTo: num "are these two numbers close?" num isNumber ifFalse: [^[self = num] ifError: [false]]. self = 0.0 ifTrue: [^num abs < 0.0001]. num = 0 ifTrue: [^self abs < 0.0001]. ^self = num asFloat or: [(self - num) abs / (self abs max: num abs) < 0.0001]! !!Float methodsFor: 'comparing' stamp: 'nice 6/11/2009 01:03'!hash "Hash is reimplemented because = is implemented. Both words of the float are used; 8 bits are removed from each end to clear most of the exponent regardless of the byte ordering. (The bitAnd:'s ensure that the intermediate results do not become a large integer.) Slower than the original version in the ratios 12:5 to 2:1 depending on values. (DNS, 11 May, 1997)" (self isFinite and: [self fractionPart = 0.0]) ifTrue: [^self truncated hash]. ^ (((self basicAt: 1) bitAnd: 16r00FFFF00) + ((self basicAt: 2) bitAnd: 16r00FFFF00)) bitShift: -8! !!Float methodsFor: 'comparing'!~= aNumber "Primitive. Compare the receiver with the argument and return true if the receiver is not equal to the argument. Otherwise return false. Fail if the argument is not a Float. Optional. See Object documentation whatIsAPrimitive." <primitive: 48> ^super ~= aNumber! !!Float methodsFor: 'converting' stamp: 'nice 1/4/2009 20:31'!adaptToFraction: rcvr andCompare: selector "If I am involved in comparison with a Fraction, convert myself to a Fraction. This way, no bit is lost and comparison is exact." self isFinite ifFalse: [ selector == #= ifTrue: [^false]. selector == #~= ifTrue: [^true]. self isNaN ifTrue: [^ false]. (selector = #< or: [selector = #'<=']) ifTrue: [^ self positive]. (selector = #> or: [selector = #'>=']) ifTrue: [^ self positive not]. ^self error: 'unknow comparison selector']. "Try to avoid asTrueFraction because it can cost" selector == #= ifTrue: [ rcvr denominator isPowerOfTwo ifFalse: [^false]]. selector == #~= ifTrue: [ rcvr denominator isPowerOfTwo ifFalse: [^true]]. ^ rcvr perform: selector with: self asTrueFraction! !!Float methodsFor: 'converting' stamp: 'di 11/6/1998 13:38'!adaptToFraction: rcvr andSend: selector "If I am involved in arithmetic with a Fraction, convert it to a Float." ^ rcvr asFloat perform: selector with: self! !!Float methodsFor: 'converting' stamp: 'nice 1/4/2009 20:31'!adaptToInteger: rcvr andCompare: selector "If I am involved in comparison with an Integer, convert myself to a Fraction. This way, no bit is lost and comparison is exact." self isFinite ifFalse: [ selector == #= ifTrue: [^false]. selector == #~= ifTrue: [^true]. self isNaN ifTrue: [^ false]. (selector = #< or: [selector = #'<=']) ifTrue: [^ self positive]. (selector = #> or: [selector = #'>=']) ifTrue: [^ self positive not]. ^self error: 'unknow comparison selector']. "Try to avoid asTrueFraction because it can cost" selector == #= ifTrue: [ self fractionPart = 0.0 ifFalse: [^false]]. selector == #~= ifTrue: [ self fractionPart = 0.0 ifFalse: [^true]]. ^ rcvr perform: selector with: self asTrueFraction! !!Float methodsFor: 'converting' stamp: 'di 11/6/1998 13:07'!adaptToInteger: rcvr andSend: selector "If I am involved in arithmetic with an Integer, convert it to a Float." ^ rcvr asFloat perform: selector with: self! !!Float methodsFor: 'converting' stamp: 'st 9/17/2004 17:17'!asApproximateFraction "Answer a Fraction approximating the receiver. This conversion uses the continued fraction method to approximate a floating point number." ^ self asApproximateFractionAtOrder: 0! !!Float methodsFor: 'converting' stamp: 'st 9/17/2004 17:14'!asApproximateFractionAtOrder: maxOrder "Answer a Fraction approximating the receiver. This conversion uses the continued fraction method to approximate a floating point number. If maxOrder is zero, use maximum order" | num1 denom1 num2 denom2 int frac newD temp order | num1 := self asInteger. "The first of two alternating numerators" denom1 := 1. "The first of two alternating denominators" num2 := 1. "The second numerator" denom2 := 0. "The second denominator--will update" int := num1. "The integer part of self" frac := self fractionPart. "The fractional part of self" order := maxOrder = 0 ifTrue: [-1] ifFalse: [maxOrder]. [frac = 0 or: [order = 0] ] whileFalse: ["repeat while the fractional part is not zero and max order is not reached" order := order - 1. newD := 1.0 / frac. "Take reciprocal of the fractional part" int := newD asInteger. "get the integer part of this" frac := newD fractionPart. "and save the fractional part for next time" temp := num2. "Get old numerator and save it" num2 := num1. "Set second numerator to first" num1 := num1 * int + temp. "Update first numerator" temp := denom2. "Get old denominator and save it" denom2 := denom1. "Set second denominator to first" denom1 := int * denom1 + temp. "Update first denominator" 10000000000.0 < denom1 ifTrue: ["Is ratio past float precision? If so, pick which of the two ratios to use" num2 = 0.0 ifTrue: ["Is second denominator 0?" ^ Fraction numerator: num1 denominator: denom1]. ^ Fraction numerator: num2 denominator: denom2]]. "If fractional part is zero, return the first ratio" denom1 = 1 ifTrue: ["Am I really an Integer?" ^ num1 "Yes, return Integer result"] ifFalse: ["Otherwise return Fraction result" ^ Fraction numerator: num1 denominator: denom1]! !!Float methodsFor: 'converting'!asFloat "Answer the receiver itself." ^self! !!Float methodsFor: 'converting' stamp: 'sma 5/3/2000 21:46'!asFraction ^ self asTrueFraction ! !!Float methodsFor: 'converting' stamp: 'nice 5/30/2006 02:29'!asIEEE32BitWord "Convert the receiver into a 32 bit Integer value representing the same number in IEEE 32 bit format. Used for conversion in FloatArrays only." | word1 word2 sign mantissa exponent destWord truncatedBits mask roundToUpper | "skip fast positive and nnegative zero" self = 0.0 ifTrue: [^self basicAt: 1]. "retrieve 64 bits of IEEE 754 double" word1 := self basicAt: 1. word2 := self basicAt: 2. "prepare sign exponent and mantissa of 32 bits float" sign := word1 bitAnd: 16r80000000. exponent := ((word1 bitShift: -20) bitAnd: 16r7FF) - 1023 + 127. mantissa := (word2 bitShift: -29) + ((word1 bitAnd: 16rFFFFF) bitShift: 3). truncatedBits := (word2 bitAnd: 16r1FFFFFFF). "We must now honour default IEEE rounding mode (round to nearest even)" "we are below gradual underflow, even if rounded to upper mantissa" exponent < -24 ifTrue: [^sign "this can be negative zero"]. "BEWARE: rounding occurs on less than 23bits when gradual underflow" exponent <= 0 ifTrue: [mask := 1 bitShift: exponent negated. mantissa := mantissa bitOr: 16r800000. roundToUpper := (mantissa bitAnd: mask) isZero not and: [truncatedBits isZero not or: [(mantissa bitAnd: mask - 1) isZero not or: [(mantissa bitAnd: mask*2) isZero not]]]. mantissa := mantissa bitShift: exponent - 1. "exponent := exponent + 1"] ifFalse: [roundToUpper := (truncatedBits bitAnd: 16r10000000) isZero not and: [(mantissa bitAnd: 16r1) isZero not or: [(truncatedBits bitAnd: 16r0FFFFFFF) isZero not]] ]. "adjust mantissa and exponent due to IEEE rounding mode" roundToUpper ifTrue: [mantissa := mantissa + 1. mantissa > 16r7FFFFF ifTrue: [mantissa := 0. exponent := exponent+1]]. exponent > 254 ifTrue: ["Overflow" exponent := 255. self isNaN ifTrue: [mantissa isZero ifTrue: ["BEWARE: do not convert a NaN to infinity due to truncatedBits" mantissa := 1]] ifFalse: [mantissa := 0]]. "Encode the word" destWord := (sign bitOr: ((exponent max: 0) bitShift: 23)) bitOr: mantissa. ^ destWord! !!Float methodsFor: 'converting' stamp: 'nice 3/29/2006 01:01'!asTrueFraction " Answer a fraction that EXACTLY represents self, a double precision IEEE floating point number. Floats are stored in the same form on all platforms. (Does handle gradual underflow but not NANs.) By David N. Smith with significant performance improvements by Luciano Esteban Notarfrancesco. (Version of 11April97)" | signexp positive expPart exp fraction fractionPart signedFraction result zeroBitsCount | self isInfinite ifTrue: [self error: 'Cannot represent infinity as a fraction']. self isNaN ifTrue: [self error: 'Cannot represent Not-a-Number as a fraction']. " Extract the sign and the biased exponent " signexp := (self basicAt: 1) bitShift: -20. positive := (signexp bitAnd: 16r800) = 0. expPart := signexp bitAnd: 16r7FF. " Extract fractional part; answer 0 if this is a true 0.0 value " fractionPart := (((self basicAt: 1) bitAnd: 16rFFFFF) bitShift: 32)+ (self basicAt: 2). ( expPart=0 and: [ fractionPart=0 ] ) ifTrue: [ ^ 0 ]. " Replace omitted leading 1 in fraction unless gradual underflow" fraction := expPart = 0 ifTrue: [fractionPart bitShift: 1] ifFalse: [fractionPart bitOr: 16r0010000000000000]. signedFraction := positive ifTrue: [fraction] ifFalse: [fraction negated]. "Unbias exponent: 16r3FF is bias; 52 is fraction width" exp := 16r3FF + 52 - expPart. " Form the result. When exp>52, the exponent is adjusted by the number of trailing zero bits in the fraction to minimize the (huge) time otherwise spent in #gcd:. " exp negative ifTrue: [ result := signedFraction bitShift: exp negated ] ifFalse: [ zeroBitsCount := fraction lowBit - 1. exp := exp - zeroBitsCount. exp <= 0 ifTrue: [ zeroBitsCount := zeroBitsCount + exp. "exp := 0." " Not needed; exp notrefernced again " result := signedFraction bitShift:zeroBitsCount negated ] ifFalse: [ result := Fraction numerator: (signedFractionbitShift: zeroBitsCount negated) denominator: (1 bitShift:exp) ] ]. "Low cost validation omitted after extensive testing" "(result asFloat = self) ifFalse: [self error: 'asTrueFraction validation failed']." ^ result ! !!Float methodsFor: 'converting'!degreesToRadians "Answer the receiver in radians. Assumes the receiver is in degrees." ^self * RadiansPerDegree! !!Float methodsFor: 'converting'!radiansToDegrees "Answer the receiver in degrees. Assumes the receiver is in radians." ^self / RadiansPerDegree! !!Float methodsFor: 'copying'!deepCopy ^self copy! !!Float methodsFor: 'copying' stamp: 'nice 10/4/2009 23:16'!shallowCopy ^self - 0.0! !!Float methodsFor: 'copying' stamp: 'pmm 3/13/2010 11:30'!veryDeepCopyWith: deepCopier "Return self. Do not record me." ^ self shallowCopy! !!Float methodsFor: 'mathematical functions'!arcCos "Answer the angle in radians." ^ Halfpi - self arcSin! !!Float methodsFor: 'mathematical functions' stamp: 'jsp 2/25/1999 11:15'!arcSin "Answer the angle in radians." ((self < -1.0) or: [self > 1.0]) ifTrue: [self error: 'Value out of range']. ((self = -1.0) or: [self = 1.0]) ifTrue: [^ Halfpi * self] ifFalse: [^ (self / (1.0 - (self * self)) sqrt) arcTan]! !!Float methodsFor: 'mathematical functions'!arcTan "Answer the angle in radians. Optional. See Object documentation whatIsAPrimitive." | theta eps step sinTheta cosTheta | <primitive: 57> "Newton-Raphson" self < 0.0 ifTrue: [ ^ 0.0 - (0.0 - self) arcTan ]. "first guess" theta := (self * Halfpi) / (self + 1.0). "iterate" eps := Halfpi * Epsilon. step := theta. [(step * step) > eps] whileTrue: [ sinTheta := theta sin. cosTheta := theta cos. step := (sinTheta * cosTheta) - (self * cosTheta * cosTheta). theta := theta - step]. ^ theta! !!Float methodsFor: 'mathematical functions' stamp: 'nice 10/30/2009 22:21'!arcTan: denominator "Answer the angle in radians. Optional. See Object documentation whatIsAPrimitive. Implementation note: use sign in order to catch cases of negativeZero" ^self = 0.0 ifTrue: [denominator sign >= 0 ifTrue: [ 0 ] ifFalse: [ self sign >= 0 ifTrue: [ Pi ] ifFalse: [ Pi negated ]]] ifFalse: [denominator = 0.0 ifTrue: [self > 0.0 ifTrue: [ Halfpi ] ifFalse: [ Halfpi negated ]] ifFalse: [denominator > 0 ifTrue: [ (self / denominator) arcTan ] ifFalse: [self > 0 ifTrue: [ ((self / denominator) arcTan) + Pi ] ifFalse: [ ((self / denominator) arcTan) - Pi ]]]]! !!Float methodsFor: 'mathematical functions' stamp: 'Janniklaval 10/23/2010 13:43'!copySignTo: aNumber "Return a number with same magnitude as aNumber and same sign as self. Implementation note: take care of Float negativeZero, which is considered as having a negative sign." (self > 0 or: [(self at: 1) = 0]) ifTrue: [^ aNumber abs]. ^aNumber abs negated! !!Float methodsFor: 'mathematical functions'!cos "Answer the cosine of the receiver taken as an angle in radians." ^ (self + Halfpi) sin! !!Float methodsFor: 'mathematical functions' stamp: 'nice 11/1/2010 11:56'!degreeCos "Take care of exceptional values" self isFinite ifTrue: [^super degreeCos]. ^self degreesToRadians cos! !!Float methodsFor: 'mathematical functions' stamp: 'nice 11/1/2010 11:56'!degreeSin "Take care of exceptional values" self isFinite ifTrue: [^super degreeSin]. ^self degreesToRadians sin! !!Float methodsFor: 'mathematical functions'!exp "Answer E raised to the receiver power. Optional. See Object documentation whatIsAPrimitive." | base fract correction delta div | <primitive: 59> "Taylor series" "check the special cases" self < 0.0 ifTrue: [^ (self negated exp) reciprocal]. self = 0.0 ifTrue: [^ 1]. self abs > MaxValLn ifTrue: [self error: 'exp overflow']. "get first approximation by raising e to integer power" base := E raisedToInteger: (self truncated). "now compute the correction with a short Taylor series" "fract will be 0..1, so correction will be 1..E" "in the worst case, convergance time is logarithmic with 1/Epsilon" fract := self fractionPart. fract = 0.0 ifTrue: [ ^ base ]. "no correction required" correction := 1.0 + fract. delta := fract * fract / 2.0. div := 2.0. [delta > Epsilon] whileTrue: [ correction := correction + delta. div := div + 1.0. delta := delta * fract / div]. correction := correction + delta. ^ base * correction! !!Float methodsFor: 'mathematical functions' stamp: 'jm 3/27/98 06:28'!floorLog: radix "Answer the floor of the log base radix of the receiver." ^ (self log: radix) floor! !!Float methodsFor: 'mathematical functions'!ln "Answer the natural logarithm of the receiver. Optional. See Object documentation whatIsAPrimitive." | expt n mant x div pow delta sum eps | <primitive: 58> "Taylor series" self <= 0.0 ifTrue: [self error: 'ln is only defined for x > 0.0']. "get a rough estimate from binary exponent" expt := self exponent. n := Ln2 * expt. mant := self timesTwoPower: 0 - expt. "compute fine correction from mantinssa in Taylor series" "mant is in the range [0..2]" "we unroll the loop to avoid use of abs" x := mant - 1.0. div := 1.0. pow := delta := sum := x. x := x negated. "x <= 0" eps := Epsilon * (n abs + 1.0). [delta > eps] whileTrue: [ "pass one: delta is positive" div := div + 1.0. pow := pow * x. delta := pow / div. sum := sum + delta. "pass two: delta is negative" div := div + 1.0. pow := pow * x. delta := pow / div. sum := sum + delta]. ^ n + sum "2.718284 ln 1.0"! !!Float methodsFor: 'mathematical functions'!log "Answer the base 10 logarithm of the receiver." ^ self ln / Ln10! !!Float methodsFor: 'mathematical functions' stamp: 'tao 4/19/98 23:22'!reciprocalFloorLog: radix "Quick computation of (self log: radix) floor, when self < 1.0. Avoids infinite recursion problems with denormalized numbers" | adjust scale n | adjust := 0. scale := 1.0. [(n := radix / (self * scale)) isInfinite] whileTrue: [scale := scale * radix. adjust := adjust + 1]. ^ ((n floorLog: radix) + adjust) negated! !!Float methodsFor: 'mathematical functions' stamp: 'tao 10/15/97 14:23'!reciprocalLogBase2 "optimized for self = 10, for use in conversion for printing" ^ self = 10.0 ifTrue: [Ln2 / Ln10] ifFalse: [Ln2 / self ln]! !!Float methodsFor: 'mathematical functions' stamp: 'laza 12/21/1999 12:15'!safeArcCos "Answer the angle in radians." (self between: -1.0 and: 1.0) ifTrue: [^ self arcCos] ifFalse: [^ self sign arcCos]! !!Float methodsFor: 'mathematical functions' stamp: 'jm 4/28/1998 01:10'!sign "Answer 1 if the receiver is greater than 0, -1 if less than 0, else 0. Handle IEEE-754 negative-zero by reporting a sign of -1" self > 0 ifTrue: [^ 1]. (self < 0 or: [((self at: 1) bitShift: -31) = 1]) ifTrue: [^ -1]. ^ 0! !!Float methodsFor: 'mathematical functions' stamp: 'Janniklaval 10/23/2010 13:44'!sign: aNumber "Return a Number with the same sign as aNumber and same magnitude as self. Implementation is different from super to handle the special case of Float negativeZero." (self = 0.0 and: [aNumber sign negative]) ifTrue: [^Float negativeZero]. ^aNumber copySignTo: self! !!Float methodsFor: 'mathematical functions'!sin "Answer the sine of the receiver taken as an angle in radians. Optional. See Object documentation whatIsAPrimitive." | sum delta self2 i | <primitive: 56> "Taylor series" "normalize to the range [0..Pi/2]" self < 0.0 ifTrue: [^ (0.0 - ((0.0 - self) sin))]. self > Twopi ifTrue: [^ (self \\ Twopi) sin]. self > Pi ifTrue: [^ (0.0 - (self - Pi) sin)]. self > Halfpi ifTrue: [^ (Pi - self) sin]. "unroll loop to avoid use of abs" sum := delta := self. self2 := 0.0 - (self * self). i := 2.0. [delta > Epsilon] whileTrue: [ "once" delta := (delta * self2) / (i * (i + 1.0)). i := i + 2.0. sum := sum + delta. "twice" delta := (delta * self2) / (i * (i + 1.0)). i := i + 2.0. sum := sum + delta]. ^ sum! !!Float methodsFor: 'mathematical functions' stamp: 'RAH 4/25/2000 19:49'!sqrt "Answer the square root of the receiver. Optional. See Object documentation whatIsAPrimitive." | exp guess eps delta | <primitive: 55> #Numeric. "Changed 200/01/19 For ANSI <number> support." "Newton-Raphson" self <= 0.0 ifTrue: [self = 0.0 ifTrue: [^ 0.0] ifFalse: ["v Chg" ^ FloatingPointException signal: 'undefined if less than zero.']]. "first guess is half the exponent" exp := self exponent // 2. guess := self timesTwoPower: 0 - exp. "get eps value" eps := guess * Epsilon. eps := eps * eps. delta := self - (guess * guess) / (guess * 2.0). [delta * delta > eps] whileTrue: [guess := guess + delta. delta := self - (guess * guess) / (guess * 2.0)]. ^ guess! !!Float methodsFor: 'mathematical functions'!tan "Answer the tangent of the receiver taken as an angle in radians." ^ self sin / self cos! !!Float methodsFor: 'mathematical functions'!timesTwoPower: anInteger "Primitive. Answer with the receiver multiplied by 2.0 raised to the power of the argument. Optional. See Object documentation whatIsAPrimitive." <primitive: 54> anInteger < -29 ifTrue: [^ self * (2.0 raisedToInteger: anInteger)]. anInteger < 0 ifTrue: [^ self / (1 bitShift: (0 - anInteger)) asFloat]. anInteger < 30 ifTrue: [^ self * (1 bitShift: anInteger) asFloat]. ^ self * (2.0 raisedToInteger: anInteger)! !!Float methodsFor: 'printing' stamp: 'tao 4/19/98 23:21'!absPrintExactlyOn: aStream base: base "Print my value on a stream in the given base. Assumes that my value is strictly positive; negative numbers, zero, and NaNs have already been handled elsewhere. Based upon the algorithm outlined in: Robert G. Burger and R. Kent Dybvig Printing Floating Point Numbers Quickly and Accurately ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation June 1996. This version guarantees that the printed representation exactly represents my value by using exact integer arithmetic." | fBase significand exp baseExpEstimate be be1 r s mPlus mMinus scale roundingIncludesLimits d tc1 tc2 fixedFormat decPointCount | self isInfinite ifTrue: [aStream nextPutAll: 'Infinity'. ^ self]. fBase := base asFloat. significand := self significandAsInteger. roundingIncludesLimits := significand even. exp := (self exponent - 52) max: MinValLogBase2. baseExpEstimate := (self exponent * fBase reciprocalLogBase2 - 1.0e-10) ceiling. exp >= 0 ifTrue: [be := 1 << exp. significand ~= 16r10000000000000 ifTrue: [r := significand * be * 2. s := 2. mPlus := be. mMinus := be] ifFalse: [be1 := be * 2. r := significand * be1 * 2. s := 4. mPlus := be1. mMinus := be]] ifFalse: [(exp = MinValLogBase2) | (significand ~= 16r10000000000000) ifTrue: [r := significand * 2. s := (1 << (exp negated)) * 2. mPlus := 1. mMinus := 1] ifFalse: [r := significand * 4. s := (1 << (exp negated + 1)) * 2. mPlus := 2. mMinus := 1]]. baseExpEstimate >= 0 ifTrue: [s := s * (base raisedToInteger: baseExpEstimate)] ifFalse: [scale := base raisedToInteger: baseExpEstimate negated. r := r * scale. mPlus := mPlus * scale. mMinus := mMinus * scale]. (r + mPlus > s) | (roundingIncludesLimits & (r + mPlus = s)) ifTrue: [baseExpEstimate := baseExpEstimate + 1] ifFalse: [r := r * base. mPlus := mPlus * base. mMinus := mMinus * base]. (fixedFormat := baseExpEstimate between: -3 and: 6) ifTrue: [decPointCount := baseExpEstimate. baseExpEstimate <= 0 ifTrue: [aStream nextPutAll: ('0.000000' truncateTo: 2 - baseExpEstimate)]] ifFalse: [decPointCount := 1]. [d := r // s. r := r \\ s. (tc1 := (r < mMinus) | (roundingIncludesLimits & (r = mMinus))) | (tc2 := (r + mPlus > s) | (roundingIncludesLimits & (r + mPlus = s)))] whileFalse: [aStream nextPut: (Character digitValue: d). r := r * base. mPlus := mPlus * base. mMinus := mMinus * base. decPointCount := decPointCount - 1. decPointCount = 0 ifTrue: [aStream nextPut: $.]]. tc2 ifTrue: [tc1 not | (tc1 & (r*2 >= s)) ifTrue: [d := d + 1]]. aStream nextPut: (Character digitValue: d). decPointCount > 0 ifTrue: [decPointCount - 1 to: 1 by: -1 do: [:i | aStream nextPut: $0]. aStream nextPutAll: '.0']. fixedFormat ifFalse: [aStream nextPut: $e. aStream nextPutAll: (baseExpEstimate - 1) printString]! !!Float methodsFor: 'printing' stamp: 'tao 4/22/98 11:58'!absPrintOn: aStream base: base "Print my value on a stream in the given base. Assumes that my value is strictly positive; negative numbers, zero, and NaNs have already been handled elsewhere. Based upon the algorithm outlined in: Robert G. Burger and R. Kent Dybvig Printing Floating Point Numbers Quickly and Accurately ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation June 1996. This version performs all calculations with Floats instead of LargeIntegers, and loses about 3 lsbs of accuracy compared to an exact conversion." | significantBits fBase exp baseExpEstimate r s mPlus mMinus scale d tc1 tc2 fixedFormat decPointCount | self isInfinite ifTrue: [aStream nextPutAll: 'Infinity'. ^ self]. significantBits := 50. "approximately 3 lsb's of accuracy loss during conversion" fBase := base asFloat. exp := self exponent. baseExpEstimate := (exp * fBase reciprocalLogBase2 - 1.0e-10) ceiling. exp >= 0 ifTrue: [r := self. s := 1.0. mPlus := 1.0 timesTwoPower: exp - significantBits. mMinus := self significand ~= 1.0 ifTrue: [mPlus] ifFalse: [mPlus / 2.0]] ifFalse: [r := self timesTwoPower: significantBits. s := 1.0 timesTwoPower: significantBits. mMinus := 1.0 timesTwoPower: (exp max: -1024). mPlus := (exp = MinValLogBase2) | (self significand ~= 1.0) ifTrue: [mMinus] ifFalse: [mMinus * 2.0]]. baseExpEstimate >= 0 ifTrue: [s := s * (fBase raisedToInteger: baseExpEstimate). exp = 1023 ifTrue: "scale down to prevent overflow to Infinity during conversion" [r := r / fBase. s := s / fBase. mPlus := mPlus / fBase. mMinus := mMinus / fBase]] ifFalse: [exp < -1023 ifTrue: "scale up to prevent denorm reciprocals overflowing to Infinity" [d := (53 * fBase reciprocalLogBase2 - 1.0e-10) ceiling. scale := fBase raisedToInteger: d. r := r * scale. mPlus := mPlus * scale. mMinus := mMinus * scale. scale := fBase raisedToInteger: (baseExpEstimate + d) negated] ifFalse: [scale := fBase raisedToInteger: baseExpEstimate negated]. s := s / scale]. (r + mPlus >= s) ifTrue: [baseExpEstimate := baseExpEstimate + 1] ifFalse: [s := s / fBase]. (fixedFormat := baseExpEstimate between: -3 and: 6) ifTrue: [decPointCount := baseExpEstimate. baseExpEstimate <= 0 ifTrue: [aStream nextPutAll: ('0.000000' truncateTo: 2 - baseExpEstimate)]] ifFalse: [decPointCount := 1]. [d := (r / s) truncated. r := r - (d * s). (tc1 := r <= mMinus) | (tc2 := r + mPlus >= s)] whileFalse: [aStream nextPut: (Character digitValue: d). r := r * fBase. mPlus := mPlus * fBase. mMinus := mMinus * fBase. decPointCount := decPointCount - 1. decPointCount = 0 ifTrue: [aStream nextPut: $.]]. tc2 ifTrue: [tc1 not | (tc1 & (r*2.0 >= s)) ifTrue: [d := d + 1]]. aStream nextPut: (Character digitValue: d). decPointCount > 0 ifTrue: [decPointCount - 1 to: 1 by: -1 do: [:i | aStream nextPut: $0]. aStream nextPutAll: '.0']. fixedFormat ifFalse: [aStream nextPut: $e. aStream nextPutAll: (baseExpEstimate - 1) printString]! !!Float methodsFor: 'printing' stamp: 'StephaneDucasse 7/21/2010 17:41'!hex ^ String streamContents: [:strm | | word nibble | 1 to: 2 do: [:i | word := self at: i. 1 to: 8 do: [:s | nibble := (word bitShift: -8+s*4) bitAnd: 16rF. strm nextPut: ('0123456789ABCDEF' at: nibble+1)]]]"(-2.0 to: 2.0) collect: [:f | f hex]"! !!Float methodsFor: 'printing' stamp: 'Nice 10/31/2010 22:50'!printOn: aStream base: base "Handle sign, zero, and NaNs; all other values passed to absPrintOn:base:" self isNaN ifTrue: [aStream nextPutAll: 'NaN'. ^ self]. "check for NaN before sign" self > 0.0 ifTrue: [self absPrintExactlyOn: aStream base: base] ifFalse: [self sign = -1 ifTrue: [aStream nextPutAll: '-']. self = 0.0 ifTrue: [aStream nextPutAll: '0.0'. ^ self] ifFalse: [self negated absPrintExactlyOn: aStream base: base]]! !!Float methodsFor: 'printing' stamp: 'StephaneDucasse 2/28/2011 09:22'!printPaddedWith: aCharacter to: aNumber "Answer the string containing the ASCII representation of the receiver padded on the left with aCharacter to be at least on aNumber integerPart characters and padded the right with aCharacter to be at least anInteger fractionPart characters." | aStream digits fPadding fLen iPadding iLen curLen periodIndex | #Numeric. "2000/03/04 Harmon R. Added Date and Time support" aStream := (String new: 10) writeStream. self printOn: aStream. digits := aStream contents. periodIndex := digits indexOf: $.. curLen := periodIndex - 1. iLen := aNumber integerPart. curLen < iLen ifTrue: [iPadding := (String new: (iLen - curLen) asInteger) atAllPut: aCharacter; yourself] ifFalse: [iPadding := '']. curLen := digits size - periodIndex. "n.b. Treat aNumber as a string format specifier rather than as a number, because floating point truncation can produce incorrect results for the fraction part." fLen := (aNumber asString copyAfterLast: $. ) ifNotEmpty: [:s | s asInteger] ifEmpty: [ 0 ]. curLen < fLen ifTrue: [fPadding := (String new: fLen - curLen) atAllPut: aCharacter; yourself] ifFalse: [fPadding := '']. ^ iPadding , digits , fPadding! !!Float methodsFor: 'printing' stamp: 'nice 3/24/2008 16:56'!printShowingDecimalPlaces: placesDesired "This implementation avoids any rounding error caused by rounded or roundTo:" ^self asTrueFraction printShowingDecimalPlaces: placesDesired! !!Float methodsFor: 'printing' stamp: 'nice 3/15/2008 22:41'!storeOn: aStream "Print the Number exactly so it can be interpreted back unchanged" self storeOn: aStream base: 10! !!Float methodsFor: 'printing' stamp: 'nice 10/31/2009 23:45'!storeOn: aStream base: base "Print the Number exactly so it can be interpreted back unchanged" self isFinite ifTrue: [self sign = -1 ifTrue: [aStream nextPutAll: '-']. base = 10 ifFalse: [aStream print: base; nextPut: $r]. self = 0.0 ifTrue: [aStream nextPutAll: '0.0'] ifFalse: [self abs absPrintExactlyOn: aStream base: base]] ifFalse: [self isNaN ifTrue: [aStream nextPutAll: 'Float nan'] ifFalse: [self > 0.0 ifTrue: [aStream nextPutAll: 'Float infinity'] ifFalse: [aStream nextPutAll: 'Float infinity negated']]]! !!Float methodsFor: 'testing' stamp: 'bf 8/20/1999 12:56'!hasContentsInExplorer ^false! !!Float methodsFor: 'testing' stamp: 'nice 3/14/2008 23:45'!isFinite "simple, byte-order independent test for rejecting Not-a-Number and (Negative)Infinity" ^(self - self) = 0.0! !!Float methodsFor: 'testing'!isFloat ^ true! !!Float methodsFor: 'testing' stamp: 'jm 4/30/1998 13:50'!isInfinite "Return true if the receiver is positive or negative infinity." ^ self = Infinity or: [self = NegativeInfinity]! !!Float methodsFor: 'testing' stamp: 'nice 3/14/2008 23:49'!isLiteral "There is no literal representation of NaN. However, there are literal representations of Infinity, like 1.0e1000. But since they are not able to print properly, only case of finite Float is considered." ^self isFinite! !!Float methodsFor: 'testing' stamp: 'tao 10/10/97 16:39'!isNaN "simple, byte-order independent test for Not-a-Number" ^ self ~= self! !!Float methodsFor: 'testing' stamp: 'ar 6/9/2000 18:56'!isPowerOfTwo "Return true if the receiver is an integral power of two. Floats never return true here." ^false! !!Float methodsFor: 'testing' stamp: 'nice 11/1/2009 21:58'!isSelfEvaluating "Float NaN and Float infinity though not literal can be stored as {Float NaN. Float infinity}. Thus all Float are self evaluating" ^true! !!Float methodsFor: 'testing'!isZero ^self = 0.0! !!Float methodsFor: 'truncation and round off'!exponent "Primitive. Consider the receiver to be represented as a power of two multiplied by a mantissa (between one and two). Answer with the SmallInteger to whose power two is raised. Optional. See Object documentation whatIsAPrimitive." | positive | <primitive: 53> self >= 1.0 ifTrue: [^self floorLog: 2]. self > 0.0 ifTrue: [positive := (1.0 / self) exponent. self = (1.0 / (1.0 timesTwoPower: positive)) ifTrue: [^positive negated] ifFalse: [^positive negated - 1]]. self = 0.0 ifTrue: [^-1]. ^self negated exponent! !!Float methodsFor: 'truncation and round off'!fractionPart "Primitive. Answer a Float whose value is the difference between the receiver and the receiver's asInteger value. Optional. See Object documentation whatIsAPrimitive." <primitive: 52> ^self - self truncated asFloat! !!Float methodsFor: 'truncation and round off'!integerPart "Answer a Float whose value is the receiver's truncated value." ^self - self fractionPart! !!Float methodsFor: 'truncation and round off' stamp: 'nice 12/2/2009 17:35'!predecessor | ulp | self isFinite ifFalse: [ (self isNaN or: [self negative]) ifTrue: [^self]. ^Float fmax]. self = 0.0 ifTrue: [^Float fmin negated]. ulp := self ulp. ^self - (0.5 * ulp) = self ifTrue: [self - ulp] ifFalse: [self - (0.5 * ulp)]! !!Float methodsFor: 'truncation and round off' stamp: 'tk 12/30/2000 20:04'!reduce "If self is close to an integer, return that integer" (self closeTo: self rounded) ifTrue: [^ self rounded]! !!Float methodsFor: 'truncation and round off' stamp: 'nice 7/24/2008 01:32'!rounded "Answer the integer nearest the receiver. Implementation note: super would not handle tricky inexact arithmetic" "self assert: 5000000000000001.0 rounded = 5000000000000001" self fractionPart abs < 0.5 ifTrue: [^self truncated] ifFalse: [^self truncated + self sign rounded]! !!Float methodsFor: 'truncation and round off' stamp: 'tao 4/19/98 13:14'!significand ^ self timesTwoPower: (self exponent negated)! !!Float methodsFor: 'truncation and round off' stamp: 'nice 3/23/2008 16:03'!significandAsInteger | exp sig | exp := self exponent. sig := (((self at: 1) bitAnd: 16r000FFFFF) bitShift: 32) bitOr: (self at: 2). (exp > -1023 and: [self ~= 0.0]) ifTrue: [sig := sig bitOr: (1 bitShift: 52)]. ^ sig.! !!Float methodsFor: 'truncation and round off' stamp: 'nice 12/2/2009 17:35'!successor | ulp | self isFinite ifFalse: [ (self isNaN or: [self positive]) ifTrue: [^self]. ^Float fmax negated]. self = 0.0 ifTrue: [^Float fmin]. ulp := self ulp. ^self + (0.5 * ulp) = self ifTrue: [self + ulp] ifFalse: [self + (0.5 * ulp)]! !!Float methodsFor: 'truncation and round off' stamp: 'nice 4/26/2006 05:09'!truncated "Answer with a SmallInteger equal to the value of the receiver without its fractional part. The primitive fails if the truncated value cannot be represented as a SmallInteger. In that case, the code below will compute a LargeInteger truncated value. Essential. See Object documentation whatIsAPrimitive. " <primitive: 51> (self isInfinite or: [self isNaN]) ifTrue: [self error: 'Cannot truncate this number']. self abs < 2.0e16 ifTrue: ["Fastest way when it may not be an integer" "^ (self quo: 1073741823.0) * 1073741823 + (self rem: 1073741823.0) truncated" | di df q r | di := (SmallInteger maxVal bitShift: -1)+1. df := di asFloat. q := self quo: df. r := self - (q asFloat * df). ^q*di+r truncated] ifFalse: [^ self asTrueFraction. "Extract all bits of the mantissa and shift if necess"] ! !!Float methodsFor: 'truncation and round off' stamp: 'nice 12/1/2009 12:07'!ulp "Answer the unit of least precision of self (the power of two corresponding to last bit of mantissa)" | exponent | self isFinite ifFalse: [ self isNaN ifTrue: [^self]. ^Float infinity]. self = 0.0 ifTrue: [^Float fmin]. exponent := self exponent. ^exponent < self class emin ifTrue: [Float fminDenormalized] ifFalse: [Float epsilon timesTwoPower: exponent]! !!Float methodsFor: 'private' stamp: 'nice 8/9/2009 21:01'!absPrintOn: aStream base: base digitCount: digitCount "Print me in the given base, using digitCount significant figures." | fuzz x exp q fBase scale logScale xi | self isInfinite ifTrue: [^ aStream nextPutAll: 'Inf']. fBase := base asFloat. "x is myself normalized to [1.0, fBase), exp is my exponent" exp := self < 1.0 ifTrue: [self reciprocalFloorLog: fBase] ifFalse: [self floorLog: fBase]. scale := 1.0. logScale := 0. [(x := fBase raisedTo: (exp + logScale)) = 0] whileTrue: [scale := scale * fBase. logScale := logScale + 1]. x := self * scale / x. fuzz := fBase raisedTo: 1 - digitCount. "round the last digit to be printed" x := 0.5 * fuzz + x. x >= fBase ifTrue: ["check if rounding has unnormalized x" x := x / fBase. exp := exp + 1]. (exp < 6 and: [exp > -4]) ifTrue: ["decimal notation" q := 0. exp < 0 ifTrue: [1 to: 1 - exp do: [:i | aStream nextPut: ('0.0000'at: i)]]] ifFalse: ["scientific notation" q := exp. exp := 0]. [x >= fuzz] whileTrue: ["use fuzz to track significance" xi := x asInteger. aStream nextPut: (Character digitValue: xi). x := x - xi asFloat * fBase. fuzz := fuzz * fBase. exp := exp - 1. exp = -1 ifTrue: [aStream nextPut: $.]]. [exp >= -1] whileTrue: [aStream nextPut: $0. exp := exp - 1. exp = -1 ifTrue: [aStream nextPut: $.]]. q ~= 0 ifTrue: [aStream nextPut: $e. q printOn: aStream]! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!Float class instanceVariableNames: ''!!Float class methodsFor: 'class initialization' stamp: 'nice 3/15/2008 22:42'!initialize "Float initialize" "Constants from Computer Approximations, pp. 182-183: Pi = 3.14159265358979323846264338327950288 Pi/2 = 1.57079632679489661923132169163975144 Pi*2 = 6.28318530717958647692528676655900576 Pi/180 = 0.01745329251994329576923690768488612 2.0 ln = 0.69314718055994530941723212145817657 2.0 sqrt = 1.41421356237309504880168872420969808" Pi := 3.14159265358979323846264338327950288. Halfpi := Pi / 2.0. Twopi := Pi * 2.0. ThreePi := Pi * 3.0. RadiansPerDegree := Pi / 180.0. Ln2 := 0.69314718055994530941723212145817657. "TODO implement Log" Ln10 := @System.Math !!Log: 10.0. Sqrt2 := 1.41421356237309504880168872420969808. E := 2.718281828459045235360287471353. Epsilon := 0.000000000001. "Defines precision of mathematical functions" "MaxVal := 1.7976931348623157e308." MaxVal := @System.Double !!MaxValue. MaxValLn := 709.782712893384. MinValLogBase2 := -1074. "Infinity := MaxVal * MaxVal. NegativeInfinity := 0.0 - Infinity." Infinity := @System.Double !!PositiveInfinity. NegativeInfinity := @System.Double !!NegativeInfinity. "NaN := Infinity - Infinity." NaN := @System.Double !!NaN. "NegativeZero := 1.0 / Infinity negated."! !!Float class methodsFor: 'constants' stamp: 'nice 6/11/2009 12:29'!denormalized "Answer whether implementation supports denormalized numbers (also known as gradual underflow)." ^true! !!Float class methodsFor: 'constants'!e "Answer the constant, E." ^E! !!Float class methodsFor: 'constants' stamp: 'nice 6/8/2009 15:42'!emax "Answer exponent of maximal representable value" ^1023! !!Float class methodsFor: 'constants' stamp: 'nice 6/8/2009 15:43'!emin "Answer exponent of minimal normalized representable value" ^-1022! !!Float class methodsFor: 'constants' stamp: 'nice 6/11/2009 12:30'!epsilon "Answer difference between 1.0 and previous representable value" ^1.0 timesTwoPower: 1 - self precision! !!Float class methodsFor: 'constants' stamp: 'nice 6/8/2009 15:20'!fmax "Answer the maximum finite floating point value representable." ^MaxVal! !!Float class methodsFor: 'constants' stamp: 'nice 6/8/2009 15:33'!fmin "Answer minimum positive representable value." ^self denormalized ifTrue: [self fminDenormalized] ifFalse: [self fminNormalized]! !!Float class methodsFor: 'constants' stamp: 'nice 6/8/2009 15:22'!fminDenormalized "Answer the minimum denormalized value representable." ^1.0 timesTwoPower: MinValLogBase2! !!Float class methodsFor: 'constants' stamp: 'nice 6/8/2009 15:22'!fminNormalized "Answer the minimum normalized value representable." ^1.0 timesTwoPower: -1022! !!Float class methodsFor: 'constants' stamp: 'sw 10/8/1999 22:59'!halfPi ^ Halfpi! !!Float class methodsFor: 'constants' stamp: 'tao 4/23/98 11:37'!infinity "Answer the value used to represent an infinite magnitude" ^ Infinity! !!Float class methodsFor: 'constants' stamp: 'tao 4/23/98 11:38'!nan "Answer the canonical value used to represent Not-A-Number" ^ NaN! !!Float class methodsFor: 'constants' stamp: 'tao 4/23/98 12:05'!negativeZero ^ NegativeZero! !!Float class methodsFor: 'constants' stamp: 'GabrielOmarCotelli 5/25/2009 15:42'!one ^1.0! !!Float class methodsFor: 'constants'!pi "Answer the constant, Pi." ^Pi! !!Float class methodsFor: 'constants' stamp: 'nice 6/11/2009 12:40'!precision "Answer the apparent precision of the floating point representation. That is the maximum number of radix-based digits (bits if radix=2) representable in floating point without round off error. Technically, 52 bits are stored in the representation, and normalized numbers have an implied leading 1 that does not need to be stored. Note that denormalized floating point numbers don't have the implied leading 1, and thus gradually loose precision. This format conforms IEEE 754 double precision standard." ^53! !!Float class methodsFor: 'constants' stamp: 'nice 6/8/2009 15:16'!radix "Answer the radix used for internal floating point representation." ^2! !!Float class methodsFor: 'constants' stamp: 'yo 6/17/2004 17:44'!threePi ^ ThreePi! !!Float class methodsFor: 'constants' stamp: 'yo 6/17/2004 17:41'!twoPi ^ Twopi! !!Float class methodsFor: 'instance creation' stamp: 'VeronicaUquillas 6/11/2010 14:02'!fromIEEE32Bit: word "Convert the given 32 bit word (which is supposed to be a positive 32bit value) from a 32bit IEEE floating point representation into an actual Pharo float object (being 64bit wide). Should only be used for conversion in FloatArrays or likewise objects." | sign mantissa exponent newFloat delta | word negative ifTrue: [^ self error:'Cannot deal with negative numbers']. word = 0 ifTrue: [^ 0.0]. sign := word bitAnd: 16r80000000. word = sign ifTrue: [^self negativeZero]. exponent := ((word bitShift: -23) bitAnd: 16rFF) - 127. mantissa := word bitAnd: 16r7FFFFF. exponent = 128 ifTrue:["Either NAN or INF" mantissa = 0 ifFalse:[^ Float nan]. sign = 0 ifTrue:[^ Float infinity] ifFalse:[^ Float infinity negated]]. exponent = -127 ifTrue: [ "gradual underflow (denormalized number) Remove first bit of mantissa and adjust exponent" delta := mantissa highBit. mantissa := (mantissa bitShift: 1) bitAnd: (1 bitShift: delta) - 1. exponent := exponent + delta - 23]. "Create new float" newFloat := self new: 2. newFloat basicAt: 1 put: ((sign bitOr: (1023 + exponent bitShift: 20)) bitOr: (mantissa bitShift: -3)). newFloat basicAt: 2 put: ((mantissa bitAnd: 7) bitShift: 29). ^newFloat! !!Float class methodsFor: 'instance creation'!readFrom: aStream "Answer a new Float as described on the stream, aStream." ^(super readFrom: aStream) asFloat! !!Float class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 00:54'!readFrom: aStream ifFail: aBlock "Answer a new Float as described on the stream, aStream." ^(super readFrom: aStream ifFail: [^aBlock value]) asFloat! ! Fraction subclass: #ScaledDecimal instanceVariableNames: 'scale' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!ScaledDecimal commentStamp: 'nice 5/16/2009 20:45' prior: 0!ScaledDecimal implement a special kind of Fraction that prints in decimal notation.It uses a limited number of digits (scale) after the decimal separation dot and round the result.Note that a ScaledDecimal does not printOn: exactly, however it will storeOn: exactly because the full precision fraction is kept in memory.This is mostly usefull with denominators being powers of 10.!!ScaledDecimal methodsFor: 'accessing' stamp: 'nice 5/16/2009 20:56'!scale ^scale! !!ScaledDecimal methodsFor: 'arithmetic' stamp: 'nice 5/17/2009 00:20'!* aNumber aNumber class = self class ifTrue: [^self asFraction * aNumber asFraction asScaledDecimal: (scale max: aNumber scale)]. ^self coerce: self asFraction * aNumber! !!ScaledDecimal methodsFor: 'arithmetic' stamp: 'nice 5/17/2009 00:21'!+ aNumber aNumber class = self class ifTrue: [^self asFraction + aNumber asFraction asScaledDecimal: (scale max: aNumber scale)]. ^self coerce: self asFraction + aNumber! !!ScaledDecimal methodsFor: 'arithmetic' stamp: 'nice 5/17/2009 00:21'!- aNumber aNumber class = self class ifTrue: [^self asFraction - aNumber asFraction asScaledDecimal: (scale max: aNumber scale)]. ^self coerce: self asFraction - aNumber! !!ScaledDecimal methodsFor: 'arithmetic' stamp: 'nice 5/17/2009 00:21'!/ aNumber aNumber class = self class ifTrue: [^self asFraction / aNumber asFraction asScaledDecimal: (scale max: aNumber scale)]. ^self coerce: self asFraction / aNumber! !!ScaledDecimal methodsFor: 'arithmetic' stamp: 'nice 5/16/2009 21:01'!negated ^self class newFromNumber: super negated scale: scale! !!ScaledDecimal methodsFor: 'arithmetic' stamp: 'nice 5/16/2009 21:01'!reciprocal ^self class newFromNumber: super reciprocal scale: scale! !!ScaledDecimal methodsFor: 'arithmetic' stamp: 'nice 5/16/2009 21:01'!squared ^self class newFromNumber: super squared scale: scale! !!ScaledDecimal methodsFor: 'comparing' stamp: 'nice 5/17/2009 00:25'!< aNumber aNumber class = self class ifTrue: [^self asFraction < aNumber asFraction]. ^self asFraction < aNumber! !!ScaledDecimal methodsFor: 'comparing' stamp: 'nice 9/25/2009 23:03'!<= aNumber aNumber class = self class ifTrue: [^self asFraction <= aNumber asFraction]. ^self asFraction <= aNumber! !!ScaledDecimal methodsFor: 'comparing' stamp: 'nice 5/17/2009 00:25'!= aNumber aNumber class = self class ifTrue: [^self asFraction = aNumber asFraction]. ^self asFraction = aNumber! !!ScaledDecimal methodsFor: 'comparing' stamp: 'nice 9/25/2009 23:04'!> aNumber aNumber class = self class ifTrue: [^self asFraction > aNumber asFraction]. ^self asFraction > aNumber! !!ScaledDecimal methodsFor: 'comparing' stamp: 'nice 9/25/2009 23:04'!>= aNumber aNumber class = self class ifTrue: [^self asFraction >= aNumber asFraction]. ^self asFraction >= aNumber! !!ScaledDecimal methodsFor: 'comparing' stamp: 'nice 8/28/2008 19:18'!literalEqual: other "Testing equality is not enough. It is also necessary to test number of decimal places (scale). Otherwise we cannot compile both literals 0.5s1 and 0.50s2 in the same method" ^(super literalEqual: other) and: [self scale = other scale]! !!ScaledDecimal methodsFor: 'converting' stamp: 'nice 5/16/2009 23:53'!adaptToFraction: rcvr andSend: selector "If I am involved in arithmetic with a Fraction, convert it to a ScaledDecimal." ^(rcvr asScaledDecimal: scale) perform: selector with: self! !!ScaledDecimal methodsFor: 'converting' stamp: 'nice 5/16/2009 23:42'!adaptToInteger: rcvr andSend: selector "If I am involved in arithmetic with an Integer, convert it to a ScaledDecimal." ^(rcvr asScaledDecimal: scale) perform: selector with: self! !!ScaledDecimal methodsFor: 'converting' stamp: 'nice 5/17/2009 00:19'!asFraction "Convert the receiver to a Fraction. Avoid using numerator / denominator to save a useless and costly gcd: computation" ^denominator = 1 ifTrue: [numerator] ifFalse: [Fraction numerator: numerator denominator: denominator]! !!ScaledDecimal methodsFor: 'mathematical functions' stamp: 'nice 5/16/2009 21:06'!raisedTo: aNumber ^self coerce: (super raisedTo: aNumber)! !!ScaledDecimal methodsFor: 'mathematical functions' stamp: 'nice 5/16/2009 21:15'!raisedToInteger: aNumber ^self class newFromNumber: (super raisedToInteger: aNumber) scale: scale! !!ScaledDecimal methodsFor: 'printing' stamp: 'nice 3/29/2011 22:39'!printOn: aStream "Append an approximated representation of the receiver on aStream. Use prescribed number of digits after decimal point (the scale) using a rounding operation if not exact" self printOn: aStream showingDecimalPlaces: scale. "Append a scale specification so that the number can be recognized as a ScaledDecimal" aStream nextPut: $s; print: scale.! !!ScaledDecimal methodsFor: 'printing' stamp: 'nice 5/16/2009 21:31'!printOn: aStream base: base base = 10 ifFalse: [self error: 'ScaledDecimals should be printed only in base 10']. ^self printOn: aStream! !!ScaledDecimal methodsFor: 'printing' stamp: 'nice 5/16/2009 21:09'!storeOn: aStream "ScaledDecimal sometimes have more digits than they print (potentially an infinity). In this case, do not use printOn: because it would loose some extra digits." self isLiteral ifTrue: [self printOn: aStream] ifFalse: [aStream nextPut: $(; store: numerator; nextPut: $/; store: denominator; nextPut: $s; store: scale; nextPut: $)]! !!ScaledDecimal methodsFor: 'testing' stamp: 'nice 5/17/2009 00:01'!isFraction "Though kind of Fraction, pretend we are not a Fraction to let coercion works correctly" ^false! !!ScaledDecimal methodsFor: 'testing' stamp: 'nice 5/16/2009 21:11'!isLiteral "Answer if this number could be a well behaved literal. Well, it would only if evaluating back to self. This is not the case of all ScaledDecimals. Some have an infinite precision and would need an infinite number of digits to print literally. Try for example (3.00s2 reciprocal)." ^denominator = 1 "first test trivial case before engaging arithmetic" or: ["Exactly we should test: (numerator * (10 raisedTo; scale)) \\ denominator = 0. But since we can assume fraction is reduced already this will be simply:" (10 raisedTo: scale) \\ denominator = 0]! !!ScaledDecimal methodsFor: 'private' stamp: 'nice 5/17/2009 00:21'!coerce: aNumber "Note: this quick hack could be replaced by double dispatching" aNumber class = self class ifTrue: [^self class newFromNumber: aNumber scale: (scale max: aNumber scale)]. (aNumber isFraction or: [aNumber isInteger]) ifTrue: [^self class newFromNumber: aNumber scale: scale]. ^aNumber! !!ScaledDecimal methodsFor: 'private' stamp: 'nice 5/16/2009 20:54'!setNumerator: n denominator: d scale: s self setNumerator: n denominator: d. scale := s! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!ScaledDecimal class instanceVariableNames: ''!!ScaledDecimal class methodsFor: 'instance creation' stamp: 'nice 5/16/2009 22:23'!newFromNumber: aNumber scale: anInteger | aFraction | aFraction := aNumber asFraction. ^aFraction isFraction ifTrue: [self new setNumerator: aFraction numerator denominator: aFraction denominator scale: anInteger] ifFalse: [self new setNumerator: aFraction denominator: 1 scale: anInteger]! !!ScaledDecimal class methodsFor: 'instance creation' stamp: 'nice 5/16/2009 22:36'!readFrom: stringOrStream "Answer a decimal number as described on stringOrStream. The number may not include a leading radix specification, as in 16rFADE, nor an exponent like 1.0e-3 It might have a scale specification at end or not like 10.3s2 If not, number of digits after decimal point will be used as scale" ^(SqNumberParser on: stringOrStream) nextScaledDecimal! ! Object subclass: #Random instanceVariableNames: 'seed a m q r' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!Random commentStamp: 'MarcusDenker 2/14/2010 22:27' prior: 0!This Random Number Generator graciously contributed by David N. Smith. It is an adaptation of the Park-Miller RNG which uses Floats to avoid the need for LargeInteger arithmetic.If you just want a quick random integer, use: 10 atRandomEvery integer interval can give a random number: (6 to: 12) atRandomSequenceableCollections can give randomly selected elements: 'pick one of these letters randomly' atRandomSequenceableCollections also respond to shuffled, as in: ($A to: $Z) shuffledThe correct way to use class Random is to store one in an instance or class variable: myGenerator := Random new.Then use it every time you need another number between 0.0 and 1.0 (excluding) myGenerator nextYou can also generate a positive integer myGenerator nextInt: 10!!Random methodsFor: 'accessing' stamp: 'sma 5/12/2000 12:25'!next "Answer a random Float in the interval [0 to 1)." ^ (seed := self nextValue) / m! !!Random methodsFor: 'accessing' stamp: 'sma 5/12/2000 12:45'!next: anInteger ^ self next: anInteger into: (Array new: anInteger)! !!Random methodsFor: 'accessing' stamp: 'sma 5/12/2000 12:46'!next: anInteger into: anArray 1 to: anInteger do: [:index | anArray at: index put: self next]. ^ anArray! !!Random methodsFor: 'accessing' stamp: 'gvc 1/31/2007 13:52'!nextInt: anInteger "Answer a random integer in the interval [1, anInteger]. Handle large numbers too (for cryptography)." anInteger strictlyPositive ifFalse: [ self error: 'Range must be positive' ]. anInteger asFloat isInfinite ifTrue: [^(self next asFraction * anInteger) truncated + 1]. ^ (self next * anInteger) truncated + 1! !!Random methodsFor: 'initialization' stamp: 'alain.plantec 5/28/2009 10:17'!initialize " Set a reasonable Park-Miller starting seed " super initialize. [seed := (Time millisecondClockValue bitAnd: 16r3FFFFFFF) bitXor: self hash. seed = 0] whileTrue: ["Try again if ever get a seed = 0"]. a := 16r000041A7 asFloat. " magic constant = 16807 " m := 16r7FFFFFFF asFloat. " magic constant = 2147483647 " q := (m quo: a) asFloat. r := (m \\ a) asFloat.! !!Random methodsFor: 'initialization' stamp: 'sma 5/12/2000 12:29'!seed: anInteger seed := anInteger! !!Random methodsFor: 'private' stamp: 'sma 5/12/2000 12:28'!nextValue "This method generates random instances of Integer in the interval 0 to 16r7FFFFFFF. This method does NOT update the seed; repeated sends answer the same value. The algorithm is described in detail in 'Random Number Generators: Good Ones Are Hard to Find' by Stephen K. Park and Keith W. Miller (Comm. Asso. Comp. Mach., 31(10):1192--1201, 1988)." | lo hi aLoRHi answer | hi := (seed quo: q) asFloat. lo := seed - (hi * q). " = seed rem: q" aLoRHi := (a * lo) - (r * hi). answer := (aLoRHi > 0.0) ifTrue: [aLoRHi] ifFalse: [aLoRHi + m]. ^ answer! !!Random methodsFor: 'private' stamp: 'sma 5/12/2000 12:43'!seed ^ seed! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!Random class instanceVariableNames: ''!!Random class methodsFor: 'instance creation' stamp: 'nk 7/30/2004 21:51'!seed: anInteger ^self new seed: anInteger! !!Random class methodsFor: 'testing' stamp: 'nice 1/5/2010 15:59'!bucketTest: randy "Execute this: Random bucketTest: Random new" " A quick-and-dirty bucket test. Prints nbuckets values on theTranscript. Each should be 'near' the value of ntries. Any run with any value'far' from ntries indicates something is very wrong. Each run generates differentvalues. For a slightly better test, try values of nbuckets of 200-1000 ormore; go get coffee. This is a poor test; see Knuth. Some 'OK' runs: 1000 1023 998 969 997 1018 1030 1019 1054 985 1003 1011 987 982 980 982 974 968 1044 976 1029 1011 1025 1016 997 1019 991 954 968 999 991 978 1035 995 988 1038 1009 988 993 976" | nbuckets buckets ntrys | nbuckets := 20. buckets := Array new: nbuckets. buckets atAllPut: 0. ntrys := 100. ntrys*nbuckets timesRepeat: [ | slot | slot := (randy next * nbuckets) floor + 1. buckets at: slot put: (buckets at: slot) + 1 ]. Transcript cr. 1 to: nbuckets do: [ :nb | Transcript show: (buckets at: nb) printString, ' ' ]! !!Random class methodsFor: 'testing'!theItsCompletelyBrokenTest "Random theItsCompletelyBrokenTest" "The above should print as... (0.149243269650845 0.331633021743797 0.75619644800024 0.393701540023881 0.941783181364547 0.549929193942775 0.659962596213428 0.991354559078512 0.696074432551896 0.922987899707159 ) If they are not these values (accounting for precision of printing) then something is horribly wrong: DO NOT USE THIS CODE FOR ANYTHING. " | rng | rng := Random new. rng seed: 2345678901. ^ (1 to: 10) collect: [:i | rng next]! ! Number subclass: #Integer instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!Integer commentStamp: '<historical>' prior: 0!I am a common abstract superclass for all Integer implementations. My implementation subclasses are SmallInteger, LargePositiveInteger, and LargeNegativeInteger. Integer division consists of: / exact division, answers a fraction if result is not a whole integer // answers an Integer, rounded towards negative infinity \\ is modulo rounded towards negative infinity quo: truncated division, rounded towards zero!!Integer methodsFor: '*Files' stamp: 'cmm 2/15/2010 15:52'!asBytesDescription "Answer a terse, easily-readable representation of this Integer reprsenting a number of bytes. Useful for file-browsers." | suffixes | suffixes := { 'k'"ilobytes". 'M'"egabytes". 'G'"igabytes". 'T'"erabytes". 'P'"etabytes". 'E'"xabytes". 'Z'"ettabytes". 'Y'"ottabytes"}. suffixes size to: 1 by: -1 do: [ : index | | units | units := 1000 raisedTo: index. self > units ifTrue: [ ^ ((self / units) asFloat roundTo: 0.01) asString, (suffixes at: index) ] ]. ^ self asString! !!Integer methodsFor: '*Graphics-Primitives' stamp: 'ar 10/31/1998 23:04'!asColorOfDepth: d "Return a color value representing the receiver as color of the given depth" ^Color colorFromPixelValue: self depth: d! !!Integer methodsFor: '*System-Hashing-Core' stamp: 'PeterHugossonMiller 9/3/2009 10:00'!asArray | stream | stream := Array new writeStream. self digitLength to: 1 by: -1 do: [:digitIndex | stream nextPut: (self digitAt: digitIndex)]. ^ stream contents! !!Integer methodsFor: '*System-Hashing-Core' stamp: 'PeterHugossonMiller 9/3/2009 10:01'!asByteArray | stream | stream := ByteArray new writeStream. self digitLength to: 1 by: -1 do: [:digitIndex | stream nextPut: (self digitAt: digitIndex)]. ^ stream contents! !!Integer methodsFor: '*System-Hashing-Core' stamp: 'StephaneDucasse 10/17/2009 17:15'!asByteArrayOfSize: aSize "Answer a ByteArray of aSize with my value, most-significant byte first." | answer digitPos | aSize < self digitLength ifTrue: [ self error: 'number to large for byte array' ]. answer := ByteArray new: aSize. digitPos := 1. aSize to: aSize - self digitLength + 1 by: -1 do: [ :pos | answer at: pos put: (self digitAt: digitPos). digitPos := digitPos + 1 ]. ^ answer! !!Integer methodsFor: '*Tools-Explorer' stamp: 'laza 3/17/2005 13:37'!explorerContents ^{ 'hexadecimal' -> 16. 'octal' -> 8. 'binary' -> 2 } collect: [:each | ObjectExplorerWrapper with: each key translated name: (self printStringBase: each value) model: self]! !!Integer methodsFor: '*Tools-Explorer' stamp: 'laza 3/17/2005 13:38'!hasContentsInExplorer ^true! !!Integer methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:59'!* aNumber "Refer to the comment in Number * " aNumber isInteger ifTrue: [^ self digitMultiply: aNumber neg: self negative ~~ aNumber negative]. ^ aNumber adaptToInteger: self andSend: #*! !!Integer methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:59'!+ aNumber "Refer to the comment in Number + " aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [^ (self digitAdd: aNumber) normalize] ifFalse: [^ self digitSubtract: aNumber]]. ^ aNumber adaptToInteger: self andSend: #+! !!Integer methodsFor: 'arithmetic' stamp: 'di 11/6/1998 13:59'!- aNumber "Refer to the comment in Number - " aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [^ self digitSubtract: aNumber] ifFalse: [^ (self digitAdd: aNumber) normalize]]. ^ aNumber adaptToInteger: self andSend: #-! !!Integer methodsFor: 'arithmetic' stamp: 'StephaneDucasse 5/27/2010 22:08'!/ aNumber "Refer to the comment in Number / " | quoRem | aNumber isInteger ifTrue: [quoRem := self digitDiv: aNumber abs neg: self negative ~~ aNumber negative. (quoRem at: 2) = 0 ifTrue: [^ (quoRem at: 1) normalize] ifFalse: [^ (Fraction numerator: self denominator: aNumber) reduced]]. ^ aNumber adaptToInteger: self andSend: #/! !!Integer methodsFor: 'arithmetic' stamp: 'RAH 4/25/2000 19:49'!// aNumber | q | #Numeric. "Changed 200/01/19 For ANSI support." aNumber = 0 ifTrue: [^ (ZeroDivide dividend: self) signal"<- Chg"]. self = 0 ifTrue: [^ 0]. q := self quo: aNumber. "Refer to the comment in Number|//." (q negative ifTrue: [q * aNumber ~= self] ifFalse: [q = 0 and: [self negative ~= aNumber negative]]) ifTrue: [^ q - 1"Truncate towards minus infinity."] ifFalse: [^ q]! !!Integer methodsFor: 'arithmetic' stamp: 'bf 9/25/2008 15:13'!\\\ anInteger "a modulo method for use in DSA. Be careful if you try to use this elsewhere." ^self \\ anInteger! !!Integer methodsFor: 'arithmetic'!alignedTo: anInteger "Answer the smallest number not less than receiver that is a multiple of anInteger." ^(self+anInteger-1//anInteger)*anInteger"5 alignedTo: 2""12 alignedTo: 3"! !!Integer methodsFor: 'arithmetic' stamp: 'jannik.laval 5/1/2010 17:03'!crossSumBase: aBase |aResult| "Precondition" [aBase isInteger and: [aBase >=2]] assert. self < 0 ifTrue: [^self negated crossSumBase: aBase]. self < aBase ifTrue: [^ self]. aResult := self \\ aBase + (self // aBase crossSumBase: aBase). "Postcondition E.g. 18 crossSumBase: 10 -> 9 => 18\\(10-1) = 0" [((aResult \\ (aBase - 1) = 0)) = ((self \\ (aBase - 1)) =0)] assert. ^aResult! !!Integer methodsFor: 'arithmetic' stamp: 'di 11/6/1998 14:00'!quo: aNumber "Refer to the comment in Number quo: " | ng quo | aNumber isInteger ifTrue: [ng := self negative == aNumber negative == false. quo := (self digitDiv: (aNumber class == SmallInteger ifTrue: [aNumber abs] ifFalse: [aNumber]) neg: ng) at: 1. ^ quo normalize]. ^ aNumber adaptToInteger: self andSend: #quo:! !!Integer methodsFor: 'arithmetic' stamp: 'nice 9/2/2010 21:29'!reciprocalModulo: n "Answer an integer x such that (self * x) \\ n = 1, x > 0, x < n. Raise an error if there is no such integer. The algorithm is a non extended euclidean modular inversion called NINV. It is described in this article: 'Using an RSA Accelerator for Modular Inversion' by Martin Seysen. See http://www.iacr.org/archive/ches2005/017.pdf" | u v f fPlusN b result result2 | ((self <= 0) or: [n <= 0]) ifTrue: [self error: 'self and n must be greater than zero']. self >= n ifTrue: [self error: 'self must be < n']. b := n highBit + 1. f := 1 bitShift: b. v := (self bitShift: b) + 1. u := n bitShift: b. fPlusN := f + n. [v >= fPlusN] whileTrue: [v := u \\\ (u := v)]. result := v - f. (result2 := result + n) > 0 ifFalse: [self error: 'no inverse']. ^result positive ifTrue: [result] ifFalse: [result2]! !!Integer methodsFor: 'benchmarks' stamp: 'jm 11/20/1998 07:06'!benchFib "Handy send-heavy benchmark" "(result // seconds to run) = approx calls per second" " | r t | t := Time millisecondsToRun: [r := 26 benchFib]. (r * 1000) // t" "138000 on a Mac 8100/100" ^ self < 2 ifTrue: [1] ifFalse: [(self-1) benchFib + (self-2) benchFib + 1]! !!Integer methodsFor: 'benchmarks' stamp: 'di 4/11/1999 11:20'!benchmark "Handy bytecode-heavy benchmark" "(500000 // time to run) = approx bytecodes per second" "5000000 // (Time millisecondsToRun: [10 benchmark]) * 1000" "3059000 on a Mac 8100/100" | size flags prime k count | size := 8190. 1 to: self do: [:iter | count := 0. flags := (Array new: size) atAllPut: true. 1 to: size do: [:i | (flags at: i) ifTrue: [prime := i+1. k := i + prime. [k <= size] whileTrue: [flags at: k put: false. k := k + prime]. count := count + 1]]]. ^ count! !!Integer methodsFor: 'benchmarks' stamp: 'adrian-lienhard 5/18/2009 20:33'!tinyBenchmarks "Report the results of running the two tiny Squeak benchmarks. ar 9/10/1999: Adjusted to run at least 1 sec to get more stable results" "0 tinyBenchmarks" "On a 292 MHz G3 Mac: 22727272 bytecodes/sec; 984169 sends/sec" "On a 400 MHz PII/Win98: 18028169 bytecodes/sec; 1081272 sends/sec" | t1 t2 r n1 n2 | n1 := 1. [t1 := Time millisecondsToRun: [n1 benchmark]. t1 < 1000] whileTrue:[n1 := n1 * 2]. "Note: #benchmark's runtime is about O(n)" n2 := 28. [t2 := Time millisecondsToRun: [r := n2 benchFib]. t2 < 1000] whileTrue:[n2 := n2 + 1]. "Note: #benchFib's runtime is about O(n^2)." ^ ((n1 * 500000 * 1000) // t1) printString, ' bytecodes/sec; ', ((r * 1000) // t2) printString, ' sends/sec'! !!Integer methodsFor: 'bit manipulation' stamp: 'adrian-lienhard 5/18/2009 20:35'!<< shiftAmount "left shift" shiftAmount < 0 ifTrue: [self error: 'negative arg']. ^ self bitShift: shiftAmount! !!Integer methodsFor: 'bit manipulation' stamp: 'adrian-lienhard 5/18/2009 20:34'!>> shiftAmount "right shift" shiftAmount < 0 ifTrue: [self error: 'negative arg']. ^ self bitShift: 0 - shiftAmount! !!Integer methodsFor: 'bit manipulation'!allMask: mask "Treat the argument as a bit mask. Answer whether all of the bits that are 1 in the argument are 1 in the receiver." ^mask = (self bitAnd: mask)! !!Integer methodsFor: 'bit manipulation' stamp: 'sr 11/29/2000 14:32'!anyBitOfMagnitudeFrom: start to: stopArg "Tests for any magnitude bits in the interval from start to stopArg." "Primitive fixed in LargeIntegers v1.2. If you have an earlier version comment out the primitive call (using this ST method then)." | magnitude firstDigitIx lastDigitIx rightShift leftShift stop | <primitive: 'primAnyBitFromTo' module:'LargeIntegers'> start < 1 | (stopArg < 1) ifTrue: [^ self error: 'out of range']. magnitude := self abs. stop := stopArg min: magnitude highBit. start > stop ifTrue: [^ false]. firstDigitIx := start - 1 // 8 + 1. lastDigitIx := stop - 1 // 8 + 1. rightShift := (start - 1 \\ 8) negated. leftShift := 7 - (stop - 1 \\ 8). firstDigitIx = lastDigitIx ifTrue: [| digit mask | mask := (255 bitShift: rightShift negated) bitAnd: (255 bitShift: leftShift negated). digit := magnitude digitAt: firstDigitIx. ^ (digit bitAnd: mask) ~= 0]. ((magnitude digitAt: firstDigitIx) bitShift: rightShift) ~= 0 ifTrue: [^ true]. firstDigitIx + 1 to: lastDigitIx - 1 do: [:ix | (magnitude digitAt: ix) ~= 0 ifTrue: [^ true]]. (((magnitude digitAt: lastDigitIx) bitShift: leftShift) bitAnd: 255) ~= 0 ifTrue: [^ true]. ^ false! !!Integer methodsFor: 'bit manipulation'!anyMask: mask "Treat the argument as a bit mask. Answer whether any of the bits that are 1 in the argument are 1 in the receiver." ^0 ~= (self bitAnd: mask)! !!Integer methodsFor: 'bit manipulation' stamp: 'sr 3/13/2000 17:47'!bitAnd: n "Answer an Integer whose bits are the logical AND of the receiver's bits and those of the argument, n." | norm | <primitive: 'primDigitBitAnd' module:'LargeIntegers'> norm := n normalize. ^ self digitLogic: norm op: #bitAnd: length: (self digitLength max: norm digitLength)! !!Integer methodsFor: 'bit manipulation' stamp: 'nice 3/21/2008 21:47'!bitAt: anInteger "Answer 1 if the bit at position anInteger is set to 1, 0 otherwise. self is considered an infinite sequence of bits, so anInteger can be any strictly positive integer. Bit at position 1 is the least significant bit. Negative numbers are in two-complements. This is a naive implementation that can be refined in subclass for speed" ^(self bitShift: 1 - anInteger) bitAnd: 1! !!Integer methodsFor: 'bit manipulation' stamp: 'StephaneDucasse 2/19/2010 15:14'!bitAt: anInteger put: value "Answer a new Integer that has the bit of rank anInteger set to value. The bit value should be 0 or 1, otherwise raise an Error. The bits are indexed starting at 1 for the least significant bit. For negative integers, operate on 2-complement representation." | b | b := self bitAt: anInteger. b = value ifTrue: [^self]. 0 = value ifTrue: [^self bitAnd: (1 bitShift: anInteger - 1) bitInvert]. 1 = value ifTrue: [^self bitOr: (1 bitShift: anInteger - 1)]. self error: 'bit value should be 0 or 1'! !!Integer methodsFor: 'bit manipulation' stamp: 'di 4/30/1998 10:32'!bitClear: aMask "Answer an Integer equal to the receiver, except with all bits cleared that are set in aMask." ^ (self bitOr: aMask) - aMask! !!Integer methodsFor: 'bit manipulation' stamp: 'tak 9/25/2008 15:17'!bitInvert "Answer an Integer whose bits are the logical negation of the receiver's bits. Numbers are interpreted as having 2's-complement representation." ^ -1 - self.! !!Integer methodsFor: 'bit manipulation'!bitInvert32 "Answer the 32-bit complement of the receiver." ^ self bitXor: 16rFFFFFFFF! !!Integer methodsFor: 'bit manipulation' stamp: 'sr 3/13/2000 17:47'!bitOr: n "Answer an Integer whose bits are the logical OR of the receiver's bits and those of the argument, n." | norm | <primitive: 'primDigitBitOr' module:'LargeIntegers'> norm := n normalize. ^ self digitLogic: norm op: #bitOr: length: (self digitLength max: norm digitLength)! !!Integer methodsFor: 'bit manipulation' stamp: 'sr 6/9/2000 10:09'!bitShift: shiftCount "Answer an Integer whose value (in twos-complement representation) is the receiver's value (in twos-complement representation) shifted left by the number of bits indicated by the argument. Negative arguments shift right. Zeros are shifted in from the right in left shifts." | magnitudeShift | magnitudeShift := self bitShiftMagnitude: shiftCount. ^ ((self negative and: [shiftCount negative]) and: [self anyBitOfMagnitudeFrom: 1 to: shiftCount negated]) ifTrue: [magnitudeShift - 1] ifFalse: [magnitudeShift]! !!Integer methodsFor: 'bit manipulation' stamp: 'sr 6/9/2000 14:02'!bitShiftMagnitude: shiftCount "Answer an Integer whose value (in magnitude representation) is the receiver's value (in magnitude representation) shifted left by the number of bits indicated by the argument. Negative arguments shift right. Zeros are shifted in from the right in left shifts." | rShift | <primitive: 'primDigitBitShiftMagnitude' module:'LargeIntegers'> shiftCount >= 0 ifTrue: [^ self digitLshift: shiftCount]. rShift := 0 - shiftCount. ^ (self digitRshift: (rShift bitAnd: 7) bytes: (rShift bitShift: -3) lookfirst: self digitLength) normalize! !!Integer methodsFor: 'bit manipulation' stamp: 'sr 3/13/2000 17:47'!bitXor: n "Answer an Integer whose bits are the logical XOR of the receiver's bits and those of the argument, n." | norm | <primitive: 'primDigitBitXor' module:'LargeIntegers'> norm := n normalize. ^ self digitLogic: norm op: #bitXor: length: (self digitLength max: norm digitLength)! !!Integer methodsFor: 'bit manipulation' stamp: 'sr 6/8/2000 02:13'!highBit "Answer the index of the high order bit of the receiver, or zero if the receiver is zero. Raise an error if the receiver is negative, since negative integers are defined to have an infinite number of leading 1's in 2's-complement arithmetic. Use >>highBitOfMagnitude if you want to get the highest bit of the magnitude." ^ self subclassResponsibility! !!Integer methodsFor: 'bit manipulation' stamp: 'sr 6/8/2000 01:55'!highBitOfMagnitude "Answer the index of the high order bit of the magnitude of the receiver, or zero if the receiver is zero." ^ self subclassResponsibility! !!Integer methodsFor: 'bit manipulation' stamp: 'jm 2/19/98 12:11'!lowBit "Answer the index of the low order bit of this number." | index | self = 0 ifTrue: [ ^ 0 ]. index := 1. [ (self digitAt: index) = 0 ] whileTrue: [ index := index + 1 ]. ^ (self digitAt: index) lowBit + (8 * (index - 1))! !!Integer methodsFor: 'bit manipulation'!noMask: mask "Treat the argument as a bit mask. Answer whether none of the bits that are 1 in the argument are 1 in the receiver." ^0 = (self bitAnd: mask)! !!Integer methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:38'!< aNumber aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [self negative ifTrue: [^ (self digitCompare: aNumber) > 0] ifFalse: [^ (self digitCompare: aNumber) < 0]] ifFalse: [^ self negative]]. ^ aNumber adaptToInteger: self andCompare: #<! !!Integer methodsFor: 'comparing' stamp: 'nice 1/4/2009 17:35'!<= aNumber aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [self negative ifTrue: [^ (self digitCompare: aNumber) >= 0] ifFalse: [^ (self digitCompare: aNumber) <= 0]] ifFalse: [^ self negative]]. ^ aNumber adaptToInteger: self andCompare: #<=! !!Integer methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:41'!= aNumber aNumber isNumber ifFalse: [^ false]. aNumber isInteger ifTrue: [aNumber negative == self negative ifTrue: [^ (self digitCompare: aNumber) = 0] ifFalse: [^ false]]. ^ aNumber adaptToInteger: self andCompare: #=! !!Integer methodsFor: 'comparing' stamp: 'nice 3/28/2006 23:38'!> aNumber aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [self negative ifTrue: [^(self digitCompare: aNumber) < 0] ifFalse: [^(self digitCompare: aNumber) > 0]] ifFalse: [^ aNumber negative]]. ^ aNumber adaptToInteger: self andCompare: #>! !!Integer methodsFor: 'comparing' stamp: 'nice 1/4/2009 17:35'!>= aNumber aNumber isInteger ifTrue: [self negative == aNumber negative ifTrue: [self negative ifTrue: [^(self digitCompare: aNumber) <= 0] ifFalse: [^(self digitCompare: aNumber) >= 0]] ifFalse: [^ aNumber negative]]. ^ aNumber adaptToInteger: self andCompare: #>=! !!Integer methodsFor: 'converting' stamp: 'di 11/6/1998 13:43'!adaptToFraction: rcvr andSend: selector "If I am involved in arithmetic with a Fraction, convert me to a Fraction." ^ rcvr perform: selector with: self asFraction! !!Integer methodsFor: 'converting' stamp: 'ar 4/9/2005 22:31'!asCharacter "Answer the Character whose value is the receiver." ^Character value: self! !!Integer methodsFor: 'converting' stamp: 'nice 6/11/2009 02:01'!asFloat "Answer a Float that represents the value of the receiver. This is the nearest possible Float according to IEEE 754 round to nearest even mode. If the receiver is too large, then answer with Float infinity." | mantissa shift sum numberOfTruncatedBits mask truncatedBits | self isZero ifTrue: [^ 0.0]. mantissa := self abs. "Assume Float is a double precision IEEE 754 number with 53bits mantissa. We should better use some Float class message for that (Float precision)..." numberOfTruncatedBits := mantissa highBit - 53. numberOfTruncatedBits > 0 ifTrue: [mask := (1 bitShift: numberOfTruncatedBits) - 1. truncatedBits := mantissa bitAnd: mask. mantissa := mantissa bitShift: numberOfTruncatedBits negated. "inexact := truncatedBits isZero not." truncatedBits highBit = numberOfTruncatedBits ifTrue: ["There is a carry, whe must eventually round upper" (mantissa even and: [truncatedBits isPowerOfTwo]) ifFalse: ["Either the mantissa is odd, and we must round upper to the nearest even Or the truncated part is not a power of two, so has more than 1 bit, so is > 0.5ulp: we must round upper" mantissa := mantissa + 1]]] ifFalse: [numberOfTruncatedBits := 0]. "now, mantissa has no more than 53 bits, we can do exact floating point arithmetic" sum := 0.0. shift := numberOfTruncatedBits. 1 to: mantissa digitLength do: [:byteIndex | sum := ((mantissa digitAt: byteIndex) asFloat timesTwoPower: shift) + sum. shift := shift + 8]. ^ self positive ifTrue: [sum] ifFalse: [sum negated] "Implementation notes: The receiver is split in three parts: - a sign - a truncated mantissa made of first 53 bits which is the maximum precision of Float - trailing truncatedBits This is like placing a floating point after numberOfTruncatedBits from the right: self = (self sign*(mantissa + fractionPart)*(1 bitShift: numberOfTruncatedBits)). where 0 <= fractionPart < 1, fractionPart = (truncatedBits/(1 bitShift: numberOfTruncatedBits)). Note that the converson is inexact if fractionPart > 0. If fractionPart > 0.5 (2r0.1), then the mantissa must be rounded upward. If fractionPart = 0.5, then it is case of exact difference between two consecutive integers. In this later case, we always round to nearest even. That is round upward if mantissa is odd. The two cases imply first bit after floating point is 1: truncatedBits highBit = numberOfTruncatedBits Possible variants: (self abs bitAt: numberOfTruncatedBits) = 1 In the former case, there must be another truncated bit set to 1: truncatedBits isPowerOfTwo not. Possible variants: (self abs lowBit < numberOfTruncatedBits) The later case is recognized as: mantissa odd. examples (I omit first 52 bits of mantissa for clarity) 2r0.00001 is rounded to 2r0 2r1.00001 is rounded to 2r1 2r0.1 is rounded to 2r0 (nearest even) 2r1.1 is rounded to 2r10 (nearest even) 2r0.10001 is rounded to 2r1 2r1.10001 is rounded to 2r10"! !!Integer methodsFor: 'converting' stamp: 'MarcusDenker 12/2/2009 12:54'!asFraction "Answer a Fraction that represents the value of the receiver." ^Fraction numerator: self denominator: 1! !!Integer methodsFor: 'converting' stamp: 'ls 5/26/1998 20:53'!asHexDigit ^'0123456789ABCDEF' at: self+1! !!Integer methodsFor: 'converting'!asInteger "Answer with the receiver itself." ^self! !!Integer methodsFor: 'converting' stamp: 'brp 5/13/2003 10:12'!asYear ^ Year year: self ! !!Integer methodsFor: 'converting' stamp: 'StephaneDucasse 7/21/2010 17:39'!hex "Print the receiver as hex, prefixed with 16r. DO NOT CHANGE THIS!! The Cog VMMaker depends on this. Consider using any of printStringHex printStringBase: 16 printStringBase: 16 length: 8 padded: true storeStringHex storeStringBase: 16 storeStringBase: 16 length: 11 padded: true" ^self storeStringBase: 16! !!Integer methodsFor: 'enumerating'!timesRepeat: aBlock "Evaluate the argument, aBlock, the number of times represented by the receiver." | count | count := 1. [count <= self] whileTrue: [aBlock value. count := count + 1]! !!Integer methodsFor: 'mathematical functions' stamp: 'di 4/22/1998 14:45'!factorial "Answer the factorial of the receiver." self = 0 ifTrue: [^ 1]. self > 0 ifTrue: [^ self * (self - 1) factorial]. self error: 'Not valid for negative integers'! !!Integer methodsFor: 'mathematical functions' stamp: 'LC 6/17/1998 19:22'!gcd: anInteger "See Knuth, Vol 2, 4.5.2, Algorithm L" "Initialize" | higher u v k uHat vHat a b c d vPrime vPrimePrime q t | higher := SmallInteger maxVal highBit. u := self abs max: (v := anInteger abs). v := self abs min: v. [v class == SmallInteger] whileFalse: [(uHat := u bitShift: (k := higher - u highBit)) class == SmallInteger ifFalse: [k := k - 1. uHat := uHat bitShift: -1]. vHat := v bitShift: k. a := 1. b := 0. c := 0. d := 1. "Test quotient" [(vPrime := vHat + d) ~= 0 and: [(vPrimePrime := vHat + c) ~= 0 and: [(q := uHat + a // vPrimePrime) = (uHat + b // vPrime)]]] whileTrue: ["Emulate Euclid" c := a - (q * (a := c)). d := b - (q * (b := d)). vHat := uHat - (q * (uHat := vHat))]. "Multiprecision step" b = 0 ifTrue: [v := u rem: (u := v)] ifFalse: [t := u * a + (v * b). v := u * c + (v * d). u := t]]. ^ v gcd: u! !!Integer methodsFor: 'mathematical functions'!lcm: n "Answer the least common multiple of the receiver and n." ^self // (self gcd: n) * n! !!Integer methodsFor: 'mathematical functions' stamp: 'nice 5/28/2010 21:25'!ln "This function is defined because super ln might overflow." | res h | self <= 0 ifTrue: [self error: 'ln is only defined for x > 0']. res := super ln. res isFinite ifTrue: [^res]. h := self highBit. ^2 ln * h + (self / (1 << h)) asFloat ln! !!Integer methodsFor: 'mathematical functions' stamp: 'nice 6/12/2010 00:40'!log "This function is defined because super log might overflow." | res h | self <= 0 ifTrue: [self error: 'log is only defined for x > 0']. res := super log. res isFinite ifTrue: [^res]. h := self highBit. ^2 log * h + (self / (1 << h)) asFloat log! !!Integer methodsFor: 'mathematical functions' stamp: 'es 5/25/2005 11:04'!raisedToInteger: exp modulo: m (exp = 0) ifTrue: [^ 1]. exp even ifTrue: [^ (self raisedToInteger: (exp // 2) modulo: m) squared \\ m] ifFalse: [^ (self * (self raisedToInteger: (exp - 1) modulo: m)) \\ m].! !!Integer methodsFor: 'mathematical functions' stamp: 'adrian-lienhard 5/18/2009 21:03'!raisedTo: y modulo: n "Answer the modular exponential. Code by Jesse Welton." | s t u | s := 1. t := self. u := y. [u = 0] whileFalse: [ u odd ifTrue: [ s := s * t. s >= n ifTrue: [s := s \\\ n]]. t := t * t. t >= n ifTrue: [t := t \\\ n]. u := u bitShift: -1]. ^ s.! !!Integer methodsFor: 'mathematical functions' stamp: 'tk 7/30/97 13:08'!take: kk "Return the number of combinations of (self) elements taken kk at a time. For 6 take 3, this is 6*5*4 / (1*2*3). Zero outside of Pascal's triangle. Use a trick to go faster." " 6 take: 3 " | num denom | kk < 0 ifTrue: [^ 0]. kk > self ifTrue: [^ 0]. num := 1. self to: (kk max: self-kk) + 1 by: -1 do: [:factor | num := num * factor]. denom := 1. 1 to: (kk min: self-kk) do: [:factor | denom := denom * factor]. ^ num // denom! !!Integer methodsFor: 'printing' stamp: 'sw 11/24/1998 14:53'!asStringWithCommas "123456789 asStringWithCommas" "-123456789 asStringWithCommas" | digits | digits := self abs printString. ^ String streamContents: [:strm | self sign = -1 ifTrue: [strm nextPut: $-]. 1 to: digits size do: [:i | strm nextPut: (digits at: i). (i < digits size and: [(i - digits size) \\ 3 = 0]) ifTrue: [strm nextPut: $,]]]! !!Integer methodsFor: 'printing' stamp: 'ar 7/18/2001 22:09'!asStringWithCommasSigned "123456789 asStringWithCommasSigned" "-123456789 asStringWithCommasSigned" | digits | digits := self abs printString. ^ String streamContents: [:strm | self sign = -1 ifTrue: [strm nextPut: $-] ifFalse:[strm nextPut: $+]. 1 to: digits size do: [:i | strm nextPut: (digits at: i). (i < digits size and: [(i - digits size) \\ 3 = 0]) ifTrue: [strm nextPut: $,]]]! !!Integer methodsFor: 'printing' stamp: 'sw 11/13/1999 23:00'!asTwoCharacterString "Answer a two-character string representing the receiver, with leading zero if required. Intended for use with integers in the range 0 to 99, but plausible replies given for other values too" ^ (self >= 0 and: [self < 10]) ifTrue: ['0', self printString] ifFalse: [self printString copyFrom: 1 to: 2]"2 asTwoCharacterString11 asTwoCharacterString1943 asTwoCharacterString0 asTwoCharacterString-2 asTwoCharacterString-234 asTwoCharacterString"! !!Integer methodsFor: 'printing' stamp: 'tk 4/1/2002 11:30'!asWords "SmallInteger maxVal asWords" | mils minus three num answer milCount | self = 0 ifTrue: [^'zero']. mils := #('' ' thousand' ' million' ' billion' ' trillion' ' quadrillion' ' quintillion' ' sextillion' ' septillion' ' octillion' ' nonillion' ' decillion' ' undecillion' ' duodecillion' ' tredecillion' ' quattuordecillion' ' quindecillion' ' sexdecillion' ' septendecillion' ' octodecillion' ' novemdecillion' ' vigintillion'). num := self. minus := ''. self < 0 ifTrue: [ minus := 'negative '. num := num negated. ]. answer := String new. milCount := 1. [num > 0] whileTrue: [ three := (num \\ 1000) threeDigitName. num := num // 1000. three isEmpty ifFalse: [ answer isEmpty ifFalse: [ answer := ', ',answer ]. answer := three,(mils at: milCount),answer. ]. milCount := milCount + 1. ]. ^minus,answer! !!Integer methodsFor: 'printing' stamp: 'MPW 1/1/1901 00:14'!destinationBuffer:digitLength digitLength <= 1 ifTrue: [self] ifFalse: [LargePositiveInteger new: digitLength].! !!Integer methodsFor: 'printing' stamp: 'MPW 1/1/1901 00:16'!digitBuffer:digitLength ^Array new:digitLength*8.! !!Integer methodsFor: 'printing'!isLiteral ^true! !!Integer methodsFor: 'printing' stamp: 'stephane.ducasse 4/13/2009 14:15'!numberOfDigits "Return how many digits are necessary to print this number in base 10. This does not count any place for minus sign, radix prefix or whatever." ^ self numberOfDigitsInBase: 10 ! !!Integer methodsFor: 'printing' stamp: 'nice 2/15/2008 22:14'!numberOfDigitsInBase: b "Return how many digits are necessary to print this number in base b. This does not count any place for minus sign, radix prefix or whatever. Note that this algorithm may cost a few operations on LargeInteger." | nDigits q | self negative ifTrue: [^self negated numberOfDigitsInBase: b]. self < b ifTrue: [^1]. b isPowerOfTwo ifTrue: [^self highBit + b highBit - 2 quo: b highBit - 1]. "A conversion from base 2 to base b has to be performed. This algorithm avoids Float computations like (self log: b) floor + 1, 1) because they are inexact 2) because LargeInteger might overflow 3) because this algorithm might be cheaper than conversion" "Make an initial nDigits guess that is lower than or equal to required number of digits" b = 10 ifTrue: [nDigits := ((self highBit - 1) * 3 quo: 10) + 1. "This is because 1024 is a little more than a kilo"] ifFalse: [nDigits := self highBit quo: b highBit]. "See how many digits remains above these first nDigits guess" q := self quo: (b raisedTo: nDigits). ^q = 0 ifTrue: [nDigits] ifFalse: [nDigits + (q numberOfDigitsInBase: b)]! !!Integer methodsFor: 'printing' stamp: 'nice 2/15/2008 21:49'!printOn: aStream ^self printOn: aStream base: 10! !!Integer methodsFor: 'printing' stamp: 'fbs 2/9/2006 08:57'!printOn: outputStream base: baseInteger showRadix: flagBoolean "Write a sequence of characters that describes the receiver in radix baseInteger with optional radix specifier. The result is undefined if baseInteger less than 2 or greater than 36." | tempString startPos | #Numeric. "2000/03/04 Harmon R. Added ANSI <integer> protocol" tempString := self printStringRadix: baseInteger. flagBoolean ifTrue: [^ outputStream nextPutAll: tempString]. startPos := (tempString indexOf: $r ifAbsent: [self error: 'radix indicator not found.']) + 1. self negative ifTrue: [outputStream nextPut: $-]. outputStream nextPutAll: (tempString copyFrom: startPos to: tempString size)! !!Integer methodsFor: 'printing' stamp: 'nice 3/29/2011 21:58'!printOn: aStream showingDecimalPlaces: placesDesired "Same as super, but provides a faster implementation because fraction part and rounding are trivial." self printOn: aStream base: 10. placesDesired <= 0 ifFalse: [aStream nextPut: $.. 0 printOn: aStream base: 10 length: placesDesired padded: true].! !!Integer methodsFor: 'printing' stamp: 'RAH 4/25/2000 19:49'!printPaddedWith: aCharacter to: anInteger "Answer the string containing the ASCII representation of the receiver padded on the left with aCharacter to be at least anInteger characters." #Numeric. "2000/03/04 Harmon R. Added Date and Time support" ^ self printPaddedWith: aCharacter to: anInteger base: 10! !!Integer methodsFor: 'printing' stamp: 'PeterHugossonMiller 9/3/2009 10:01'!printPaddedWith: aCharacter to: anInteger base: aRadix "Answer the string containing the ASCII representation of the receiver padded on the left with aCharacter to be at least anInteger characters." | aStream padding digits | #Numeric. "2000/03/04 Harmon R. Added Date and Time support" aStream := (String new: 10) writeStream. self printOn: aStream base: aRadix showRadix: false. digits := aStream contents. padding := anInteger - digits size. padding > 0 ifFalse: [^ digits]. ^ ((String new: padding) atAllPut: aCharacter; yourself) , digits! !!Integer methodsFor: 'printing' stamp: 'nice 2/15/2008 21:49'!printString "For Integer, prefer the stream version to the string version for efficiency" ^String streamContents: [:str | self printOn: str base: 10]! !!Integer methodsFor: 'printing' stamp: 'md 7/30/2005 21:00'!printStringRadix: baseInteger "Return a string containing a sequence of characters that represents the numeric value of the receiver in the radix specified by the argument. If the receiver is negative, a minus sign ('-') is prepended to the sequence of characters. The result is undefined if baseInteger less than 2 or greater than 36." | tempString | #Numeric. "2000/03/04 Harmon R. Added ANSI <integer> protocol" baseInteger = 10 ifTrue: [tempString := self storeStringBase: baseInteger. self negative ifTrue: [^ '-10r' , (tempString copyFrom: 2 to: tempString size)] ifFalse: [^ '10r' , tempString]]. ^ self storeStringBase: baseInteger! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 18:13'!printOn: aStream base: base length: minimum padded: zeroFlag | prefix | prefix := self negative ifTrue: ['-'] ifFalse: [String new]. self print: (self abs printStringBase: base) on: aStream prefix: prefix length: minimum padded: zeroFlag! !!Integer methodsFor: 'printing-numerative' stamp: 'nice 2/15/2008 21:44'!printOn: aStream base: b nDigits: n "Append a representation of this number in base b on aStream using nDigits. self must be positive." self subclassResponsibility! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 18:14'!printStringBase: base length: minimum padded: zeroFlag ^String streamContents: [:s| self printOn: s base: base length: minimum padded: zeroFlag]! !!Integer methodsFor: 'printing-numerative' stamp: 'StephaneDucasse 7/31/2010 19:45'!printStringHex "returns the hex digit part of the integer when printed in hexadecimal format. 30 printStringHex '1E' 30 hex '16r1E' " ^self printStringBase: 16! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 18:21'!printStringLength: minimal ^self printStringLength: minimal padded: false! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 18:20'!printStringLength: minimal padded: zeroFlag ^self printStringBase: 10 length: minimal padded: zeroFlag! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 18:20'!printStringPadded: minimal ^self printStringLength: minimal padded: true! !!Integer methodsFor: 'printing-numerative' stamp: 'PeterHugossonMiller 9/3/2009 10:01'!printStringRoman | stream integer | stream := String new writeStream. integer := self negative ifTrue: [stream nextPut: $-. self negated] ifFalse: [self]. integer // 1000 timesRepeat: [stream nextPut: $M]. integer romanDigits: 'MDC' for: 100 on: stream; romanDigits: 'CLX' for: 10 on: stream; romanDigits: 'XVI' for: 1 on: stream. ^stream contents! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 13:35'!radix: base ^ self printStringBase: base! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 13:36'!storeOn: aStream base: base "Print a representation of the receiver on the stream <aStream> in base <base> where 2 <= <baseInteger> <= 16. If <base> is other than 10 it is written first separated by $r followed by the number like for example: 16rFCE2" | integer | integer := self negative ifTrue: [aStream nextPut: $-. self negated] ifFalse: [self]. base = 10 ifFalse: [aStream nextPutAll: base printString; nextPut: $r]. aStream nextPutAll: (integer printStringBase: base).! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 18:16'!storeOn: aStream base: base length: minimum padded: zeroFlag | prefix | prefix := self negative ifTrue: ['-'] ifFalse: [String new]. base = 10 ifFalse: [prefix := prefix, base printString, 'r']. self print: (self abs printStringBase: base) on: aStream prefix: prefix length: minimum padded: zeroFlag! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 18:16'!storeStringBase: base length: minimum padded: zeroFlag ^String streamContents: [:s| self storeOn: s base: base length: minimum padded: zeroFlag]! !!Integer methodsFor: 'printing-numerative' stamp: 'laza 3/29/2004 10:58'!storeStringHex ^self storeStringBase: 16! !!Integer methodsFor: 'system primitives' stamp: 'tk 3/24/1999 20:26'!lastDigit "Answer the last digit of the integer base 256. LargePositiveInteger uses bytes of base two number, and each is a 'digit'." ^self digitAt: self digitLength! !!Integer methodsFor: 'system primitives'!replaceFrom: start to: stop with: replacement startingAt: repStart | j | "Catches failure if LgInt replace primitive fails" j := repStart. start to: stop do: [:i | self digitAt: i put: (replacement digitAt: j). j := j+1]! !!Integer methodsFor: 'testing'!even "Refer to the comment in Number|even." ^((self digitAt: 1) bitAnd: 1) = 0! !!Integer methodsFor: 'testing'!isInteger "True for all subclasses of Integer." ^ true! !!Integer methodsFor: 'testing' stamp: 'StephaneDucasse 11/1/2009 22:37'!isMostLikelyPrime "See isProbablyPrimeWithK:andQ: for the algoritm description." | k q | self <= 1 ifTrue: [^self error: 'operation undefined']. self even ifTrue: [^self = 2]. k := 1. q := self - 1 bitShift: -1. [q odd] whileFalse: [q := q bitShift: -1. k := k + 1]. 25 timesRepeat: [(self isProbablyPrimeWithK: k andQ: q) ifFalse: [^false]]. ^true! !!Integer methodsFor: 'testing' stamp: 'ar 6/9/2000 18:56'!isPowerOfTwo "Return true if the receiver is an integral power of two." ^ (self bitAnd: self-1) = 0! !!Integer methodsFor: 'testing' stamp: 'jannik.laval 2/4/2010 14:36'!isPrime "Answer true if the receiver is a prime number. See isProbablyPrime for a probabilistic implementation that is much faster for large integers, and that is correct to an extremely high statistical level of confidence (effectively deterministic)." self <= 1 ifTrue: [ ^false ]. self even ifTrue: [ ^self = 2]. 3 to: self sqrtFloor by: 2 do: [ :each | self \\ each = 0 ifTrue: [ ^false ] ]. ^true! !!Integer methodsFor: 'testing' stamp: 'StephaneDucasse 12/1/2009 14:36'!isProbablyPrime "See isProbablyPrimeWithK:andQ: for the algoritm description." | k q | self <= 1 ifTrue: [ ^false ]. self even ifTrue: [ ^self = 2 ]. k := 1. q := self - 1 bitShift: -1. [ q odd ] whileFalse: [ q := q bitShift: -1. k := k + 1 ]. 25 timesRepeat: [ (self isProbablyPrimeWithK: k andQ: q) ifFalse: [ ^false ] ]. ^true! !!Integer methodsFor: 'testing' stamp: 'StephaneDucasse 12/1/2009 14:36'!isProbablyPrimeWithK: k andQ: q "Algorithm P, probabilistic primality test, from Knuth, Donald E. 'The Art of Computer Programming', Vol 2, Third Edition, section 4.5.4, page 395, P1-P5 refer to Knuth description." "P1" | x j y | x := (self - 2) atRandom + 1. "P2" j := 0. y := x raisedToInteger: q modulo: self. "P3" [(((j = 0) & (y = 1)) | (y = (self - 1))) ifTrue: [^true]. ((j > 0) & (y = 1)) ifTrue: [^false]. "P5" true] whileTrue: [j := j + 1. (j < k) ifTrue: [y := y squared \\ self] ifFalse:[^ false]]! !!Integer methodsFor: 'testing' stamp: 'StephaneDucasse 12/1/2009 14:38'!sqrtFloor "Return the integer part of the square root of self" | guess guessSquared delta | guess := 1 bitShift: self highBit + 1 // 2. [ guessSquared := guess * guess. delta := guessSquared - self // (guess bitShift: 1). delta = 0 ] whileFalse: [ guess := guess - delta ]. guessSquared = self ifFalse: [ guess := guess - 1 ]. ^guess! !!Integer methodsFor: 'truncation and round off' stamp: 'ar 6/9/2000 19:16'!asLargerPowerOfTwo "Convert the receiver into a power of two which is not less than the receiver" self isPowerOfTwo ifTrue:[^self] ifFalse:[^1 bitShift: (self highBit)]! !!Integer methodsFor: 'truncation and round off' stamp: 'ar 6/9/2000 18:56'!asPowerOfTwo "Convert the receiver into a power of two" ^self asSmallerPowerOfTwo! !!Integer methodsFor: 'truncation and round off' stamp: 'ar 6/9/2000 19:16'!asSmallerPowerOfTwo "Convert the receiver into a power of two which is not larger than the receiver" self isPowerOfTwo ifTrue:[^self] ifFalse:[^1 bitShift: (self highBit - 1)]! !!Integer methodsFor: 'truncation and round off' stamp: 'lr 11/4/2003 12:14'!atRandom "Answer a random integer from 1 to self. This implementation uses a shared generator. Heavy users should their own implementation or use Interval>atRandom: directly." self = 0 ifTrue: [ ^0 ]. self < 0 ifTrue: [ ^self negated atRandom negated ]. ^Collection mutexForPicking critical: [ self atRandom: Collection randomForPicking ]! !!Integer methodsFor: 'truncation and round off' stamp: 'sma 5/12/2000 12:35'!atRandom: aGenerator "Answer a random integer from 1 to self picked from aGenerator." ^ aGenerator nextInt: self! !!Integer methodsFor: 'truncation and round off'!ceiling "Refer to the comment in Number|ceiling."! !!Integer methodsFor: 'truncation and round off'!floor "Refer to the comment in Number|floor."! !!Integer methodsFor: 'truncation and round off'!normalize "SmallInts OK; LgInts override" ^ self! !!Integer methodsFor: 'truncation and round off'!rounded "Refer to the comment in Number|rounded."! !!Integer methodsFor: 'truncation and round off'!truncated "Refer to the comment in Number|truncated."! !!Integer methodsFor: 'private'!copyto: x | stop | stop := self digitLength min: x digitLength. ^ x replaceFrom: 1 to: stop with: self startingAt: 1! !!Integer methodsFor: 'private' stamp: 'sr 1/23/2000 05:41'!digitAdd: arg | len arglen accum sum | <primitive: 'primDigitAdd' module:'LargeIntegers'> accum := 0. (len := self digitLength) < (arglen := arg digitLength) ifTrue: [len := arglen]. "Open code max: for speed" sum := Integer new: len neg: self negative. 1 to: len do: [:i | accum := (accum bitShift: -8) + (self digitAt: i) + (arg digitAt: i). sum digitAt: i put: (accum bitAnd: 255)]. accum > 255 ifTrue: [sum := sum growby: 1. sum at: sum digitLength put: (accum bitShift: -8)]. ^ sum! !!Integer methodsFor: 'private' stamp: 'sr 1/23/2000 05:43'!digitCompare: arg "Compare the magnitude of self with that of arg. Return a code of 1, 0, -1 for self >, = , < arg" | len arglen argDigit selfDigit | <primitive: 'primDigitCompare' module:'LargeIntegers'> len := self digitLength. (arglen := arg digitLength) ~= len ifTrue: [arglen > len ifTrue: [^ -1] ifFalse: [^ 1]]. [len > 0] whileTrue: [(argDigit := arg digitAt: len) ~= (selfDigit := self digitAt: len) ifTrue: [argDigit < selfDigit ifTrue: [^ 1] ifFalse: [^ -1]]. len := len - 1]. ^ 0! !!Integer methodsFor: 'private' stamp: 'sr 6/8/2000 01:28'!digitDiv: arg neg: ng "Answer with an array of (quotient, remainder)." | quo rem ql d div dh dnh dl qhi qlo j l hi lo r3 a t | <primitive: 'primDigitDivNegative' module:'LargeIntegers'> arg = 0 ifTrue: [^ (ZeroDivide dividend: self) signal]. "TFEI added this line" l := self digitLength - arg digitLength + 1. l <= 0 ifTrue: [^ Array with: 0 with: self]. "shortcut against #highBit" d := 8 - arg lastDigit highBitOfPositiveReceiver. div := arg digitLshift: d. div := div growto: div digitLength + 1. "shifts so high order word is >=128" rem := self digitLshift: d. rem digitLength = self digitLength ifTrue: [rem := rem growto: self digitLength + 1]. "makes a copy and shifts" quo := Integer new: l neg: ng. dl := div digitLength - 1. "Last actual byte of data" ql := l. dh := div digitAt: dl. dnh := dl = 1 ifTrue: [0] ifFalse: [div digitAt: dl - 1]. 1 to: ql do: [:k | "maintain quo*arg+rem=self" "Estimate rem/div by dividing the leading to bytes of rem by dh." "The estimate is q = qhi*16+qlo, where qhi and qlo are nibbles." j := rem digitLength + 1 - k. "r1 := rem digitAt: j." (rem digitAt: j) = dh ifTrue: [qhi := qlo := 15 "i.e. q=255"] ifFalse: ["Compute q = (r1,r2)//dh, t = (r1,r2)\\dh. Note that r1,r2 are bytes, not nibbles. Be careful not to generate intermediate results exceeding 13 bits." "r2 := (rem digitAt: j - 1)." t := ((rem digitAt: j) bitShift: 4) + ((rem digitAt: j - 1) bitShift: -4). qhi := t // dh. t := (t \\ dh bitShift: 4) + ((rem digitAt: j - 1) bitAnd: 15). qlo := t // dh. t := t \\ dh. "Next compute (hi,lo) := q*dnh" hi := qhi * dnh. lo := qlo * dnh + ((hi bitAnd: 15) bitShift: 4). hi := (hi bitShift: -4) + (lo bitShift: -8). lo := lo bitAnd: 255. "Correct overestimate of q. Max of 2 iterations through loop -- see Knuth vol. 2" r3 := j < 3 ifTrue: [0] ifFalse: [rem digitAt: j - 2]. [(t < hi or: [t = hi and: [r3 < lo]]) and: ["i.e. (t,r3) < (hi,lo)" qlo := qlo - 1. lo := lo - dnh. lo < 0 ifTrue: [hi := hi - 1. lo := lo + 256]. hi >= dh]] whileTrue: [hi := hi - dh]. qlo < 0 ifTrue: [qhi := qhi - 1. qlo := qlo + 16]]. "Subtract q*div from rem" l := j - dl. a := 0. 1 to: div digitLength do: [:i | hi := (div digitAt: i) * qhi. lo := a + (rem digitAt: l) - ((hi bitAnd: 15) bitShift: 4) - ((div digitAt: i) * qlo). rem digitAt: l put: lo - (lo // 256 * 256). "sign-tolerant form of (lo bitAnd: 255)" a := lo // 256 - (hi bitShift: -4). l := l + 1]. a < 0 ifTrue: ["Add div back into rem, decrease q by 1" qlo := qlo - 1. l := j - dl. a := 0. 1 to: div digitLength do: [:i | a := (a bitShift: -8) + (rem digitAt: l) + (div digitAt: i). rem digitAt: l put: (a bitAnd: 255). l := l + 1]]. quo digitAt: quo digitLength + 1 - k put: (qhi bitShift: 4) + qlo]. rem := rem digitRshift: d bytes: 0 lookfirst: dl. ^ Array with: quo with: rem! !!Integer methodsFor: 'private' stamp: 'nice 1/26/2008 02:12'!digitLogic: arg op: op length: len | i result neg1 neg2 rneg z1 z2 rz b1 b2 b | neg1 := self negative. neg2 := arg negative. rneg := ((neg1 ifTrue: [-1] ifFalse: [0]) perform: op with: (neg2 ifTrue: [-1] ifFalse: [0])) < 0. result := Integer new: len neg: rneg. rz := z1 := z2 := true. i := 0. [(i := i + 1) <= len or: ["mind a carry on result that might go past len digits" rneg and: [rz and: [result := result growby: 1. true]]]] whileTrue: [b1 := self digitAt: i. neg1 ifTrue: [b1 := z1 ifTrue: [b1 = 0 ifTrue: [0] ifFalse: [z1 := false. 256 - b1]] ifFalse: [255 - b1]]. b2 := arg digitAt: i. neg2 ifTrue: [b2 := z2 ifTrue: [b2 = 0 ifTrue: [0] ifFalse: [z2 := false. 256 - b2]] ifFalse: [255 - b2]]. b := b1 perform: op with: b2. result digitAt: i put: (rneg ifTrue: [rz ifTrue: [b = 0 ifTrue: [0] ifFalse: [rz := false. 256 - b]] ifFalse: [255 - b]] ifFalse: [b])]. ^ result normalize! !!Integer methodsFor: 'private' stamp: 'sr 6/8/2000 01:30'!digitLshift: shiftCount | carry rShift mask len result digit byteShift bitShift highBit | (highBit := self highBitOfMagnitude) = 0 ifTrue: [^ 0]. len := highBit + shiftCount + 7 // 8. result := Integer new: len neg: self negative. byteShift := shiftCount // 8. bitShift := shiftCount \\ 8. bitShift = 0 ifTrue: ["Fast version for byte-aligned shifts" ^ result replaceFrom: byteShift + 1 to: len with: self startingAt: 1]. carry := 0. rShift := bitShift - 8. mask := 255 bitShift: 0 - bitShift. 1 to: byteShift do: [:i | result digitAt: i put: 0]. 1 to: len - byteShift do: [:i | digit := self digitAt: i. result digitAt: i + byteShift put: (((digit bitAnd: mask) bitShift: bitShift) bitOr: carry). carry := digit bitShift: rShift]. ^ result! !!Integer methodsFor: 'private' stamp: 'sr 1/23/2000 05:46'!digitMultiply: arg neg: ng | prod prodLen carry digit k ab | <primitive: 'primDigitMultiplyNegative' module:'LargeIntegers'> (arg digitLength = 1 and: [(arg digitAt: 1) = 0]) ifTrue: [^ 0]. (self digitLength = 1 and: [(self digitAt: 1) = 0]) ifTrue: [^ 0]. prodLen := self digitLength + arg digitLength. prod := Integer new: prodLen neg: ng. "prod starts out all zero" 1 to: self digitLength do: [:i | (digit := self digitAt: i) ~= 0 ifTrue: [k := i. carry := 0. "Loop invariant: 0<=carry<=0377, k=i+j-1" 1 to: arg digitLength do: [:j | ab := (arg digitAt: j) * digit + carry + (prod digitAt: k). carry := ab bitShift: -8. prod digitAt: k put: (ab bitAnd: 255). k := k + 1]. prod digitAt: k put: carry]]. ^ prod normalize! !!Integer methodsFor: 'private'!digitRshift: anInteger bytes: b lookfirst: a "Shift right 8*b+anInteger bits, 0<=n<8. Discard all digits beyond a, and all zeroes at or below a." | n x r f m digit count i | n := 0 - anInteger. x := 0. f := n + 8. i := a. m := 255 bitShift: 0 - f. digit := self digitAt: i. [((digit bitShift: n) bitOr: x) = 0 and: [i ~= 1]] whileTrue: [x := digit bitShift: f "Can't exceed 8 bits". i := i - 1. digit := self digitAt: i]. i <= b ifTrue: [^Integer new: 0 neg: self negative]. "All bits lost" r := Integer new: i - b neg: self negative. count := i. x := (self digitAt: b + 1) bitShift: n. b + 1 to: count do: [:j | digit := self digitAt: j + 1. r digitAt: j - b put: (((digit bitAnd: m) bitShift: f) bitOr: x) "Avoid values > 8 bits". x := digit bitShift: n]. ^r! !!Integer methodsFor: 'private' stamp: 'StephaneDucasse 3/5/2010 14:47'!digitSubtract: arg | smaller larger z sum sl al ng | <primitive: 'primDigitSubtract' module:'LargeIntegers'> sl := self digitLength. al := arg digitLength. (sl = al ifTrue: [[(self digitAt: sl) = (arg digitAt: sl) and: [sl > 1]] whileTrue: [sl := sl - 1]. al := sl. (self digitAt: sl) < (arg digitAt: sl)] ifFalse: [sl < al]) ifTrue: [larger := arg. smaller := self. ng := self negative == false. sl := al] ifFalse: [larger := self. smaller := arg. ng := self negative]. sum := Integer new: sl neg: ng. z := 0. "Loop invariant is -1<=z<=1" 1 to: sl do: [:i | z := z + (larger digitAt: i) - (smaller digitAt: i). sum digitAt: i put: z - (z // 256 * 256). "sign-tolerant form of (z bitAnd: 255)" z := z // 256]. ^ sum normalize! !!Integer methodsFor: 'private'!growby: n ^self growto: self digitLength + n! !!Integer methodsFor: 'private'!growto: n ^self copyto: (self species new: n)! !!Integer methodsFor: 'private' stamp: 'laza 3/29/2004 18:16'!print: positiveNumberString on: aStream prefix: prefix length: minimum padded: zeroFlag | padLength | padLength := minimum - positiveNumberString size - prefix size. padLength > 0 ifTrue: [zeroFlag ifTrue: [aStream nextPutAll: prefix; nextPutAll: (String new: padLength withAll: $0)] ifFalse: [aStream nextPutAll: (String new: padLength withAll: Character space); nextPutAll: prefix]] ifFalse: [aStream nextPutAll: prefix]. aStream nextPutAll: positiveNumberString ! !!Integer methodsFor: 'private' stamp: 'sma 5/20/2000 17:00'!romanDigits: digits for: base on: aStream | n | n := self \\ (base * 10) // base. n = 9 ifTrue: [^ aStream nextPut: digits last; nextPut: digits first]. n = 4 ifTrue: [^ aStream nextPut: digits last; nextPut: digits second]. n > 4 ifTrue: [aStream nextPut: digits second]. n \\ 5 timesRepeat: [aStream nextPut: digits last]! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!Integer class instanceVariableNames: ''!!Integer class methodsFor: 'class initialization' stamp: 'ar 11/30/2009 22:01'!initialize "Integer initialize" "TODO No compact class here" "Ensure we have the right compact class index" "LPI has been a compact class forever - just ensure basic correctness" "(LargePositiveInteger indexIfCompact = 5) ifFalse:[ (Smalltalk compactClassesArray at: 5) ifNil:[LargePositiveInteger becomeCompactSimplyAt: 5] ifNotNil:[self error: 'Unexpected compact class setup']]." "Cog requires LNI to be compact at 4 (replacing PseudoContext)" "(LargeNegativeInteger indexIfCompact = 4) ifFalse:[" "PseudoContext will likely get removed at some point so write this test without introducing a hard dependency" "(Smalltalk compactClassesArray at: 4) name == #PseudoContext ifTrue:[Smalltalk compactClassesArray at: 4 put: nil]. (Smalltalk compactClassesArray at: 4) ifNil:[LargeNegativeInteger becomeCompactSimplyAt: 4] ifNotNil:[self error: 'Unexpected compact class setup']]."! !!Integer class methodsFor: 'compatibility' stamp: 'laza 10/16/2004 14:34'!readFrom: aStream radix: radix ^self readFrom: aStream base: radix! !!Integer class methodsFor: 'instance creation' stamp: 'tk 4/20/1999 14:18'!basicNew self == Integer ifTrue: [ ^ self error: 'Integer is an abstract class. Make a concrete subclass.']. ^ super basicNew! !!Integer class methodsFor: 'instance creation' stamp: 'bf 2/2/2004 00:23'!byte1: byte1 byte2: byte2 byte3: byte3 byte4: byte4 "Depending on high-order byte copy directly into a LargeInteger, or build up a SmallInteger by shifting" | value | byte4 < 16r40 ifTrue: [^ (byte4 bitShift: 24) + (byte3 bitShift: 16) + (byte2 bitShift: 8) + byte1]. value := LargePositiveInteger new: 4. value digitAt: 4 put: byte4. value digitAt: 3 put: byte3. value digitAt: 2 put: byte2. value digitAt: 1 put: byte1. ^ value! !!Integer class methodsFor: 'instance creation' stamp: 'tk 4/18/1999 22:01'!new self == Integer ifTrue: [ ^ self error: 'Integer is an abstract class. Make a concrete subclass.']. ^ super new! !!Integer class methodsFor: 'instance creation'!new: length neg: neg "Answer an instance of a large integer whose size is length. neg is a flag determining whether the integer is negative or not." neg ifTrue: [^LargeNegativeInteger new: length] ifFalse: [^LargePositiveInteger new: length]! !!Integer class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 00:36'!readFrom: aStringOrStream "Answer a new Integer as described on the stream, aStream. Embedded radix specifiers not allowed - use Number readFrom: for that." ^self readFrom: aStringOrStream base: 10! !!Integer class methodsFor: 'instance creation' stamp: 'GuillermoPolito 8/24/2010 18:48'!readFrom: aStringOrStream base: base "Answer an instance of one of the concrete subclasses if Integer. Initial minus sign accepted, and bases > 10 use letters A-Z. Imbedded radix specifiers not allowed; use Number class readFrom: for that. Raise an Error if there are no digits. If stringOrStream dos not start with a valid number description, answer 0 for backward compatibility. This is not clever and should better be changed." ^(SqNumberParser on: aStringOrStream) nextIntegerBase: base! !!Integer class methodsFor: 'instance creation' stamp: 'nice 3/15/2008 01:09'!readFrom: aStringOrStream ifFail: aBlock "Answer an instance of one of the concrete subclasses if Integer. Initial minus sign accepted. Imbedded radix specifiers not allowed; use Number class readFrom: for that. Execute aBlock if there are no digits." ^(SqNumberParser on: aStringOrStream) nextIntegerBase: 10 ifFail: aBlock! !!Integer class methodsFor: 'prime numbers' stamp: 'ar 10/6/2001 19:34'!largePrimesUpTo: maxValue "Compute and return all the prime numbers up to maxValue" ^Array streamContents:[:s| self largePrimesUpTo: maxValue do:[:prime| s nextPut: prime]]! !!Integer class methodsFor: 'prime numbers' stamp: 'ar 10/6/2001 02:38'!largePrimesUpTo: max do: aBlock "Evaluate aBlock with all primes up to maxValue. The Algorithm is adapted from http://www.rsok.com/~jrm/printprimes.html It encodes prime numbers much more compactly than #primesUpTo: 38.5 integer per byte (2310 numbers per 60 byte) allow for some fun large primes. (all primes up to SmallInteger maxVal can be computed within ~27MB of memory; the regular #primesUpTo: would require 4 *GIGA*bytes). Note: The algorithm could be re-written to produce the first primes (which require the longest time to sieve) faster but only at the cost of clarity." | limit flags maskBitIndex bitIndex maskBit byteIndex index primesUpTo2310 indexLimit | limit := max asInteger - 1. indexLimit := max sqrt truncated + 1. "Create the array of flags." flags := ByteArray new: (limit + 2309) // 2310 * 60 + 60. flags atAllPut: 16rFF. "set all to true" "Compute the primes up to 2310" primesUpTo2310 := self primesUpTo: 2310. "Create a mapping from 2310 integers to 480 bits (60 byte)" maskBitIndex := Array new: 2310. bitIndex := -1. "for pre-increment" maskBitIndex at: 1 put: (bitIndex := bitIndex + 1). maskBitIndex at: 2 put: (bitIndex := bitIndex + 1). 1 to: 5 do:[:i| aBlock value: (primesUpTo2310 at: i)]. index := 6. 2 to: 2309 do:[:n| [(primesUpTo2310 at: index) < n] whileTrue:[index := index + 1]. n = (primesUpTo2310 at: index) ifTrue:[ maskBitIndex at: n+1 put: (bitIndex := bitIndex + 1). ] ifFalse:[ "if modulo any of the prime factors of 2310, then could not be prime" (n \\ 2 = 0 or:[n \\ 3 = 0 or:[n \\ 5 = 0 or:[n \\ 7 = 0 or:[n \\ 11 = 0]]]]) ifTrue:[maskBitIndex at: n+1 put: 0] ifFalse:[maskBitIndex at: n+1 put: (bitIndex := bitIndex + 1)]. ]. ]. "Now the real work begins... Start with 13 since multiples of 2,3,5,7,11 are handled by the storage method; increment by 2 for odd numbers only." 13 to: limit by: 2 do:[:n| (maskBit := maskBitIndex at: (n \\ 2310 + 1)) = 0 ifFalse:["not a multiple of 2,3,5,7,11" byteIndex := n // 2310 * 60 + (maskBit-1 bitShift: -3) + 1. bitIndex := 1 bitShift: (maskBit bitAnd: 7). ((flags at: byteIndex) bitAnd: bitIndex) = 0 ifFalse:["not marked -- n is prime" aBlock value: n. "Start with n*n since any integer < n has already been sieved (e.g., any multiple of n with a number k < n has been cleared when k was sieved); add 2 * i to avoid even numbers and mark all multiples of this prime. Note: n < indexLimit below limits running into LargeInts -- nothing more." n < indexLimit ifTrue:[ index := n * n. (index bitAnd: 1) = 0 ifTrue:[index := index + n]. [index <= limit] whileTrue:[ (maskBit := maskBitIndex at: (index \\ 2310 + 1)) = 0 ifFalse:[ byteIndex := (index // 2310 * 60) + (maskBit-1 bitShift: -3) + 1. maskBit := 255 - (1 bitShift: (maskBit bitAnd: 7)). flags at: byteIndex put: ((flags at: byteIndex) bitAnd: maskBit). ]. index := index + (2 * n)]. ]. ]. ]. ].! !!Integer class methodsFor: 'prime numbers' stamp: 'ar 10/6/2001 19:33'!primesUpTo: max "Return a list of prime integers up to the given integer." "Integer primesUpTo: 100" ^Array streamContents:[:s| self primesUpTo: max do:[:prime| s nextPut: prime]]! !!Integer class methodsFor: 'prime numbers' stamp: 'md 2/13/2006 14:38'!primesUpTo: max do: aBlock "Compute aBlock with all prime integers up to the given integer." "Integer primesUpTo: 100" | limit flags prime k | limit := max asInteger - 1. "Fall back into #largePrimesUpTo:do: if we'd require more than 100k of memory; the alternative will only requre 1/154th of the amount we need here and is almost as fast." limit > 25000 ifTrue:[^self largePrimesUpTo: max do: aBlock]. flags := (Array new: limit) atAllPut: true. 1 to: limit - 1 do: [:i | (flags at: i) ifTrue: [ prime := i + 1. k := i + prime. [k <= limit] whileTrue: [ flags at: k put: false. k := k + prime]. aBlock value: prime]].! !!Integer class methodsFor: 'prime numbers' stamp: 'ar 10/6/2001 19:33'!verbosePrimesUpTo: max "Integer verbosePrimesUpTo: SmallInteger maxVal" "<- heh, heh" "Compute primes up to max, but be verbose about it" ^Array streamContents:[:s| self verbosePrimesUpTo: max do:[:prime| s nextPut: prime]].! !!Integer class methodsFor: 'prime numbers' stamp: 'nice 1/5/2010 15:59'!verbosePrimesUpTo: max do: aBlock "Integer verbosePrimesUpTo: SmallInteger maxVal" "<- heh, heh" "Compute primes up to max, but be verbose about it" | lastTime | lastTime := Time millisecondClockValue. UIManager default informUserDuring: [ :bar | bar value: 'Computing primes...'. self primesUpTo: max do: [ :prime | | nowTime | aBlock value: prime. nowTime := Time millisecondClockValue. nowTime - lastTime > 1000 ifTrue: [ lastTime := nowTime. bar value: 'Last prime found: ' , prime printString ] ] ]! ! Integer variableByteSubclass: #LargePositiveInteger instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!LargePositiveInteger commentStamp: '<historical>' prior: 0!I represent positive integers of more than 30 bits (ie, >= 1073741824). These values are beyond the range of SmallInteger, and are encoded here as an array of 8-bit digits. Care must be taken, when new values are computed, that any result that COULD BE a SmallInteger IS a SmallInteger (see normalize).Note that the bit manipulation primitives, bitAnd:, bitShift:, etc., = and ~= run without failure (and therefore fast) if the value fits in 32 bits. This is a great help to the simulator.!!LargePositiveInteger methodsFor: 'arithmetic'!* anInteger "Primitive. Multiply the receiver by the argument and answer with an Integer result. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive. " <primitive: 29> ^super * anInteger! !!LargePositiveInteger methodsFor: 'arithmetic'!+ anInteger "Primitive. Add the receiver to the argument and answer with an Integer result. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." <primitive: 21> ^super + anInteger! !!LargePositiveInteger methodsFor: 'arithmetic'!- anInteger "Primitive. Subtract the argument from the receiver and answer with an Integer result. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." <primitive: 22> ^super - anInteger! !!LargePositiveInteger methodsFor: 'arithmetic'!/ anInteger "Primitive. Divide the receiver by the argument and answer with the result if the division is exact. Fail if the result is not a whole integer. Fail if the argument is 0. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive. " <primitive: 30> ^super / anInteger! !!LargePositiveInteger methodsFor: 'arithmetic'!// anInteger "Primitive. Divide the receiver by the argument and return the result. Round the result down towards negative infinity to make it a whole integer. Fail if the argument is 0. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive. " <primitive: 32> ^super // anInteger! !!LargePositiveInteger methodsFor: 'arithmetic'!\\ anInteger "Primitive. Take the receiver modulo the argument. The result is the remainder rounded towards negative infinity, of the receiver divided by the argument. Fail if the argument is 0. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." <primitive: 31> ^super \\ anInteger! !!LargePositiveInteger methodsFor: 'arithmetic' stamp: 'RAA 5/31/2000 13:21'!\\\ anInteger "a faster modulo method for use in DSA. Be careful if you try to use this elsewhere" ^(self digitDiv: anInteger neg: false) second! !!LargePositiveInteger methodsFor: 'arithmetic'!abs! !!LargePositiveInteger methodsFor: 'arithmetic'!negated ^ (self copyto: (LargeNegativeInteger new: self digitLength)) normalize "Need to normalize to catch SmallInteger minVal"! !!LargePositiveInteger methodsFor: 'arithmetic'!quo: anInteger "Primitive. Divide the receiver by the argument and return the result. Round the result down towards zero to make it a whole integer. Fail if the argument is 0. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." <primitive: 33> ^super quo: anInteger! !!LargePositiveInteger methodsFor: 'bit manipulation' stamp: 'nice 3/21/2008 00:09'!bitAt: anInteger "Optimize super algorithm to avoid long bit operations. Instead work on digits which are known to be SmallInteger and fast. Note that this algorithm does not work for negative integers." | digitIndex bitIndex | digitIndex := anInteger - 1 // 8 + 1. digitIndex > self digitLength ifTrue: [^0]. bitIndex := anInteger - 1 \\ 8 + 1. ^(self digitAt: digitIndex) bitAt: bitIndex! !!LargePositiveInteger methodsFor: 'bit manipulation' stamp: 'SqR 9/18/2000 15:17'!hashMultiply "Truncate to 28 bits and try again" ^(self bitAnd: 16rFFFFFFF) hashMultiply! !!LargePositiveInteger methodsFor: 'bit manipulation' stamp: 'sr 6/8/2000 02:11'!highBit "Answer the index of the high order bit of the receiver, or zero if the receiver is zero. Raise an error if the receiver is negative, since negative integers are defined to have an infinite number of leading 1's in 2's-complement arithmetic. Use >>highBitOfMagnitude if you want to get the highest bit of the magnitude." ^ self highBitOfMagnitude! !!LargePositiveInteger methodsFor: 'bit manipulation' stamp: 'VeronicaUquillas 6/11/2010 14:14'!highBitOfMagnitude "Answer the index of the high order bit of the magnitude of the receiver, or zero if the receiver is zero. This method is used for LargeNegativeIntegers as well, since LargeIntegers are sign/magnitude." | realLength lastDigit | realLength := self digitLength. [(lastDigit := self digitAt: realLength) = 0] whileTrue: [(realLength := realLength - 1) = 0 ifTrue: [^ 0]]. ^ lastDigit highBitOfPositiveReceiver + (8 * (realLength - 1))! !!LargePositiveInteger methodsFor: 'comparing'!< anInteger "Primitive. Compare the receiver with the argument and answer true if the receiver is less than the argument. Otherwise answer false. Fail if the argument is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." <primitive: 23> ^super < anInteger! !!LargePositiveInteger methodsFor: 'comparing'!<= anInteger "Primitive. Compare the receiver with the argument and answer true if the receiver is less than or equal to the argument. Otherwise answer false. Fail if the argument is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." <primitive: 25> ^super <= anInteger! !!LargePositiveInteger methodsFor: 'comparing'!> anInteger "Primitive. Compare the receiver with the argument and answer true if the receiver is greater than the argument. Otherwise answer false. Fail if the argument is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." <primitive: 24> ^super > anInteger! !!LargePositiveInteger methodsFor: 'comparing'!>= anInteger "Primitive. Compare the receiver with the argument and answer true if the receiver is greater than or equal to the argument. Otherwise answer false. Fail if the argument is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." <primitive: 26> ^super >= anInteger! !!LargePositiveInteger methodsFor: 'comparing' stamp: 'SqR 8/13/2002 10:52'!hash ^ByteArray hashBytes: self startingWith: self species hash! !!LargePositiveInteger methodsFor: 'converting' stamp: 'ajh 7/25/2001 22:28'!as31BitSmallInt "This is only for 31 bit numbers. Keep my 31 bits the same, but put them in a small int. The small int will be negative since my 31st bit is 1. We know my 31st bit is 1 because otherwise I would already be a positive small int." self highBit = 31 ifFalse: [self error: 'more than 31 bits can not fit in a SmallInteger']. ^ self - 16r80000000! !!LargePositiveInteger methodsFor: 'converting' stamp: 'ar 5/17/2000 16:09'!normalize "Check for leading zeroes and return shortened copy if so" | sLen val len oldLen | <primitive: 'primNormalizePositive' module:'LargeIntegers'> "First establish len = significant length" len := oldLen := self digitLength. [len = 0 ifTrue: [^0]. (self digitAt: len) = 0] whileTrue: [len := len - 1]. "Now check if in SmallInteger range" sLen := SmallInteger maxVal digitLength. (len <= sLen and: [(self digitAt: sLen) <= (SmallInteger maxVal digitAt: sLen)]) ifTrue: ["If so, return its SmallInt value" val := 0. len to: 1 by: -1 do: [:i | val := (val *256) + (self digitAt: i)]. ^ val]. "Return self, or a shortened copy" len < oldLen ifTrue: [^ self growto: len] ifFalse: [^ self]! !!LargePositiveInteger methodsFor: 'converting' stamp: 'RAA 3/2/2002 14:32'!withAtLeastNDigits: desiredLength | new | self size >= desiredLength ifTrue: [^self]. new := self class new: desiredLength. new replaceFrom: 1 to: self size with: self startingAt: 1. ^new! !!LargePositiveInteger methodsFor: 'printing' stamp: 'nice 7/22/2008 00:13'!printOn: aStream base: b "Append a representation of this number in base b on aStream. In order to reduce cost of LargePositiveInteger ops, split the number in approximately two equal parts in number of digits." | halfDigits halfPower head tail nDigitsUnderestimate | "Don't engage any arithmetic if not normalized" (self digitLength = 0 or: [(self digitAt: self digitLength) = 0]) ifTrue: [^self normalize printOn: aStream base: b]. nDigitsUnderestimate := b = 10 ifTrue: [((self highBit - 1) * 3 quo: 10) + 1 "because 1024 is almost a kilo"] ifFalse: [self highBit quo: b highBit]. "splitting digits with a whole power of two is more efficient" halfDigits := 1 bitShift: nDigitsUnderestimate highBit - 2. halfDigits <= 1 ifTrue: ["Hmmm, this could happen only in case of a huge base b... Let lower level fail" ^self printOn: aStream base: b nDigits: (self numberOfDigitsInBase: b)]. "Separate in two halves, head and tail" halfPower := b raisedToInteger: halfDigits. head := self quo: halfPower. tail := self - (head * halfPower). "print head" head printOn: aStream base: b. "print tail without the overhead to count the digits" tail printOn: aStream base: b nDigits: halfDigits! !!LargePositiveInteger methodsFor: 'printing' stamp: 'StephaneDucasse 9/1/2010 08:49'!printOn: aStream base: b nDigits: n "Append a representation of this number in base b on aStream using n digits. In order to reduce cost of LargePositiveInteger ops, split the number of digts approximatily in two Should be invoked with: 0 <= self < (b raisedToInteger: n)" | halfPower half head tail | n <= 1 ifTrue: [ n <= 0 ifTrue: [self error: 'Number of digits n should be > 0']. "Note: this is to stop an infinite loop if one ever attempts to print with a huge base This can happen because choice was to not hardcode any limit for base b We let Character>>#digitValue: fail" ^aStream nextPut: (Character digitValue: self)]. halfPower := n bitShift: -1. half := b raisedToInteger: halfPower. head := self quo: half. tail := self - (head * half). head printOn: aStream base: b nDigits: n - halfPower. tail printOn: aStream base: b nDigits: halfPower! !!LargePositiveInteger methodsFor: 'system primitives' stamp: 'tk 3/24/1999 20:28'!digitAt: index "Primitive. Answer the value of an indexable field in the receiver. LargePositiveInteger uses bytes of base two number, and each is a 'digit' base 256. Fail if the argument (the index) is not an Integer or is out of bounds. Essential. See Object documentation whatIsAPrimitive." <primitive: 60> self digitLength < index ifTrue: [^0] ifFalse: [^super at: index]! !!LargePositiveInteger methodsFor: 'system primitives'!digitAt: index put: value "Primitive. Store the second argument (value) in the indexable field of the receiver indicated by index. Fail if the value is negative or is larger than 255. Fail if the index is not an Integer or is out of bounds. Answer the value that was stored. Essential. See Object documentation whatIsAPrimitive." <primitive: 61> ^super at: index put: value! !!LargePositiveInteger methodsFor: 'system primitives'!digitLength "Primitive. Answer the number of indexable fields in the receiver. This value is the same as the largest legal subscript. Essential. See Object documentation whatIsAPrimitive." <primitive: 62> self primitiveFailed! !!LargePositiveInteger methodsFor: 'system primitives'!replaceFrom: start to: stop with: replacement startingAt: repStart "Primitive. This destructively replaces elements from start to stop in the receiver starting at index, repStart, in the collection, replacement. Answer the receiver. Range checks are performed in the primitive only. Optional. See Object documentation whatIsAPrimitive." <primitive: 105> ^ super replaceFrom: start to: stop with: replacement startingAt: repStart! !!LargePositiveInteger methodsFor: 'testing' stamp: 'nice 8/31/2008 00:07'!isLarge ^true! !!LargePositiveInteger methodsFor: 'testing' stamp: 'di 4/23/1998 11:18'!negative "Answer whether the receiver is mathematically negative." ^ false! !!LargePositiveInteger methodsFor: 'testing' stamp: 'di 4/23/1998 11:00'!positive "Answer whether the receiver is positive or equal to 0. (ST-80 protocol). See also strictlyPositive" ^ true! !!LargePositiveInteger methodsFor: 'testing' stamp: 'jm 3/27/98 06:19'!sign "Optimization. Answer 1 since receiver is greater than 0." ^ 1! !!LargePositiveInteger methodsFor: 'testing' stamp: 'di 4/23/1998 11:02'!strictlyPositive "Answer whether the receiver is mathematically positive." ^ true! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!LargePositiveInteger class instanceVariableNames: ''! LargePositiveInteger variableByteSubclass: #LargeNegativeInteger instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!LargeNegativeInteger commentStamp: '<historical>' prior: 0!Just like LargePositiveInteger, but represents a negative number.!!LargeNegativeInteger methodsFor: 'arithmetic'!abs ^ self negated! !!LargeNegativeInteger methodsFor: 'arithmetic'!negated ^ self copyto: (LargePositiveInteger new: self digitLength)! !!LargeNegativeInteger methodsFor: 'bit manipulation' stamp: 'nice 3/21/2008 01:02'!bitAt: anInteger "super would not work because we have to pretend we are in two-complement. this has to be tricky..." | digitIndex bitIndex i | digitIndex := anInteger - 1 // 8 + 1. digitIndex > self digitLength ifTrue: [^1]. bitIndex := anInteger - 1 \\ 8 + 1. i := 1. [i = digitIndex ifTrue: ["evaluate two complement (bitInvert + 1) on the digit : (if digitIndex > 1, we must still add 1 due to the carry). but x bitInvert is -1-x, bitInvert+1 is just x negated..." ^(self digitAt: digitIndex) negated bitAt: bitIndex]. (self digitAt: i) = 0] whileTrue: [ "two complement (bitInvert + 1) raises a carry: 0 bitInvert -> 2r11111111. 2r11111111 + 1 -> 0 with carry... Thus we must inquire one digit forward" i := i + 1]. "We escaped the while loop, because there is no more carry. Do a simple bitInvert without a carry" ^1 - ((self digitAt: digitIndex) bitAt: bitIndex)! !!LargeNegativeInteger methodsFor: 'bit manipulation' stamp: 'sr 6/8/2000 02:10'!highBit "Answer the index of the high order bit of the receiver, or zero if the receiver is zero. Raise an error if the receiver is negative, since negative integers are defined to have an infinite number of leading 1's in 2's-complement arithmetic. Use >>highBitOfMagnitude if you want to get the highest bit of the magnitude." ^ self shouldNotImplement! !!LargeNegativeInteger methodsFor: 'converting' stamp: 'ar 5/17/2000 16:10'!normalize "Check for leading zeroes and return shortened copy if so" | sLen val len oldLen minVal | <primitive: 'primNormalizeNegative' module:'LargeIntegers'> "First establish len = significant length" len := oldLen := self digitLength. [len = 0 ifTrue: [^0]. (self digitAt: len) = 0] whileTrue: [len := len - 1]. "Now check if in SmallInteger range" sLen := 4 "SmallInteger minVal digitLength". len <= sLen ifTrue: [minVal := SmallInteger minVal. (len < sLen or: [(self digitAt: sLen) < minVal lastDigit]) ifTrue: ["If high digit less, then can be small" val := 0. len to: 1 by: -1 do: [:i | val := (val *256) - (self digitAt: i)]. ^ val]. 1 to: sLen do: "If all digits same, then = minVal" [:i | (self digitAt: i) = (minVal digitAt: i) ifFalse: ["Not so; return self shortened" len < oldLen ifTrue: [^ self growto: len] ifFalse: [^ self]]]. ^ minVal]. "Return self, or a shortened copy" len < oldLen ifTrue: [^ self growto: len] ifFalse: [^ self]! !!LargeNegativeInteger methodsFor: 'printing' stamp: 'nice 2/15/2008 21:47'!printOn: aStream base: b "Append a representation of this number in base b on aStream." aStream nextPut: $-. self abs printOn: aStream base: b! !!LargeNegativeInteger methodsFor: 'testing' stamp: 'di 4/23/1998 11:18'!negative "Answer whether the receiver is mathematically negative." ^ true! !!LargeNegativeInteger methodsFor: 'testing' stamp: 'di 4/23/1998 11:00'!positive "Answer whether the receiver is positive or equal to 0. (ST-80 protocol). See also strictlyPositive" ^ false! !!LargeNegativeInteger methodsFor: 'testing' stamp: 'jm 3/27/98 06:19'!sign "Optimization. Answer -1 since receiver is less than 0." ^ -1! !!LargeNegativeInteger methodsFor: 'testing' stamp: 'di 4/23/1998 11:03'!strictlyPositive "Answer whether the receiver is mathematically positive." ^ false! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!LargeNegativeInteger class instanceVariableNames: ''! Integer subclass: #SmallInteger instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Kernel-Numbers'!!SmallInteger commentStamp: '<historical>' prior: 0!My instances are 31-bit numbers, stored in twos complement form. The allowable range is approximately +- 1 billion (see SmallInteger minVal, maxVal).!!SmallInteger methodsFor: 'arithmetic' stamp: 'di 2/1/1999 21:29'!* aNumber "Primitive. Multiply the receiver by the argument and answer with the result if it is a SmallInteger. Fail if the argument or the result is not a SmallInteger. Essential. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 9> ^ super * aNumber! !!SmallInteger methodsFor: 'arithmetic' stamp: 'di 2/1/1999 21:31'!+ aNumber "Primitive. Add the receiver to the argument and answer with the result if it is a SmallInteger. Fail if the argument or the result is not a SmallInteger Essential No Lookup. See Object documentation whatIsAPrimitive." <primitive: 1> ^ super + aNumber! !!SmallInteger methodsFor: 'arithmetic'!- aNumber "Primitive. Subtract the argument from the receiver and answer with the result if it is a SmallInteger. Fail if the argument or the result is not a SmallInteger. Essential. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 2> ^super - aNumber! !!SmallInteger methodsFor: 'arithmetic' stamp: 'tak 9/25/2008 15:14'!/ aNumber "Primitive. This primitive (for /) divides the receiver by the argument and returns the result if the division is exact. Fail if the result is not a whole integer. Fail if the argument is 0 or is not a SmallInteger. Optional. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 10> aNumber isZero ifTrue: [^(ZeroDivide dividend: self) signal]. ^(aNumber isMemberOf: SmallInteger) ifTrue: [(Fraction numerator: self denominator: aNumber) reduced] ifFalse: [super / aNumber]! !!SmallInteger methodsFor: 'arithmetic' stamp: 'tk 11/30/2001 11:55'!// aNumber "Primitive. Divide the receiver by the argument and answer with the result. Round the result down towards negative infinity to make it a whole integer. Fail if the argument is 0 or is not a SmallInteger. Essential. No Lookup. See Object documentation whatIsAPrimitive. " <primitive: 12> ^ super // aNumber "Do with quo: if primitive fails"! !!SmallInteger methodsFor: 'arithmetic' stamp: 'tk 11/30/2001 11:53'!\\ aNumber "Primitive. Take the receiver modulo the argument. The result is the remainder rounded towards negative infinity, of the receiver divided by the argument Fail if the argument is 0 or is not a SmallInteger. Optional. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 11> ^ super \\ aNumber "will use // to compute it if primitive fails"! !!SmallInteger methodsFor: 'arithmetic' stamp: 'LC 4/22/1998 14:21'!gcd: anInteger "See SmallInteger (Integer) | gcd:" | n m | n := self. m := anInteger. [n = 0] whileFalse: [n := m \\ (m := n)]. ^ m abs! !!SmallInteger methodsFor: 'arithmetic' stamp: 'ul 11/15/2010 10:12'!quo: aNumber "Primitive. Divide the receiver by the argument and answer with the result. Round the result down towards zero to make it a whole integer. Fail if the argument is 0 or is not a SmallInteger. Optional. See Object documentation whatIsAPrimitive." <primitive: 13> aNumber = 0 ifTrue: [^ (ZeroDivide dividend: self) signal]. (aNumber isMemberOf: SmallInteger) ifFalse: [^ super quo: aNumber]. (aNumber = -1 and: [self = self class minVal]) ifTrue: ["result is aLargeInteger" ^ self negated]. self primitiveFailed! !!SmallInteger methodsFor: 'bit manipulation' stamp: 'bf 9/25/2008 15:18'!bitAnd: arg "Primitive. Answer an Integer whose bits are the logical OR of the receiver's bits and those of the argument, arg. Numbers are interpreted as having 2's-complement representation. Essential. See Object documentation whatIsAPrimitive." <primitive: 14> self >= 0 ifTrue: [^ arg bitAnd: self]. ^ (self bitInvert bitOr: arg bitInvert) bitInvert.! !!SmallInteger methodsFor: 'bit manipulation' stamp: 'di 4/30/1998 10:33'!bitOr: arg "Primitive. Answer an Integer whose bits are the logical OR of the receiver's bits and those of the argument, arg. Numbers are interpreted as having 2's-complement representation. Essential. See Object documentation whatIsAPrimitive." <primitive: 15> self >= 0 ifTrue: [^ arg bitOr: self]. ^ arg < 0 ifTrue: [(self bitInvert bitAnd: arg bitInvert) bitInvert] ifFalse: [(self bitInvert bitClear: arg) bitInvert]! !!SmallInteger methodsFor: 'bit manipulation' stamp: 'mir 9/25/2008 15:18'!bitShift: arg "Primitive. Answer an Integer whose value is the receiver's value shifted left by the number of bits indicated by the argument. Negative arguments shift right. The receiver is interpreted as having 2's-complement representation. Essential. See Object documentation whatIsAPrimitive." <primitive: 17> self >= 0 ifTrue: [^ super bitShift: arg]. ^ arg >= 0 ifTrue: [(self negated bitShift: arg) negated] ifFalse: [(self bitInvert bitShift: arg) bitInvert].! !!SmallInteger methodsFor: 'bit manipulation' stamp: 'mir 9/25/2008 15:18'!bitXor: arg "Primitive. Answer an Integer whose bits are the logical XOR of the receiver's bits and those of the argument, arg. Numbers are interpreted as having 2's-complement representation. Essential. See Object documentation whatIsAPrimitive." <primitive: 16> self >= 0 ifTrue: [^ arg bitXor: self]. ^ arg < 0 ifTrue: [self bitInvert bitXor: arg bitInvert] ifFalse: [(self bitInvert bitXor: arg) bitInvert].! !!SmallInteger methodsFor: 'bit manipulation' stamp: 'SqR 8/3/2000 13:29'!hashMultiply | low | low := self bitAnd: 16383. ^(16r260D * low + ((16r260D * (self bitShift: -14) + (16r0065 * low) bitAnd: 16383) * 16384)) bitAnd: 16r0FFFFFFF! !!SmallInteger methodsFor: 'bit manipulation' stamp: 'sr 6/8/2000 02:07'!highBit "Answer the index of the high order bit of the receiver, or zero if the receiver is zero. Raise an error if the receiver is negative, since negative integers are defined to have an infinite number of leading 1's in 2's-complement arithmetic. Use >>highBitOfMagnitude if you want to get the highest bit of the magnitude." self < 0 ifTrue: [^ self error: 'highBit is not defined for negative integers']. ^ self highBitOfPositiveReceiver! !!SmallInteger methodsFor: 'bit manipulation' stamp: 'VeronicaUquillas 6/11/2010 13:01'!highBitOfMagnitude "Answer the index of the high order bit of the receiver, or zero if the receiver is zero. This method is used for negative SmallIntegers as well, since Pharo's LargeIntegers are sign/magnitude." self < 0 ifTrue: [ "Beware: do not use highBitOfPositiveReceiver because self negated is not necessarily a SmallInteger (see SmallInteger minVal)" ^self negated highBitOfMagnitude]. "Implementation note: this method could be as well inlined here." ^self highBitOfPositiveReceiver! !!SmallInteger methodsFor: 'bit manipulation' stamp: 'nice 11/27/2009 19:49'!lowBit " Answer the index of the low order one bit. 2r00101000 lowBit (Answers: 4) 2r-00101000 lowBit (Answers: 4) First we skip bits in groups of 8, then do a lookup in a table. While not optimal, this is a good tradeoff; long integer #lowBit always invokes us with bytes." | n result lastByte | n := self. n = 0 ifTrue: [ ^ 0 ]. result := 0. [(lastByte := n bitAnd: 16rFF) = 0] whileTrue: [ result := result + 8. n := n bitShift: -8 ]. "The low bits table can be obtained with: ((1 to: 8) inject: #[1] into: [:lowBits :rank | (lowBits copy at: 1 put: lowBits first + 1; yourself) , lowBits]) allButFirst." ^result + ( #[1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 7 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 8 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 7 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 6 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1] at: lastByte)! !!SmallInteger methodsFor: 'comparing'!< aNumber "Primitive. Compare the receiver with the argument and answer with true if the receiver is less than the argument. Otherwise answer false. Fail if the argument is not a SmallInteger. Essential. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 3> ^super < aNumber! !!SmallInteger methodsFor: 'comparing'!<= aNumber "Primitive. Compare the receiver with the argument and answer true if the receiver is less than or equal to the argument. Otherwise answer false. Fail if the argument is not a SmallInteger. Optional. No Lookup. See Object documentation whatIsAPrimitive. " <primitive: 5> ^super <= aNumber! !!SmallInteger methodsFor: 'comparing'!= aNumber "Primitive. Compare the receiver with the argument and answer true if the receiver is equal to the argument. Otherwise answer false. Fail if the argument is not a SmallInteger. Essential. No Lookup. See Object documentation whatIsAPrimitive. " <primitive: 7> ^super = aNumber! !!SmallInteger methodsFor: 'comparing'!> aNumber "Primitive. Compare the receiver with the argument and answer true if the receiver is greater than the argument. Otherwise answer false. Fail if the argument is not a SmallInteger. Essential. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 4> ^super > aNumber! !!SmallInteger methodsFor: 'comparing'!>= aNumber "Primitive. Compare the receiver with the argument and answer true if the receiver is greater than or equal to the argument. Otherwise answer false. Fail if the argument is not a SmallInteger. Optional. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 6> ^super >= aNumber! !!SmallInteger methodsFor: 'comparing'!hash ^self! !!SmallInteger methodsFor: 'comparing' stamp: 'MartinMcClure 3/19/2010 00:09'!identityHash ^self hashMultiply! !!SmallInteger methodsFor: 'comparing'!~= aNumber "Primitive. Compare the receiver with the argument and answer true if the receiver is not equal to the argument. Otherwise answer false. Fail if the argument is not a SmallInteger. Essential. No Lookup. See Object documentation whatIsAPrimitive." <primitive: 8> ^super ~= aNumber! !!SmallInteger methodsFor: 'converting' stamp: 'ajh 7/25/2001 22:34'!as31BitSmallInt "Polymorphic with LargePositiveInteger (see comment there). Return self since all SmallIntegers are 31 bits" ^ self! !!SmallInteger methodsFor: 'converting'!asFloat "Primitive. Answer a Float that represents the value of the receiver. Essential. See Object documentation whatIsAPrimitive." <primitive: 40> self primitiveFailed! !!SmallInteger methodsFor: 'copying'!deepCopy! !!SmallInteger methodsFor: 'copying'!shallowCopy! !!SmallInteger methodsFor: 'copying' stamp: 'tk 8/19/1998 16:04'!veryDeepCopyWith: deepCopier "Return self. I can't be copied. Do not record me."! !!SmallInteger methodsFor: 'memory' stamp: 'MarianoMartinezPeck 10/1/2010 11:11'!sizeInMemory "SmallInteger occupy 0 bytes since the only space occupied by a SmallInteger is the space of the slot containing it. There is no SmallInteger object beyond the slot. From another POV, it could be 4, the size of the slot. But we don't count the size of the slots, they are already counted in the containing object, that's why it should answer 0." ^0.! !!SmallInteger methodsFor: 'printing' stamp: 'gk 5/25/2007 15:10'!decimalDigitLength "Answer the number of digits printed out in base 10. Note that this only works for positive SmallIntegers." ^ self < 10000 ifTrue: [self < 100 ifTrue: [self < 10 ifTrue: [1] ifFalse: [2]] ifFalse: [self < 1000 ifTrue: [3] ifFalse: [4]]] ifFalse: [self < 1000000 ifTrue: [self < 100000 ifTrue: [5] ifFalse: [6]] ifFalse: [self < 100000000 ifTrue: [self < 10000000 ifTrue: [7] ifFalse: [8]] ifFalse: [self < 1000000000 ifTrue: [9] ifFalse: [10]]]]! !!SmallInteger methodsFor: 'printing' stamp: 'MPW 1/1/1901 00:15'!destinationBuffer:digitLength ^ LargePositiveInteger new: digitLength.! !!SmallInteger methodsFor: 'printing' stamp: 'nice 2/15/2008 22:22'!numberOfDigitsInBase: b "Return how many digits are necessary to print this number in base b. Mostly same as super but an optimized version for base 10 case" b = 10 ifFalse: [^super numberOfDigitsInBase: b]. self < 0 ifTrue: [^self negated numberOfDigitsInBase: b]. ^self decimalDigitLength! !!SmallInteger methodsFor: 'printing' stamp: 'ul 12/8/2010 03:59'!printOn: stream base: base "Append a representation of this number in base b on aStream." self printOn: stream base: base length: 0 padded: false! !!SmallInteger methodsFor: 'printing' stamp: 'ul 11/30/2010 01:38'!printOn: stream base: base length: minimumLength padded: padWithZeroes | n numberOfDigits totalLength divisor | self < 0 ifTrue: [ n := self negated. totalLength := 1 ] ifFalse: [ n := self. totalLength := 0 ]. numberOfDigits := n numberOfDigitsInBase: base. totalLength := totalLength + numberOfDigits. padWithZeroes ifFalse: [ [ totalLength < minimumLength ] whileTrue: [ stream space. totalLength := totalLength + 1 ] ]. n = self ifFalse: [ stream nextPut: $- ]. padWithZeroes ifTrue: [ [ totalLength < minimumLength ] whileTrue: [ stream nextPut: $0. totalLength := totalLength + 1 ] ]. divisor := (base raisedToInteger: numberOfDigits - 1). [ divisor > 0 ] whileTrue: [ | digit | digit := n // divisor. stream nextPut: ('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' at: digit + 1). n := n - (digit * divisor). divisor := divisor // base ]! !!SmallInteger methodsFor: 'printing' stamp: 'ul 12/8/2010 04:00'!printOn: aStream base: b nDigits: n "Append a representation of this number in base b on aStream using nDigits. self must be positive." self printOn: aStream base: b length: n padded: true! !!SmallInteger methodsFor: 'printing' stamp: 'gk 5/25/2007 15:08'!printString "Highly optimized version for base 10 and that we know it is a SmallInteger." | integer next result len | self = 0 ifTrue: [^'0']. self < 0 ifTrue: [^'-', self negated printString]. len := self decimalDigitLength. result := String new: len. integer := self. len to: 1 by: -1 do: [:i | next := integer // 10. result byteAt: i put: 48 + (integer - (next * 10)). integer := next]. ^result! !!SmallInteger methodsFor: 'printing' stamp: 'nice 7/6/2008 00:48'!printStringBase: b "Return a String representation of this number in base b. For SmallIntegers, it is more efficient to print directly in a String, rather than using a Stream like super." self < 0 ifTrue: [^ '-' , (self negated printStringBase: b)]. self < b ifTrue: [^ String with: (Character digitValue: self)]. ^ self printStringBase: b nDigits: (self numberOfDigitsInBase: b)! !!SmallInteger methodsFor: 'printing' stamp: 'nice 2/15/2008 21:39'!printStringBase: b nDigits: n "Return a string representation of this number in base b with n digits (left padded with 0). Should be invoked with: 0 <= self < (b raisedToInteger: n)." | integer next result | result := String new: n. integer := self. n to: 1 by: -1 do: [:i | next := integer // b. result byteAt: i put: (Character digitValue: (integer - (next * b))). integer := next]. ^result! !!SmallInteger methodsFor: 'printing' stamp: 'RAA 8/24/2001 13:59'!threeDigitName | units answer | self = 0 ifTrue: [^'']. units := #('one' 'two' 'three' 'four' 'five' 'six' 'seven' 'eight' 'nine' 'ten' 'eleven' 'twelve' 'thirteen' 'fourteen' 'fifteen' 'sixteen' 'seventeen' 'eighteen' 'nineteen'). self > 99 ifTrue: [ answer := (units at: self // 100),' hundred'. (self \\ 100) = 0 ifFalse: [ answer := answer,' ',(self \\ 100) threeDigitName ]. ^answer ]. self < 20 ifTrue: [ ^units at: self ]. answer := #('twenty' 'thirty' 'forty' 'fifty' 'sixty' 'seventy' 'eighty' 'ninety') at: self // 10 - 1. (self \\ 10) = 0 ifFalse: [ answer := answer,'-',(units at: self \\ 10) ]. ^answer! !!SmallInteger methodsFor: 'system primitives' stamp: 'MartinMcClure 1/12/2010 21:12'!basicIdentityHash ^self! !!SmallInteger methodsFor: 'system primitives' stamp: 'tk 3/24/1999 20:28'!digitAt: n "Answer the value of an indexable field in the receiver. LargePositiveInteger uses bytes of base two number, and each is a 'digit' base 256. Fail if the argument (the index) is not an Integer or is out of bounds." n>4 ifTrue: [^ 0]. self < 0 ifTrue: [self = SmallInteger minVal ifTrue: ["Can't negate minVal -- treat specially" ^ #(0 0 0 64) at: n]. ^ ((0-self) bitShift: (1-n)*8) bitAnd: 16rFF] ifFalse: [^ (self bitShift: (1-n)*8) bitAnd: 16rFF]! !!SmallInteger methodsFor: 'system primitives' stamp: 'md 6/5/2003 10:42'!digitAt: n put: value "Fails. The digits of a small integer can not be modified." self error: 'You can''t store in a SmallInteger'! !!SmallInteger methodsFor: 'system primitives'!digitLength "Answer the number of indexable fields in the receiver. This value is the same as the largest legal subscript. Included so that a SmallInteger can behave like a LargePositiveInteger or LargeNegativeInteger." (self < 16r100 and: [self > -16r100]) ifTrue: [^ 1]. (self < 16r10000 and: [self > -16r10000]) ifTrue: [^ 2]. (self < 16r1000000 and: [self > -16r1000000]) ifTrue: [^ 3]. ^ 4! !!SmallInteger methodsFor: 'system primitives'!instVarAt: i "Small integer has to be specially handled." i = 1 ifTrue: [^self]. self error: 'argument too big for small integer instVarAt:'! !!SmallInteger methodsFor: 'system primitives' stamp: 'tk 5/14/1999 20:54'!nextInstance "SmallIntegers can't be enumerated this way. There are a finite number of them from from (SmallInteger minVal) to (SmallInteger maxVal), but you'll have to enumerate them yourself with: (SmallInteger minVal) to: (SmallInteger maxVal) do: [:integer | <your code here>]. " self shouldNotImplement ! !!SmallInteger methodsFor: 'system primitives' stamp: 'je 10/22/2002 12:10'!nextObject "SmallIntegers are immediate objects, and, as such, do not have successors in object memory." self shouldNotImplement ! !!SmallInteger methodsFor: 'testing'!even ^(self bitAnd: 1) = 0! !!SmallInteger methodsFor: 'testing' stamp: 'nice 8/31/2008 00:07'!isLarge ^false! !!SmallInteger methodsFor: 'testing'!odd ^(self bitAnd: 1) = 1! !!SmallInteger methodsFor: 'private'!fromString: str radix: radix | maxdigit c val | maxdigit := radix + (radix > 10 ifTrue: [55 - 1] ifFalse: [48 - 1]). val := 0. 1 to: str size do: [:i | c := str at: i. (c < 48 ifFalse: [c > maxdigit]) ifTrue: [^false]. val := val * radix + (c <= 57 ifTrue: [c - 48] ifFalse: [c < 65 ifTrue: [^false]. c - 55])]. ^val! !!SmallInteger methodsFor: 'private' stamp: 'nice 11/27/2009 19:58'!highBitOfPositiveReceiver | shifted bitNo | "Answer the index of the high order bit of the receiver, or zero if the receiver is zero. Receiver has to be positive!!" shifted := self. bitNo := 0. [shifted < 65536] whileFalse: [shifted := shifted bitShift: -16. bitNo := bitNo + 16]. shifted < 256 ifFalse: [shifted := shifted bitShift: -8. bitNo := bitNo + 8]. "The high bits table can be obtained with: (1 to: 8) inject: #[0] into: [:highBits :rank | highBits , (highBits collect: [:e | rank])]." ^bitNo + ( #[0 1 2 2 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8] at: shifted + 1)! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!SmallInteger class instanceVariableNames: ''!!SmallInteger class methodsFor: 'constants'!maxVal "Answer the maximum value for a SmallInteger." ^ 16r3FFFFFFF! !!SmallInteger class methodsFor: 'constants'!minVal "Answer the minimum value for a SmallInteger." ^ -16r40000000! !!SmallInteger class methodsFor: 'documentation'!guideToDivision "Handy guide to the kinds of Integer division: / exact division, returns a fraction if result is not a whole integer. // returns an Integer, rounded towards negative infinity. \\ is modulo rounded towards negative infinity. quo: truncated division, rounded towards zero."! !!SmallInteger class methodsFor: 'instance creation' stamp: 'tk 4/20/1999 14:17'!basicNew self error: 'SmallIntegers can only be created by performing arithmetic'! !!SmallInteger class methodsFor: 'instance creation' stamp: 'tk 4/20/1999 14:18'!new self basicNew "generates an error"! !!SmallInteger class methodsFor: 'plugin generation' stamp: 'acg 9/20/1999 11:20'!ccgCanConvertFrom: anObject ^anObject class == self! !Float initialize!Integer initialize!