Long multiplication: Difference between revisions

Content added Content deleted
(Added 11l)
Line 5,453: Line 5,453:
{{out}}
{{out}}
3402823669293846346337467431768211456
3402823669293846346337467431768211456

The above code does not really integrate into the Smalltalk class library. For example, it will not allow mixed mode arithmetic between regular integers and ''Rosetta integers''.
Here is a full example in portable chunk file format which makes mixed mode arithmetic completely transparent (I implemented only addition and multiplication):
<lang smalltalk>Integer
subclass: #RosettaInteger
instanceVariableNames:'digitArray'
classVariableNames:'WORDMAX'
package:'Rosetta demos'
!

!RosettaInteger class methodsFor:'initialization'!

initialize
WORDMAX := 100.
! !

!RosettaInteger class methodsFor:'instance creation'!

newWithDigits:digitArray
"returns a new RosettaInteger with a digitArray"

^ self basicNew digits:digitArray
!

fromInteger:anInteger
"returns a new RosettaInteger with anInteger's value"

|digits gen|

gen := [:n :s |
s nextPut:(n % 100).
n > 99 ifTrue:[ gen value:(n // 100) value:s]].
digits := Array streamContents:[:s | gen value:anInteger value:s].
^ self newWithDigits:digits
! !

!RosettaInteger class methodsFor:'helpers'!

addDigits:a and:b
|add|

add :=
[:a :b |
Array streamContents:[:s |
|cy|
cy := 0.
1 to:(a size max:b size) do:[:wordIndex |
|sum|
wA := a at:wordIndex ifAbsent:0.
wB := b at:wordIndex ifAbsent:0.
sum := (wA + wB + cy).
cy := (sum // WORDMAX).
s nextPut:(sum % WORDMAX).
].
cy ~~ 0 ifTrue:[s nextPut:cy].
].
].
^ add value:a value:b
!

mulDigits:a and:b
|mulW|

mulW :=
[:a :w |
|cy|
cy := 0.
Array streamContents:[:s |
a do:[:wordA |
|product|
product := (wordA * w) + cy.
s nextPut:(product % WORDMAX).
cy := (product // WORDMAX)
].
cy ~~ 0 ifTrue:[s nextPut:cy].
]
].

mul :=
[:a :b |
|sum|

sum := #( 0 ).
b doWithIndex:[:wordB :wordIndex |
partSum := mulW value:a value:wordB.
shifted := (Array new:wordIndex-1 withAll:0),partSum.
sum := self addDigits:sum and:shifted.
].
sum.
].

^ mul value:a value:b.
! !

!RosettaInteger methodsFor:'private accessing'!
digits
"return my digitArray"

^ digitArray
!

digits:digits
"set my digitArray"

digitArray := digits
! !

!RosettaInteger methodsFor:'arithmetic'!
+ aNumber
^ aNumber sumFromRosettaInteger:self
!

* aNumber
^ aNumber productFromRosettaInteger:self
!

raisedTo:exp
|raise|

raise :=
[:a :exp |
|e rslt|

rslt := #(1).
t := a.
e := exp.
[e ~~ 0] whileTrue:[
[(e bitAnd:1) == 0] whileTrue:[
e := e bitShift:-1.
t := self class mulDigits:t and:t.
].
e := e - 1.
rslt := self class mulDigits:rslt and:t.
].
rslt.
].
^ self class newWithDigits:(raise value:(self digits) value:exp)
!

sumFromRosettaInteger:anRInt
^ self class
newWithDigits:(self class addDigits:(anRInt digits) and:(self digits))
!

productFromRosettaInteger:anRInt
^ self class newWithDigits:(self class mulDigits:(anRInt digits) and:(self digits))
! !

!RosettaInteger methodsFor:'printing'!

printOn:aStream
|print|

print :=
[:n :stream |
|first|
first := true.
n reverseDo:[:_2Digits |
first
ifTrue:[ stream nextPutAll:(_2Digits printString)]
ifFalse:[ stream nextPutAll:(_2Digits printString leftPaddedTo:2 with:$0)].
first := false.
].
].

print value:(self digits) value:aStream
! !

!Integer methodsFor:'converting'!

asRosettaInteger
^ RosettaInteger fromInteger:self
! !

!Integer methodsFor:'double dispatching'!

sumFromRosettaInteger:anRInt
^ anRInt + (RosettaInteger fromInteger:self)
!

productFromRosettaInteger:anRInt
^ anRInt * (RosettaInteger fromInteger:self)
! !

RosettaInteger initialize
!

a := 124 asRosettaInteger.
e'a is: {a} ({a class})' printCR.
b := 333 asRosettaInteger.
e'b is: {b} ({b class})'printCR.
a_plus_b := a+b.
e'(a+b) is: {a_plus_b} ({(a_plus_b) class})' printCR.

c := 999 asRosettaInteger.
e'c is: {c} ({c class})' printCR.
c_plus_1 := c+1.
e'c+1 is: {c_plus_1} ({(c_plus_1) class})' printCR.

d := 100 asRosettaInteger.
e'd is: {d} ({d class})' printCR.
d_squared := d squared.
e'd squared is: {d_squared} ({d_squared class})' printCR.

e := 2 asRosettaInteger.
e_raisedTo_64 := e raisedTo:64.
e'2 raisedTo:64 is: {e_raisedTo_64} ({e_raisedTo_64 class})' printCR.

e_raisedTo_64_squared := (e raisedTo:64) squared.
e'result is: {e_raisedTo_64_squared} ({e_raisedTo_64_squared class})' printCR.

Transcript show:'once again: '.
result := (2 asRosettaInteger raisedTo:64) squared.
Transcript showCR:result.</lang>
{{out}}
<pre>a is: 124 (RosettaInteger)
b is: 333 (RosettaInteger)
(a+b) is: 457 (RosettaInteger)
c is: 999 (RosettaInteger)
c+1 is: 1000 (RosettaInteger)
d is: 100 (RosettaInteger)
d squared is: 10000 (RosettaInteger)
2 raisedTo:64 is: 18446744073709551616 (RosettaInteger)
result is: 340282366920938463463374607431768211456 (RosettaInteger)
once again: 340282366920938463463374607431768211456</pre>


=={{header|Tcl}}==
=={{header|Tcl}}==