Binary Search

Applied mathematicians model the real-world with non-linear equations and are then confronted with the task of solving them. Here is a simplistic example:
Given a perfect cube that encloses 27m#tex2html_wrap_inline73624#. What area do its six walls cover?
We know from geometry that if the length of a cube's side is x, the enclosed space is #tex2html_wrap_inline73628#. Hence, we need to know the possible values of <#35588#>x<#35588#> such that

#displaymath73630#

Once we solved the equation, the covered area is #tex2html_wrap_inline73632#. In general, we are given a function <#35589#>f<#35589#> from numbers to numbers, and want to know some number r such that

#displaymath73636#

The value <#66589#><#35590#>r<#35590#><#66589#> is called the <#35591#>root<#35591#> of <#35592#>f<#35592#>. In our above example, #tex2html_wrap_inline73638#, and the value <#35593#>r<#35593#> is the length of the side of the cube. For the past few centuries, mathematicians have developed many methods for finding the root of different types of functions. In this section, we study a solution that is based on the <#35595#>Mean Value Theorem<#35595#>, an early result of mathematical analysis. The resulting algorithm is a primary example of generative recursion based on a deep mathematical theorem. It has been adapted to other uses and has become known as the ``binary search algorithm'' in computer science.


#displaymath73622#

<#66590#>Figure: A numeric function <#35597#>f<#35597#> with root in interval [a,b] (stage~1)<#66590#>


The Mean Value Theorem says that a continuous function f has a root in an interval [a,b] if the signs of f(a) and f(b) differ. By <#35599#>continuous<#35599#> we mean a function that doesn't ``jump'', that doesn't have gaps, and that always continues in a ``smooth'' fashion. The theorem is best illustrated with the graph of a function. The function f in figure~#figroot#35600> is below the x-axis at a and above the x-axis at b. It is a continuous function, which we can tell from the uninterrupted, smooth line. And indeed, the function intersects the x-axis somewhere between a and b. Now take a look at the midpoint between a and b:

#displaymath73674#

It partitions the interval [a,b] into two smaller, equally large intervals. We can now compute the value of f at m and see whether it is below or above 0. Here f(m) ;SPMgt; 0, so according to the Mean Value Theorem, the root is in the right interval: [m,b]. Our picture confirms this because the root is in the right half of the interval, labeled ``range 2'' in figure~#figroot#35602>. The abstract description of the Mean Value Theorem and the illustrative example describe a process for finding a root. Specifically, we use the halving step as many times as necessary to determine a tolerably small range in which f must have a root. Let us now translate this description into a Scheme algorithm, which we call <#66591#><#35603#>find-root<#35603#><#66591#>. To begin with, we must agree on the exact task of <#66592#><#35604#>find-root<#35604#><#66592#>. It consumes a function, let's call it <#66593#><#35605#>f<#35605#><#66593#>, for which we need to find a root. In addition, it must consume the boundaries of the interval in which we expect to find a root. For simplicity, let's say that <#66594#><#35606#>find-root<#35606#><#66594#> consumes two numbers: <#66595#><#35607#>left<#35607#><#66595#> and <#66596#><#35608#>right<#35608#><#66596#>. But these parameters can't just be any two numbers. For our algorithm to work we must assume that

<#35613#>(or<#35613#> <#35614#>(;SPMlt;=<#35614#> <#35615#>(f<#35615#> <#35616#>left)<#35616#> <#35617#>0<#35617#> <#35618#>(f<#35618#> <#35619#>right))<#35619#>
    <#35620#>(;SPMlt;=<#35620#> <#35621#>(f<#35621#> <#35622#>right)<#35622#> <#35623#>0<#35623#> <#35624#>(f<#35624#> <#35625#>left)))<#35625#> 
holds. This assumption expresses in Scheme the condition of the Mean Value Theorem that the function must have different signs for <#66597#><#35629#>left<#35629#><#66597#> and <#66598#><#35630#>right<#35630#><#66598#>. According to the informal process description, the task of <#66599#><#35631#>find-root<#35631#><#66599#> is to find an interval that contains a root and that is tolerably small. The size of the given interval is <#66600#><#35632#>(-<#35632#>\ <#35633#>right<#35633#><#35634#> <#35634#><#35635#>left)<#35635#><#66600#>. For the moment, we assume that the tolerance is defined as a top-level variable <#66601#><#35636#>TOLERANCE<#35636#><#66601#>. Given that, <#66602#><#35637#>find-root<#35637#><#66602#> can produce one of the two boundaries of the interval because we know what its size is; let's pick the left one. Here is a translation of our discussion into a contract, a purpose statement, and a header, including the assumption on the parameters:
<#71506#>;; <#66603#><#35642#>find-root<#35642#> <#35643#>:<#35643#> <#35644#>(number<#35644#> <#35645#><#35645#><#35646#>-;SPMgt;<#35646#><#35647#><#35647#> <#35648#>number)<#35648#> <#35649#>number<#35649#> <#35650#>number<#35650#> <#35651#><#35651#><#35652#>-;SPMgt;<#35652#><#35653#><#35653#> <#35654#>number<#35654#><#66603#><#71506#>
<#71507#>;; to determine <#66604#><#35655#>R<#35655#><#66604#> such that <#66605#><#35656#>f<#35656#><#66605#> has a root in [<#66606#><#35657#>R<#35657#><#66606#>,<#66607#><#35658#>(+<#35658#> <#35659#>R<#35659#> <#35660#>TOLERANCE)<#35660#><#66607#>]<#71507#> 
<#35661#>;; <#35661#> 
<#71508#>;; <#35662#>ASSUMPTION<#35662#>: <#66608#><#35663#>(or<#35663#> <#35664#>(;SPMlt;=<#35664#> <#35665#>(f<#35665#> <#35666#>left)<#35666#> <#35667#>0<#35667#> <#35668#>(f<#35668#> <#35669#>right))<#35669#> <#35670#>(;SPMlt;=<#35670#> <#35671#>(f<#35671#> <#35672#>right)<#35672#> <#35673#>0<#35673#> <#35674#>(f<#35674#> <#35675#>left)))<#35675#><#66608#><#71508#> 
<#35676#>(define<#35676#> <#35677#>(find-root<#35677#> <#35678#>f<#35678#> <#35679#>left<#35679#> <#35680#>right)<#35680#> <#35681#>...)<#35681#> 
At this stage, we should develop an example of how the function works. We have already seen one; the following exercise develops a second one.
<#35687#>Exercise 27.3.1<#35687#> Consider the following function definition:
<#71509#>;; <#66609#><#35693#>poly<#35693#> <#35694#>:<#35694#> <#35695#>number<#35695#> <#35696#><#35696#><#35697#>-;SPMgt;<#35697#><#35698#><#35698#> <#35699#>number<#35699#><#66609#><#71509#>
<#35700#>(<#35700#><#35701#>define<#35701#> <#35702#>(poly<#35702#> <#35703#>x)<#35703#> 
 <#35704#>(*<#35704#> <#35705#>(-<#35705#> <#35706#>x<#35706#> <#35707#>2)<#35707#> <#35708#>(-<#35708#> <#35709#>x<#35709#> <#35710#>4)))<#35710#> 
It defines a binomial for which we can determine its roots by hand---they are <#66610#><#35714#>2<#35714#><#66610#> and <#66611#><#35715#>4<#35715#><#66611#>. But it is also a non-trivial input for <#66612#><#35716#>find-root<#35716#><#66612#>, so that it makes sense to use it as an example. Mimic the root-finding process based on the Mean Value Theorem for <#66613#><#35717#>poly<#35717#><#66613#>, starting with the interval <#66614#><#35718#>3<#35718#><#66614#> and <#66615#><#35719#>6<#35719#><#66615#>. Tabulate the information as follows:

#tabular35721#

Find an interval of size .5 (or less) in which <#66616#><#35732#>poly<#35732#><#66616#> contains a root.~ external Solution<#66617#><#66617#>
Next we turn our attention to the definition of <#66618#><#35740#>find-root<#35740#><#66618#>. We start from <#66619#><#35741#>generative-recursive-fun<#35741#><#66619#> and ask the four relevant questions:

  1. We need a condition that describes when the problem is solved and a matching answer. This is straightforward. The problem is solved if the distance from <#66620#><#35743#>left<#35743#><#66620#> to <#66621#><#35744#>right<#35744#><#66621#> is smaller than or equal to <#66622#><#35745#>TOLERANCE<#35745#><#66622#>:
    <#35750#>(;SPMlt;=<#35750#> <#35751#>(-<#35751#> <#35752#>right<#35752#> <#35753#>left)<#35753#> <#35754#>TOLERANCE)<#35754#>
    
    The matching result is <#66623#><#35758#>left<#35758#><#66623#>.
  2. We must formulate an expression that generates new problems for <#66624#><#35759#>find-root<#35759#><#66624#>. According to our informal process description, this step requires determining the mid-point and choosing the next interval. The midpoint is used several times, so we use a <#66625#><#35760#>local<#35760#>-expression<#66625#> to introduce it:
    <#35765#>(local<#35765#> <#35766#>((define<#35766#> <#35767#>mid<#35767#> <#35768#>(/<#35768#> <#35769#>(+<#35769#> <#35770#>left<#35770#> <#35771#>right)<#35771#> <#35772#>2)))<#35772#> <#35773#>...)<#35773#>
    
    Choosing an interval is more complicated than that. Consider the Mean Value Theorem again. It says that a given interval is an interesting candidate if the function values at the boundaries have different signs. For the function's purpose statement, we expressed this constraint using
    <#35781#>(or<#35781#> <#35782#>(;SPMlt;=<#35782#> <#35783#>(f<#35783#> <#35784#>left)<#35784#> <#35785#>0<#35785#> <#35786#>(f<#35786#> <#35787#>right))<#35787#> <#35788#>(;SPMlt;=<#35788#> <#35789#>(f<#35789#> <#35790#>right)<#35790#> <#35791#>0<#35791#> <#35792#>(f<#35792#> <#35793#>left)))<#35793#>
    
    Accordingly, the interval between <#66626#><#35797#>left<#35797#><#66626#> and <#66627#><#35798#>mid<#35798#><#66627#> is the next candidate if
    <#35803#>(or<#35803#> <#35804#>(;SPMlt;=<#35804#> <#35805#>(f<#35805#> <#35806#>left)<#35806#> <#35807#>0<#35807#> <#35808#>(f<#35808#> <#35809#>mid))<#35809#> <#35810#>(;SPMlt;=<#35810#> <#35811#>(f<#35811#> <#35812#>mid)<#35812#> <#35813#>0<#35813#> <#35814#>(f<#35814#> <#35815#>left)))<#35815#>
    
    And, the interval between <#66628#><#35819#>mid<#35819#><#66628#> and <#66629#><#35820#>right<#35820#><#66629#> is it, if
    <#35825#>(or<#35825#> <#35826#>(;SPMlt;=<#35826#> <#35827#>(f<#35827#> <#35828#>mid)<#35828#> <#35829#>0<#35829#> <#35830#>(f<#35830#> <#35831#>right))<#35831#> <#35832#>(;SPMlt;=<#35832#> <#35833#>(f<#35833#> <#35834#>right)<#35834#> <#35835#>0<#35835#> <#35836#>(f<#35836#> <#35837#>mid)))<#35837#>
    
    In short, the body of the <#66630#><#35841#>local<#35841#>-expression<#66630#> must be a conditional:
    <#35846#>(l<#35846#><#35847#>ocal<#35847#> <#35848#>((define<#35848#> <#35849#>mid<#35849#> <#35850#>(/<#35850#> <#35851#>(+<#35851#> <#35852#>left<#35852#> <#35853#>right)<#35853#> <#35854#>2)))<#35854#>
      <#35855#>(c<#35855#><#35856#>ond<#35856#> 
        <#35857#>[<#35857#><#35858#>(or<#35858#> <#35859#>(;SPMlt;=<#35859#> <#35860#>(f<#35860#> <#35861#>left)<#35861#> <#35862#>0<#35862#> <#35863#>(f<#35863#> <#35864#>mid))<#35864#> <#35865#>(;SPMlt;=<#35865#> <#35866#>(f<#35866#> <#35867#>mid)<#35867#> <#35868#>0<#35868#> <#35869#>(f<#35869#> <#35870#>left)))<#35870#> 
         <#35871#>(find-root<#35871#> <#35872#>left<#35872#> <#35873#>mid)]<#35873#> 
        <#35874#>[<#35874#><#35875#>(or<#35875#> <#35876#>(;SPMlt;=<#35876#> <#35877#>(f<#35877#> <#35878#>mid)<#35878#> <#35879#>0<#35879#> <#35880#>(f<#35880#> <#35881#>right))<#35881#> <#35882#>(;SPMlt;=<#35882#> <#35883#>(f<#35883#> <#35884#>right)<#35884#> <#35885#>0<#35885#> <#35886#>(f<#35886#> <#35887#>mid)))<#35887#> 
         <#35888#>(find-root<#35888#> <#35889#>mid<#35889#> <#35890#>right)]<#35890#><#35891#>))<#35891#> 
    
    In both clauses, we use <#66631#><#35895#>find-root<#35895#><#66631#> to continue the search.
The completed function is displayed in figure~#figrootoff#35897>. The following exercises suggest some tests and a termination argument.
<#71510#>;; <#66632#><#35902#>find-root<#35902#> <#35903#>:<#35903#> <#35904#>(number<#35904#> <#35905#><#35905#><#35906#>-;SPMgt;<#35906#><#35907#><#35907#> <#35908#>number)<#35908#> <#35909#>number<#35909#> <#35910#>number<#35910#> <#35911#><#35911#><#35912#>-;SPMgt;<#35912#><#35913#><#35913#> <#35914#>number<#35914#><#66632#><#71510#>
<#71511#>;; to determine a number R such that <#66633#><#35915#>f<#35915#><#66633#> has a <#71511#> 
<#71512#>;; root between R and <#66634#><#35916#>(+<#35916#> <#35917#>R<#35917#> <#35918#>TOLERANCE)<#35918#><#66634#> <#71512#> 
<#35919#>;; <#35919#> 
<#66635#>;; <#35920#>ASSUMPTION<#35920#>: <#35921#>f<#35921#> is continuous and monotonic<#66635#> 
<#35922#>(d<#35922#><#35923#>efine<#35923#> <#35924#>(find-root<#35924#> <#35925#>f<#35925#> <#35926#>left<#35926#> <#35927#>right)<#35927#> 
  <#35928#>(c<#35928#><#35929#>ond<#35929#> 
    <#35930#>[<#35930#><#35931#>(;SPMlt;=<#35931#> <#35932#>(-<#35932#> <#35933#>right<#35933#> <#35934#>left)<#35934#> <#35935#>TOLERANCE)<#35935#> <#35936#>left]<#35936#> 
    <#35937#>[<#35937#><#35938#>e<#35938#><#35939#>lse<#35939#> 
      <#35940#>(l<#35940#><#35941#>ocal<#35941#> <#35942#>((define<#35942#> <#35943#>mid<#35943#> <#35944#>(/<#35944#> <#35945#>(+<#35945#> <#35946#>left<#35946#> <#35947#>right)<#35947#> <#35948#>2)))<#35948#> 
        <#35949#>(c<#35949#><#35950#>ond<#35950#> 
          <#35951#>[<#35951#><#35952#>(;SPMlt;=<#35952#> <#35953#>(f<#35953#> <#35954#>mid)<#35954#> <#35955#>0<#35955#> <#35956#>(f<#35956#> <#35957#>right))<#35957#> 
           <#35958#>(find-root<#35958#> <#35959#>mid<#35959#> <#35960#>right)]<#35960#> 
          <#35961#>[<#35961#><#35962#>else<#35962#> 
           <#35963#>(find-root<#35963#> <#35964#>left<#35964#> <#35965#>mid)]<#35965#><#35966#>))]<#35966#><#35967#>))<#35967#> 
<#66636#>Figure: The root-finding algorithm <#35971#>find-root<#35971#><#66636#>

<#35975#>Exercise 27.3.2<#35975#> Use <#66637#><#35977#>poly<#35977#><#66637#> from #exfindrootexample#35978> to test <#66638#><#35979#>find-root<#35979#><#66638#>. Experiment with different values for <#66639#><#35980#>TOLERANCE<#35980#><#66639#>. Use the strategy of section~#secequaltest#35981> to formulate the tests as boolean-valued expressions.~ external Solution<#66640#><#66640#> <#35987#>Exercise 27.3.3<#35987#> Suppose the original arguments of <#66641#><#35989#>find-root<#35989#><#66641#> describe an interval of size <#66642#><#35990#>S1<#35990#><#66642#>. How large is the distance between <#66643#><#35991#>left<#35991#><#66643#> and <#66644#><#35992#>right<#35992#><#66644#> for the first recursive call to <#66645#><#35993#>find-root<#35993#><#66645#>? The second one? And the third? After how many evaluation steps is the distance between <#66646#><#35994#>left<#35994#><#66646#> and <#66647#><#35995#>right<#35995#><#66647#> smaller than or equal to <#66648#><#35996#>TOLERANCE<#35996#><#66648#>? How does the answer to this question show that <#66649#><#35997#>find-root<#35997#><#66649#> produces an answer for all inputs that satisfy the assumption?~ external Solution<#66650#><#66650#> <#36003#>Exercise 27.3.4<#36003#> For every mid-point <#66651#><#36005#>m<#36005#><#66651#>, except for the last one, the function <#66652#><#36006#>find-root<#36006#><#66652#> needs to determine the value of <#66653#><#36007#>(f<#36007#>\ <#36008#>m)<#36008#><#66653#> twice. Validate this claim for one example with a hand-evaluation. Since the evaluation of <#66654#><#36009#>(f<#36009#>\ <#36010#>m)<#36010#><#66654#> may be time-consuming, programmers often implement a variant of <#66655#><#36011#>find-root<#36011#><#66655#> that avoids this recomputation. Modify <#66656#><#36012#>find-root<#36012#><#66656#> in figure~#figrootoff#36013> so that it does not need to re-compute the value of <#66657#><#36014#>(f<#36014#>\ <#36015#>mid)<#36015#><#66657#>. <#36016#>Hint:<#36016#> Define a help function <#66658#><#36017#>find-root-aux<#36017#><#66658#> that takes two extra arguments: the values <#66659#><#36018#>(f<#36018#>\ <#36019#>left)<#36019#><#66659#> and <#66660#><#36020#>(f<#36020#><#36021#> <#36021#><#36022#>right)<#36022#><#66660#>.~ external Solution<#66661#><#66661#> <#36028#>Exercise 27.3.5<#36028#> A <#36030#>table<#36030#> is a function that consumes natural numbers between <#66662#><#36031#>0<#36031#><#66662#> and <#66663#><#36032#>VL<#36032#><#66663#> (exclusive) and produces numbers:
<#71513#>;; <#66664#><#36037#>g<#36037#> <#36038#>:<#36038#> <#36039#>N<#36039#> <#36040#><#36040#><#36041#>-;SPMgt;<#36041#><#36042#><#36042#> <#36043#>num<#36043#><#66664#><#71513#>
<#71514#>;; <#36044#>ASSUMPTION<#36044#>: <#66665#><#36045#>i<#36045#><#66665#> is between 0 and <#66666#><#36046#>VL<#36046#><#66666#><#71514#> 
<#36047#>(d<#36047#><#36048#>efine<#36048#> <#36049#>(g<#36049#> <#36050#>i)<#36050#> 
  <#36051#>(c<#36051#><#36052#>ond<#36052#> 
    <#36053#>[<#36053#><#36054#>(=<#36054#> <#36055#>i<#36055#> <#36056#>0)<#36056#> <#36057#>-10]<#36057#> 
    <#36058#>[<#36058#><#36059#>(=<#36059#> <#36060#>i<#36060#> <#36061#>1)<#36061#> <#36062#>...]<#36062#> 
    <#36063#>...<#36063#> 
    <#36064#>[<#36064#><#36065#>(=<#36065#> <#36066#>i<#36066#> <#36067#>(-<#36067#> <#36068#>VL<#36068#> <#36069#>1))<#36069#> <#36070#>...]<#36070#> 
    <#36071#>[<#36071#><#36072#>else<#36072#> <#36073#>(error<#36073#> <#36074#>'<#36074#><#36075#>g<#36075#> <#36076#>``is<#36076#> <#36077#>defined<#36077#> <#36078#>only<#36078#> <#36079#>between<#36079#> <#36080#>0<#36080#> <#36081#>and<#36081#> <#36082#>VL<#36082#> <#36083#>(exclusive)'')]<#36083#><#36084#>))<#36084#> 
The number <#66667#><#36088#>VL<#36088#><#66667#> is called the <#36089#>table's length<#36089#>. The <#36090#>root of a table<#36090#> is the number in the table that is closest to <#66668#><#36091#>0<#36091#><#66668#>. Even if we can't read the definition of a table, we can find its root with a search function. Develop the function <#66669#><#36092#>find-root-linear<#36092#><#66669#>, which consumes a table, the table's length, and finds the root of the table. Use structural induction on natural numbers. This kind of root-finding process is often called a <#36093#>linear search<#36093#>. A table <#66670#><#36094#>t<#36094#><#66670#> is sorted in ascending order if <#66671#><#36095#>(t<#36095#>\ <#36096#>0)<#36096#><#66671#> is less then <#66672#><#36097#>(t<#36097#>\ <#36098#>1)<#36098#><#66672#>, <#66673#><#36099#>(t<#36099#>\ <#36100#>1)<#36100#><#66673#> is less than <#66674#><#36101#>(t<#36101#>\ <#36102#>2)<#36102#><#66674#>, and so on. If a table is monotonic, we can determine the root using binary search. Specifically, we can use binary search to find an interval of size <#66675#><#36103#>1<#36103#><#66675#> such that either the left or the right boundary is the root's index. Develop <#66676#><#36104#>find-root-discrete<#36104#><#66676#>, which consumes a table and its length, and finds the table's root. <#36105#>Hints:<#36105#> (1) The interval boundary arguments for <#66677#><#36106#>find-root-discrete<#36106#><#66677#> must always be natural numbers. Consider how this affects the mid-point computation. (2) Also contemplate how the first hint affects the discovery of trivially solvable problem instances. (3) Does the termination argument from exercise~#exfindroottermination#36107> apply? If the tabulating function is defined on all natural numbers between <#66678#><#36108#>0<#36108#><#66678#> and <#66679#><#36109#>1024<#36109#><#66679#>, and if its root is at <#66680#><#36110#>0<#36110#><#66680#>, how many recursive applications are needed with <#66681#><#36111#>find-root-discrete<#36111#><#66681#> and <#66682#><#36112#>find-root-lin<#36112#><#66682#> to determine a root interval?~ external Solution<#66683#><#66683#> <#36118#>Exercise 27.3.6<#36118#> As mentioned in section~#secintegrate1#36120>, mathematicians are not only interested in the roots of functions, but also in the area that a function encloses between two points. Mathematically put, we are interested in <#36121#>integrating<#36121#> functions over some interval. Take another look at the following graph: \ \ \ <#66684#> external <#66684#>
Here the area of interest is that enclosed by the bold vertical lines at a and b, the <#36123#>x<#36123#>-axis, and the graph of the function. In section~#secintegrate1#36124>, we learned to approximate the area by computing and adding up the area of rectangles like the two above. Using the divide-and-conquer strategy, we can also design a function that computes the area based on generative recursion. Roughly speaking, we split the interval into two pieces, compute the area of each piece, and add the two areas together.

<#36125#>Step 1<#36125#>: Develop the algorithm <#66685#><#36126#>integrate-dc<#36126#><#66685#>, which integrates a function <#66686#><#36127#>f<#36127#><#66686#> between the boundaries <#66687#><#36128#>left<#36128#><#66687#> and <#66688#><#36129#>right<#36129#><#66688#> via the divide-and-conquer strategy employed in <#66689#><#36130#>find-root<#36130#><#66689#>. Use rectangle approximations when an interval has become small enough. Although the area of a rectangle is easy to compute, a rectangle is often a bad approximation of the area under a function graph. A better geometric shape is the trapezoid limited by a, <#66690#><#36131#>(f<#36131#>\ <#36132#>a)<#36132#><#66690#>, b, and <#66691#><#36133#>(f<#36133#>\ <#36134#>b)<#36134#><#66691#>. Its area is:

#displaymath73708#

<#36140#>Step 2<#36140#>: Modify <#66693#><#36141#>integrate-dc<#36141#><#66693#> so that it uses trapezoids instead of rectangles. The plain divide-and-conquer approach is wasteful. Consider a function graph is level in one part and rapidly changes in another. For the level part it is pointless to keep splitting the interval. We could just compute the trapezoid over a and b instead of the two halves. To discover when <#36142#>f<#36142#> is level, we can change the algorithm as follows. Instead of just testing how large the interval is, the new algorithm computes the area of three trapezoids: the given one, and the two halves. Suppose the difference between the two is less than

#displaymath73714#

This area represents a small rectangle, of height <#66694#><#36146#>TOLERANCE<#36146#><#66694#>, and represents the error margin of our computation. In other words, the algorithm determines whether <#36147#>f<#36147#> changes enough to affect the error margin, and if not, it stops. Otherwise, it continues with the divide-and-conquer approach.

<#36148#>Step 3<#36148#>: Develop <#66695#><#36149#>integrate-adaptive<#36149#><#66695#>, which integrates a function <#36150#>f<#36150#> between <#36151#>left<#36151#> and <#36152#>right<#36152#> according to the suggested method. Do not discuss the termination of <#66696#><#36153#>integrate-adaptive<#36153#><#66696#>. <#36154#>Note<#36154#>: The algorithm is called ``adaptive integration'' because it automatically adapts its strategy. For those parts of <#36155#>f<#36155#> that are level, it performs just a few calculations; for the other parts, it inspects very small intervals so that the error margin is also decreased accordingly.~ external Solution<#66697#><#66697#>