EmilSekerinski,McMasterUniversity,WinterTerm16/17COMPSCI1MD3IntroductiontoProgramming
"Thereareonly10typesofpeopleintheworld:thosewhounderstandbinaryandthosewhodon't"
Integeraisanapproximatesquarerootofnifa2 ≤ n < (a+1)2
Onewaytocomputethesquarerootisbylinearsearch(exhaustivesearch):def linearSqrt(n): a = 0 while (a+1)*(a+1) <= n: a = a+1 return a
>>> linearSqrt(27)5
Statement a
A 0
B 1
B 2
B 3
B 4
B 5
A:
B:
Traceforinputn=27:
def linearSqrt (n): a = 0 while (a+1)*(a+1) <= n: a = a+1 return a
A:
Aisexecutedexactlyatimes,so:
linearSqrt(4) = 2 →2timeslinearSqrt(8) = 2 →2timeslinearSqrt(9) = 3 →3timeslinearSqrt(10) = 3 →3times
Hence,Aisexecuted√ntimes(√hereintegersquareroot)
Supposewehavea,bsuchthattherootisbetweenaandb:0 ≤ a < b and a2 ≤ n < b2
Werepeatedlyreplaceeitheraorbby(a+b)//2suchthataboveholds,untila+1 == b;thenaistheapproximatesquarerootwhile a+1 != b: c = (a+b)//2 if c*c <= n: a = c else: b = cHowdowefindsuitableinitialvaluesforaandb?
Statement a b c
C 0 8 4
D 4 8 4
D 4 8 6
E 4 6 6
C 4 6 5
D 5 6 5
C:D:E:
Traceforn=27,a=0,b=8:
Forawetake0.Forb,thesmallestvaluesatisfying0 ≤ a < b is1,whichwemultiplyby2untilbsatisfiesa2 ≤ n < b2Howoftenaretheloopbodiesexecuted?
a,b:=0,1
a+1≠b
c*c≤n
a:=c b:=c
+
–
+ –
c:=(a+b)//2
def binarySqrt(n): a, b = 0, 1 while b*b <= n: b = 2*b while a+1 != b: c = (a+b)//2 if c*c <= n: a = c else: b = c return a
0≤a<ba2≤n<b2
b*b≤n+
–
b:=2*b
a+1=ba2≤n<(a+1)2
Thefirstloopsetsb = 2k > √nafterkexecutions.Thesecondloophalvestheintervalb - aateveryexecution,untila+1 = b,hencealsotakeskexecutions.Henceeachlooptakesk = log2 bexecutions,sok ≈ log2 √n
def binarySqrt(n): a, b = 0, 1 while b*b <= n: b = 2*b while a+1 != b: c = (a+b)//2 if c*c <= n: a = c else: b = c return a
Statement a b c
A 0 1
B 0 2
B 0 4
B 0 8
C 0 8 4
… … … …
Traceforn=27:
A:
B:
C:D:
E:
Atriple(a,b,c)ofintegersisPythagoreanifa2+b2=c2Asimplewaytofindsuchtriplesisbybruteforce:enumerateallvaluesofa,b,candcheckiftheyformaPythagoreanTripledef printPythagoreanTriples1(n): for a in range(1, n+1): for b in range(1, n+1): for c in range(1, n+1): if a**2+b**2 == c**2: print(a, b, c)printPythagoreanTriples1doesnotreturnaresult,buthasaside-effect,printingonthescreen.Itisaprocedure(method)ratherthanafunctioninthemathematicalsense
3
4
5
def printPythagoreanTriples1(n): for a in range(1, n+1): for b in range(1, n+1): for c in range(1, n+1): if a*a+b*b == c*c: print(a, b, c)
A:
Eachofa,b,ctakendifferentvalues,inallcombinations,soAisexecutedonn*n*n=n3combinationsintotalHowcanweimprovethat?
Ratherthangoingoverallvaluesofc,wecalculatecfroma,bandcheckifitisanintegerdef printPythagoreanTriples2(n): for a in range(1, n+1): for b in range(1, n+1): c2 = a*a+b*b c = binarySqrt(c2) if c <= n and c2 == c*c: print(a, b, c)Bothaandbtakendifferentvaluesinallcombinations,soAisexecutedonn*n=n2combinationsintotalCanweimprovefurther?
A:
Both(3,4,5)and(4,3,5)areprinted,whichisunnecessary.Wecanrestricta,b,csuchthat0<a≤b<c≤ndef printPythagoreanTriples(n): for a in range(1, n): for b in range(a, n): c2 = a*a+b*b c = binarySqrt(c2) if c <= n and c2 == c*c: print(a, b, c)Ifa=1,thenbtakesn-1values,ifa=2,thenn-2values,etc.Intotal(n-1)+(n-2)+…+1=n(n-1)/2=n2/2-n/2Comparedtothepreviousversion,Aisexecutedonlyhalfasoften
A:
Ifweknowhowmanystepsaprogramtakesdependingontheinput,wecanusethistopredicttheexecutiontimeThiscanbedonewithoutknowingdetailsoftheprocessorandcompilationtomachinelanguage!
log2nn
√n
nnlog2nn2n3
Modificationwithoutprintingforbettermeasurement:def countPythagoreanTriples1(n): k = 0 for a in range(1, n+1): for b in range(1, n+1): for c in range(1, n+1): if a*a+b*b == c*c: k = k+1 return kEachofa,b,ctakendifferentvalues,inallcombinations,soAisexecutedonn*n*n=n3combinationsintotalForn=200:2003executionsofA;forn=400:4003executions
(4003/2003)=(400/200)3=8Forn=400:8timeslonger,8tsec
A:
Modificationwithoutprintingforbettermeasurement:def countPythagoreanTriples2(n): k = 0 for a in range(1, n+1): for b in range(1, n+1): c2 = a*a+b*b c = binarySqrt(c2) if c <= n and c2 == c*c: k = k+1 return kBothaandbtakendifferentvaluesinallcombinations,soAisexecutedonn*n=n2combinationsintotalForn=200:2002executionsofA;forn=400:4002executionsForn=400:4timeslonger,4tsec,whenignoringbinarySqrt
A:
Modificationwithoutprintingforbettermeasurement:def countPythagoreanTriples(n): k = 0 for a in range(1, n): for b in range(a, n): c2 = a*a+b*b c = binarySqrt(c2) if c <= n and c2 == c*c: k = k+1 return kIfa=1,thenbtakesn-1values,ifa=2,thenn-2values,etc.Intotal(n-1)+(n-2)+…+1=n(n-1)/2=n2/2-n/2
A:
Forlargen,n/2isnegligible:((8002/2)/(4002/2))=4Forn=800:4timeslonger,4tsec,whenignoringbinarySqrt
1/2+1/2==1.01/3+1/3+1/3==1.01/4+1/4+1/4+1/4==1.01/5+1/5+1/5+1/5+1/5==1.01/6+1/6+1/6+1/6+1/6+1/6==1.01/7+1/7+1/7+1/7+1/7+1/7+1/7==1.01/8+1/8+1/8+1/8+1/8+1/8+1/8+1/8==1.01/9+1/9+1/9+1/9+1/9+1/9+1/9+1/9+1/9==1.01/10+1/10+1/10+1/10+1/10+1/10+1/10+1/10+1/10+1/10==1.01.0+2.0==3.00.1+0.2==0.3
Thefixedpointrepresentationofafractionalnumberconsistsofthesignificantdigitswithapointatafixedposition.Fordecimalandbinarywith2integerand2fractionaldigits:2*101+0*100+5*10-1+3*10-2 1*21+0*20+1*2-1+1*2-2
=2o+0+.5+.03 =2+0+.5+.25=20.53 =2.75
2 0. 5 3
101 100 10-1 10-2
1 0. 1 1
21 20 2-1 2-2
Howmanybinarydigitsareneededtorepresent0.1?
=1/16+1/32=3/32=.09375
=51/512=.099609375
=819/8192=.0999755859375
. 0 0 0 1 1
2-1 2-2 2-3 2-4 2-5
. 0 0 0 1 1 0 0 1 1
2-1 2-2 2-3 2-4 2-5 2-6 2-7 2-8 2-9
. 0 0 0 1 1 0 0 1 1 0 0 1 1
2-1 2-2 2-3 2-4 2-5 2-6 2-7 2-8 2-9 2-10 2-11 2-12 2-13
Infinitelymanybinarydigitsareneeded:aftertheinitialdigit0,thedigits0011keeprepeatingDependingonthebase,certainrationalnumberscannotbewrittenwithfinitelymanydigits,e.g.1/3indecimal,1/10inbinary
WIKIPEDIA
3/4=.11base2 è finitebinaryrepresentation1/3=.01010101…base2 è nofinitebinaryrepresentationFollowingtheIEEEstandard,Pythonuses52binarydigits,approximately16decimaldigits.Standardoutputgivesonlythefirst16decimaldigits,eveniftheconversionfrombinaryresultsinmoredigits.Onlyanapproximatevalueisprinted!>>> 1/3, 1/10>>> format(1/3, ".60f"), format(1/10, ".60f").60f:printfloatingpointnumberwith60digitsafter.
. ? ? ? ? ?
2-1 2-2 2-3 2-4 …
.5 .25 .125 .0625 …
Withafinitenumberofdigits,arithmeticoperationswillleadtoroundingerrors.Sometimetheerrorgetscancelled,sometimesnot>>> 1/3+1/3+1/3, 1/6+1/6+1/6+1/6+1/6+1/6>>> format(1/3+1/3+1/3, ".60f"), ...Asaconsequence,fractionalnumbersshouldneverbecomparedforequality:
a == bshouldbecome
abs(b-a) ≤ εHowever,εmustnotbetoosmall!
def x_intersect(f, a, b, eps): "f(a) ≤ 0 ≤ f(b), a ≤ b" while b-a > eps: m = (a+b)/2 if f(m) <= 0: a = m else: b = m return a, b
InPython,functionsaredata;theycanbepassedaroundasanyotherdata>>> x_intersect(f1, 0, 100, 1e-8)>>> x_intersect(f2, 0, 100, 1e-8)
>>> x_intersect(f1, 0, 100, 1e-15)>>> x_intersect(f1, 0, 100, 1e-16) # interrupt
def f1(x): return x*x-4
def f2(x): return x*x-2
>>> type(f1)
Afloatingpointnumberconsistsofafraction(mantissa)withthesignificantdigitsandanexponent.Forexample,fordecimalnumbers:
(1.963,3)=1.963*103=1963FollowingtheIEEEstandard,Pythonstoresthefractionwith52bitsinnormalizedform(leading1before.)andtheexponentwith11bits(withrange-1022to1023):
(1.f)*2e
Thelargestpositivenumberis(1.11…base2)*21023=1.7976931348623157*10308
Thesmallestpositivenumberis1.0*2-1022=2.2250738585072014*10-308
MostcomputersfollowtheIEEEstandard:floating-pointcomputationwillhavethesameresultsacrosscomputers.Severalformatsexist,with8bytesbeingwidelyused:Thenumberofbitsofthefractionlimitstheprecision.Thenumberofbitsintheexponentlimitstherange.Arithmeticoperationsonfloatmayleadtoalossofsignificantdigits:>>> 10000000000000000+1>>> 10000000000000000.0+1
52bitsfraction11bitsexponent1bitsign
+,-onfloatarethe"dangerous"operations!
def quadraticEquationSolution(a, b, c): d = math.sqrt(b*b-4*a*c) return (-b+d)/(2*a), (-b-d)/(2*a)
>>> quadraticEquationSolution(1, -3, -4)>>> quadraticEquationSolution(1, -2e8, 1)However,0.0isnotasolutionofx2-2e8*x+1=0:b*b-4*a*c=(-2e8)*(-2e8)-4*1*1=4e16-4=4e16Therefore,d=sqrt(4e16)=2e8and:(-b+d)/(2*a)=(-(-2e8)+2e8)/(2*1)=2e8(-b-d)/(2*a)=(-(-2e8)-2e8)/(2*1)=0Howcanweavoidsucherrors?
!
x1/2=−b± b2 −4ac
2a
lossofsignificantdigits
SolutionsofthequadraticequationarerelatedbyVieta'sformula:Giventhesolutionwithlargerabsolutevalue,thesmallercanbecomputedusingVieta,avoidingthelossofsignificantdigitsdef quadraticEquationSolutionPlus(a, b, c): d = math.sqrt(b*b-4*a*c) x1 = -(b+d)/(2*a) if b>=0 else (d-b)/(2*a) x2 = c/(x1*a) return x1, x2
quadraticEquationSolutionPlus(1, -2e8, 1)
x1/2=−b± b2 −4ac
2a
x1x2=ca
WIKIPEDIA
ArithmeticwiththePythondecimallibrarywillproducethesameerrorsascalculationsbyhand;bydefault,28fractionaldigitsarekept;theprecisioncanbechanged:>>> Decimal(1)/Decimal(3), Decimal(1)/Decimal(10)>>> Decimal('0.1')+Decimal('0.2')==Decimal('0.3')Howfastisdecimalarithmetic?def timeDecimalAddition(): from time import time start = time() for i in range(100000): x = Decimal(0) for j in range(10): x = x+Decimal(1)/Decimal(10) return time()-start
python.org
ThePythonlibraryfractionsstoresrationalnumbersa/bwithnumeratoraanddenominatorbasapair(a, b).Thismakescalculationswith+,-,*,/precise.>>> Fraction(1)/Fraction(3) == Fraction(1, 3)Conversionbetweenfloat,Decimal,Fractionrevealsdifferencesinrepresentation:>>> Decimal(0.1) >>> Fraction(0.1)
1. Avoidfloat,useintegerinstead:computewith¢rather$,mmratherthanm
2. Usedecimalorfractionsstandardlibraryinstead:slower,particularlyforverylarge/smallnumbers
3. Usealibraryforintervalarithmeticwithfloat:givessafelowerandupperbounds,takestwiceasmuchmemory/time
4. Useaproblem-specificlibrarywithorcheckliteratureforalgorithmswithknownnumericalproperties(e.g.solvingdifferentialequations)
5. Usesymboliccomputationasincomputeralgebrasystemsinsteadofaprogramminglanguage
6. Whenusingfloat,nevercompareforequality;checkplausibilityofresult