danbaron
30-08-2011, 08:43
This program calculates a power sum twice.
By a power sum, I mean, for given values of x and n,
power sum = x^0 + x^1 + x^2 + x^3 + .. + x^n.
As it is, in the program I have set x=2, and n=100.
The program calculates the given power sum twice, only the first time it calls the function, "slowevaluation()", and the second time it calls the function, "fastevaluation()".
(Actually, both of the functions are very slow, but one is much faster than the other.)
Both evaluations give the same sum.
The question is, why is the fast function so much faster than the slow function (or vice versa)?
' code ----------------------------------------------------------------------------------------------
Uses "console"
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%neg = -1
%pos = +1
%intsize = 500
Type genint
digit(%intsize) As Byte
sign As Integer
error As Byte
End Type
'--------------------------------------------------------------
Function TBMain()
Local s As String
Local t1, t2, tt As Integer
Local x, ps As genint
Local n As DWord
'Set value of x (string s).
s = "2"
'Set number of terms, n.
n = 20
genintsetvalue(x,s)
PrintL "power sum = x^0 + x^1 + x^2 + .. + x^n"
PrintL
PrintL "x = ", Format$(s)
PrintL "n = ", n
PrintL
PrintL "-------------------------------------------------------------"
PrintL
PrintL "Calculating power sum by slow method."
t1 = Timer
slowevaluation(x,n, ps)
s = genintgetstringrep(ps)
t2 = Timer
tt = t2 - t1
PrintL
PrintL "sum = ", s
PrintL
PrintL "elapsed time = ", tt, " seconds"
PrintL
PrintL "-------------------------------------------------------------"
PrintL
PrintL "Calculating power sum by fast method."
t1 = Timer
fastevaluation(x,n, ps)
s = genintgetstringrep(ps)
t2 = Timer
tt = t2 - t1
PrintL
PrintL "sum = ", s
PrintL
PrintL "elapsed time = ", tt, " seconds"
PrintL
PrintL "-------------------------------------------------------------"
PrintL
PrintL "Done. Press a key to quit."
WaitKey
End Function
'--------------------------------------------------------------
Function slowevaluation(ByRef x As genint, n As DWord, psum As genint)
Local xp As genint
Local s As String
Local i As Integer
s = "0"
genintsetvalue(psum,s)
If n=0 Then Return
For i = 0 To n
genintpower(x,i,xp)
genintadd(psum,xp,psum)
Next
End Function
'--------------------------------------------------------------
Function fastevaluation(ByRef x As genint, n As DWord, psum As genint)
Local temp, xp As genint
Local s As String
Local i As Integer
s = "0"
genintsetvalue(psum,s)
If n=0 Then Return
s = "1"
genintsetvalue(psum,s)
genintsetvalue(xp,s)
For i = 1 To n
genintmult(xp,x,temp)
genintsetequal(xp,temp)
genintadd(psum,xp,psum)
Next
End Function
'--------------------------------------------------------------
Function genintpower(ByRef x As genint, p As DWord, ByRef xp As genint)
Local product, temp As genint
Local s As String
Local i As Integer
s = "1"
genintsetvalue(xp,s)
If p=0 Then Return
For i = 1 To p
genintmult(xp,x,temp)
genintsetequal(xp,temp)
Next
End Function
'--------------------------------------------------------------
Function genintfactorial(n As Integer) As String
Local num1, num2, num3 As genint
Local s As String
Local i As Integer
s = "1"
genintsetvalue(num1,s)
For i = n To 2 Step -1
PrintL i
s = Format$(i)
genintsetvalue(num2,s)
genintmult(num1,num2,num3)
genintsetequal(num1,num3)
Next
Return genintgetstringrep(num3)
End Function
'--------------------------------------------------------------
Function genintsetequal(gn2 As genint, gn1 As genint)
'Set gn2 = gn1.
Local i As DWord
For i = 1 To %intsize
gn2.digit(i) = gn1.digit(i)
Next
End Function
'--------------------------------------------------------------
Function genintsetvalue(gn As genint, vs As String)
Local i, l As DWord
genintzero(gn)
l = Len(vs)
For i = 1 To l
gn.digit(l - i + 1) = Val(Mid$(vs, i, 1))
Next
End Function
'--------------------------------------------------------------
Function genintzero(gn As genint)
Local i As DWord
For i = 1 To %intsize
gn.digit(i) = 0
Next
End Function
'--------------------------------------------------------------
Function genintsetsign(gn As genint, s As Integer)
gn.sign = s
End Function
'--------------------------------------------------------------
Function genintgetstringrep(gn As genint) As String
Local i, j As DWord
Local vs As String
vs = ""
If gn.sign > -1 Then
vs = vs & "+"
Else
vs = vs & "-"
EndIf
i = 0
Do
If %intsize - i = 0 Then Return "0"
If gn.digit(%intsize - i) > 0 Then Exit Do
i += 1
Loop
For j = i + 1 To %intsize
vs = vs & Chr$(48 + gn.digit(%intsize - j + 1))
Next
Return vs
End Function
'--------------------------------------------------------------
Function genintgetsize(gn As genint) As DWord
Local i As DWord
i = 0
Do
If %intsize - i = 0 Then Return 0
If gn.digit(%intsize - i) > 0 Then Exit Do
i += 1
Loop
Return %intsize - i
End Function
'--------------------------------------------------------------
Function genintseterror(gn As genint)
gn.error = TRUE
End Function
'--------------------------------------------------------------
Function genintshiftleft(gn As genint, nplaces As DWord)
Local sz, i, j As DWord
sz = genintgetsize(gn)
For i = 1 To sz
j = sz - i + 1
gn.digit(j + nplaces) = gn.digit(j)
Next
For i = 1 To nplaces
gn.digit(i) = 0
Next
End Function
'--------------------------------------------------------------
Function genintadd(a As genint, b As genint, c As genint)
Local i As DWord
Local s, v, k As Byte
Local asize, bsize, maxsize
Local temp As genint
asize = genintgetsize(a)
bsize = genintgetsize(b)
maxsize = asize
If bsize > maxsize Then maxsize = bsize
genintzero(temp)
k = 0
For i = 1 To maxsize + 1
s = a.digit(i) + b.digit(i) + k
v = Mod(s, 10)
k = s \ 10
temp.digit(i) = v
Next
For i = 1 To %intsize
c.digit(i) = temp.digit(i)
Next
End Function
'--------------------------------------------------------------
Function genintmult(a As genint, b As genint, c As genint)
Local i, j As DWord
Local p, v, k As Byte
Local asize, bsize, tsize As DWord
Local temp As genint
genintzero(c)
genintzero(temp)
asize = genintgetsize(a)
bsize = genintgetsize(b)
tsize = asize + bsize
If tsize > %intsize Then
genintseterror(c)
Return
EndIf
For i = 1 To asize
k = 0
For j = 1 To bsize + 1
p = a.digit(i) * b.digit(j) + k
v = Mod(p, 10)
k = p \ 10
temp.digit(j) = v
Next
genintshiftleft(temp, i - 1)
genintadd(c, temp, c)
genintzero(temp)
Next
End Function
' output --------------------------------------------------------------------------------------------
power sum = x^0 + x^1 + x^2 + .. + x^n
x = 2
n = 100
-------------------------------------------------------------
Calculating power sum by slow method.
sum = +2535301200456458802993406410751
elapsed time = 506 seconds
-------------------------------------------------------------
Calculating power sum by fast method.
sum = +2535301200456458802993406410751
elapsed time = 16 seconds
-------------------------------------------------------------
Done. Press a key to quit.
By a power sum, I mean, for given values of x and n,
power sum = x^0 + x^1 + x^2 + x^3 + .. + x^n.
As it is, in the program I have set x=2, and n=100.
The program calculates the given power sum twice, only the first time it calls the function, "slowevaluation()", and the second time it calls the function, "fastevaluation()".
(Actually, both of the functions are very slow, but one is much faster than the other.)
Both evaluations give the same sum.
The question is, why is the fast function so much faster than the slow function (or vice versa)?
' code ----------------------------------------------------------------------------------------------
Uses "console"
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%neg = -1
%pos = +1
%intsize = 500
Type genint
digit(%intsize) As Byte
sign As Integer
error As Byte
End Type
'--------------------------------------------------------------
Function TBMain()
Local s As String
Local t1, t2, tt As Integer
Local x, ps As genint
Local n As DWord
'Set value of x (string s).
s = "2"
'Set number of terms, n.
n = 20
genintsetvalue(x,s)
PrintL "power sum = x^0 + x^1 + x^2 + .. + x^n"
PrintL
PrintL "x = ", Format$(s)
PrintL "n = ", n
PrintL
PrintL "-------------------------------------------------------------"
PrintL
PrintL "Calculating power sum by slow method."
t1 = Timer
slowevaluation(x,n, ps)
s = genintgetstringrep(ps)
t2 = Timer
tt = t2 - t1
PrintL
PrintL "sum = ", s
PrintL
PrintL "elapsed time = ", tt, " seconds"
PrintL
PrintL "-------------------------------------------------------------"
PrintL
PrintL "Calculating power sum by fast method."
t1 = Timer
fastevaluation(x,n, ps)
s = genintgetstringrep(ps)
t2 = Timer
tt = t2 - t1
PrintL
PrintL "sum = ", s
PrintL
PrintL "elapsed time = ", tt, " seconds"
PrintL
PrintL "-------------------------------------------------------------"
PrintL
PrintL "Done. Press a key to quit."
WaitKey
End Function
'--------------------------------------------------------------
Function slowevaluation(ByRef x As genint, n As DWord, psum As genint)
Local xp As genint
Local s As String
Local i As Integer
s = "0"
genintsetvalue(psum,s)
If n=0 Then Return
For i = 0 To n
genintpower(x,i,xp)
genintadd(psum,xp,psum)
Next
End Function
'--------------------------------------------------------------
Function fastevaluation(ByRef x As genint, n As DWord, psum As genint)
Local temp, xp As genint
Local s As String
Local i As Integer
s = "0"
genintsetvalue(psum,s)
If n=0 Then Return
s = "1"
genintsetvalue(psum,s)
genintsetvalue(xp,s)
For i = 1 To n
genintmult(xp,x,temp)
genintsetequal(xp,temp)
genintadd(psum,xp,psum)
Next
End Function
'--------------------------------------------------------------
Function genintpower(ByRef x As genint, p As DWord, ByRef xp As genint)
Local product, temp As genint
Local s As String
Local i As Integer
s = "1"
genintsetvalue(xp,s)
If p=0 Then Return
For i = 1 To p
genintmult(xp,x,temp)
genintsetequal(xp,temp)
Next
End Function
'--------------------------------------------------------------
Function genintfactorial(n As Integer) As String
Local num1, num2, num3 As genint
Local s As String
Local i As Integer
s = "1"
genintsetvalue(num1,s)
For i = n To 2 Step -1
PrintL i
s = Format$(i)
genintsetvalue(num2,s)
genintmult(num1,num2,num3)
genintsetequal(num1,num3)
Next
Return genintgetstringrep(num3)
End Function
'--------------------------------------------------------------
Function genintsetequal(gn2 As genint, gn1 As genint)
'Set gn2 = gn1.
Local i As DWord
For i = 1 To %intsize
gn2.digit(i) = gn1.digit(i)
Next
End Function
'--------------------------------------------------------------
Function genintsetvalue(gn As genint, vs As String)
Local i, l As DWord
genintzero(gn)
l = Len(vs)
For i = 1 To l
gn.digit(l - i + 1) = Val(Mid$(vs, i, 1))
Next
End Function
'--------------------------------------------------------------
Function genintzero(gn As genint)
Local i As DWord
For i = 1 To %intsize
gn.digit(i) = 0
Next
End Function
'--------------------------------------------------------------
Function genintsetsign(gn As genint, s As Integer)
gn.sign = s
End Function
'--------------------------------------------------------------
Function genintgetstringrep(gn As genint) As String
Local i, j As DWord
Local vs As String
vs = ""
If gn.sign > -1 Then
vs = vs & "+"
Else
vs = vs & "-"
EndIf
i = 0
Do
If %intsize - i = 0 Then Return "0"
If gn.digit(%intsize - i) > 0 Then Exit Do
i += 1
Loop
For j = i + 1 To %intsize
vs = vs & Chr$(48 + gn.digit(%intsize - j + 1))
Next
Return vs
End Function
'--------------------------------------------------------------
Function genintgetsize(gn As genint) As DWord
Local i As DWord
i = 0
Do
If %intsize - i = 0 Then Return 0
If gn.digit(%intsize - i) > 0 Then Exit Do
i += 1
Loop
Return %intsize - i
End Function
'--------------------------------------------------------------
Function genintseterror(gn As genint)
gn.error = TRUE
End Function
'--------------------------------------------------------------
Function genintshiftleft(gn As genint, nplaces As DWord)
Local sz, i, j As DWord
sz = genintgetsize(gn)
For i = 1 To sz
j = sz - i + 1
gn.digit(j + nplaces) = gn.digit(j)
Next
For i = 1 To nplaces
gn.digit(i) = 0
Next
End Function
'--------------------------------------------------------------
Function genintadd(a As genint, b As genint, c As genint)
Local i As DWord
Local s, v, k As Byte
Local asize, bsize, maxsize
Local temp As genint
asize = genintgetsize(a)
bsize = genintgetsize(b)
maxsize = asize
If bsize > maxsize Then maxsize = bsize
genintzero(temp)
k = 0
For i = 1 To maxsize + 1
s = a.digit(i) + b.digit(i) + k
v = Mod(s, 10)
k = s \ 10
temp.digit(i) = v
Next
For i = 1 To %intsize
c.digit(i) = temp.digit(i)
Next
End Function
'--------------------------------------------------------------
Function genintmult(a As genint, b As genint, c As genint)
Local i, j As DWord
Local p, v, k As Byte
Local asize, bsize, tsize As DWord
Local temp As genint
genintzero(c)
genintzero(temp)
asize = genintgetsize(a)
bsize = genintgetsize(b)
tsize = asize + bsize
If tsize > %intsize Then
genintseterror(c)
Return
EndIf
For i = 1 To asize
k = 0
For j = 1 To bsize + 1
p = a.digit(i) * b.digit(j) + k
v = Mod(p, 10)
k = p \ 10
temp.digit(j) = v
Next
genintshiftleft(temp, i - 1)
genintadd(c, temp, c)
genintzero(temp)
Next
End Function
' output --------------------------------------------------------------------------------------------
power sum = x^0 + x^1 + x^2 + .. + x^n
x = 2
n = 100
-------------------------------------------------------------
Calculating power sum by slow method.
sum = +2535301200456458802993406410751
elapsed time = 506 seconds
-------------------------------------------------------------
Calculating power sum by fast method.
sum = +2535301200456458802993406410751
elapsed time = 16 seconds
-------------------------------------------------------------
Done. Press a key to quit.