Shop OBEX P1 Docs P2 Docs Learn Events
Binary search on a lookup table for — Parallax Forums

Binary search on a lookup table for

ArchiverArchiver Posts: 46,084
edited 2003-06-29 08:07 in General Discussion
I've posted a question about this previously, but I've changed my program a
bit and now have a new question.

This is on a BS2. I have a lookup table of 199 words, sorted in ascending
order. I have a value that I want to look up in this table. However, this
value may not have an exact match in the table - I want to find the nearest
match, and if there are two adjacent entries that the value is right
between, I don't care which entry is returned. Now, I want the index of the
result, not the value at the location.

Right now, I use a very simple sequential search, which computes a
difference between my value and the table entry. I then keep going through
the table until the difference stops decreasing and starts increasing, then
abort the search.

Binary search would be better, but it's implementation is done with a
recursive function - impossible in the stamp. Does anyone have a pointer to
an implementation that is non-recursive, or to an algorithm that will suit
my needs and is easily implemented on the BS2?

Thanks,
Steve

Comments

  • ArchiverArchiver Posts: 46,084
    edited 2003-06-26 18:51
    Hi Steve,

    I do have binary search code, but I'll have to pull it out of a
    program that was meant for a different purpose. It is Pbasically the
    same algorithm that you find in a successive approximation ADC,
    simple and fast.

    -- Tracy



    >I've posted a question about this previously, but I've changed my program a
    >bit and now have a new question.
    >
    >This is on a BS2. I have a lookup table of 199 words, sorted in ascending
    >order. I have a value that I want to look up in this table. However, this
    >value may not have an exact match in the table - I want to find the nearest
    >match, and if there are two adjacent entries that the value is right
    >between, I don't care which entry is returned. Now, I want the index of the
    >result, not the value at the location.
    >
    >Right now, I use a very simple sequential search, which computes a
    >difference between my value and the table entry. I then keep going through
    >the table until the difference stops decreasing and starts increasing, then
    >abort the search.
    >
    >Binary search would be better, but it's implementation is done with a
    >recursive function - impossible in the stamp. Does anyone have a pointer to
    >an implementation that is non-recursive, or to an algorithm that will suit
    >my needs and is easily implemented on the BS2?
    >
    >Thanks,
    >Steve
  • ArchiverArchiver Posts: 46,084
    edited 2003-06-27 08:52
    Here's a demo program for binary search. It is like the lookdown
    operator, except that it searches a table of increasing numbers (word
    values) in DATA eeprom. You enter a number at the keyboard, and the
    program finds the numbers closest above and below it in the table.
    This kind of thing is good for interpolation problems or search for
    free memory. The binary algorithm finds the answer in N steps, given
    a table with 2^N entries. E.g., a table with 1024 entries is resolved
    in 10 steps. Algorithm is like a successive approximation ADC. Uses
    a bunch of math tricks in place of IF-THEN or CASE statements.

    '{$STAMP BS2}
    '{$PBASIC 2.5}
    ' (c) 2001 Tracy Allen, http://www.emesystems.com
    ' like lookdown operator, except data in eeprom word table
    ' word values increasing in table.
    ' User enters a number. The routine finds the closest two values
    ' in the table such that wx < number < wy
    ' and the index pointer to the position of wx in the table
    ' Uses binary search algorithm for fast acquisition.
    ' Finds value in a 2^N table in N steps.
    ' number < smallest value in table returns smallest value
    ' number > largest value in table returns largest value

    value VAR Word ' number entered by user
    wx VAR Word ' comparison value from table
    wy VAR Word ' binary increment (word for large table)
    wz VAR Word ' index into table (word for large table)
    sign VAR Bit ' selects up or down for next step in table

    tablesize CON 22 ' just for example, 22 entries in DATA table
    tablesize1 CON tablesize-1

    table DATA Word 2,Word 5,Word 30,Word 35, Word 57, Word 77, Word 99
    DATA Word 110, Word 125, Word 278
    DATA Word 678, Word 777, Word 888, Word 999
    DATA Word 1010, Word 1111, Word 2000, Word 3333
    DATA Word 4000, Word 5555, Word 6000, Word 7777

    DO
    DEBUG CR,CR,"enter a number: "
    DEBUGIN DEC5 value ' get user to input a number

    index_check0:
    wy=DCD NCD tablesize / 2 ' note A
    wz=wy-1 ' first address to check, halfway point in the table

    index_check1:
    READ wz MAX tablesize1 * 2 + table, Word wx ' note B
    IF wx=value THEN index_check8 ' note C
    sign=wx/(value MIN 1) MAX 1 ' note D
    wy=wy/2 ' note E
    wz=-sign^wy+sign+wz ' note F
    PAUSE 2
    ' DEBUG CR,DEC wz,TAB, DEC wy,TAB, DEC wx ,TAB,IBIN sign ' show
    inner workings
    IF wy THEN index_check1 ' note G
    index_check8: ' note H
    IF value>=wx THEN
    READ wz+1 MAX tablesize1 * 2,Word wy
    ELSE
    wy=wx
    READ wz MIN 1 -1 * 2,Word wx
    ENDIf
    DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    LOOP

    ' note A: could use a constant here if tablesize is a constant
    ' =largest power of two less than tablesize
    ' tablesize does not have to be a power of two.
    ' note B: limit read to last table address, *2 because 2 bytes per word
    ' note C: speed up process if exact match is found
    ' note D: "sign" is 1 iff value<wx, that is, if value fits into a lower
    ' position in the table. "value min 1" avoids divide by zero.
    ' note E: wy is successively lower powers of two
    ' note F: add (sign=0) or subtract (sign=1) wy from wz
    ' -sign^wy+sign forms the conditional 2s complement of wy
    ' note G: continue until wy is reduced to zero
    ' note H: The IF-THEN-ELSE resolves wx<= value < wy
    ' wz is the index of wx
    ' note I: show index and table values below and above user value entered
  • ArchiverArchiver Posts: 46,084
    edited 2003-06-27 16:57
    Thanks Tracy!

    I'm going to try to incorporate this into my stamp this evening.

    Steve

    Original Message
    From: "Tracy Allen" <tracy@e...>
    To: <basicstamps@yahoogroups.com>
    Sent: Friday, June 27, 2003 9:52 AM
    Subject: Re: [noparse][[/noparse]basicstamps] Binary search on a lookup table for "closest
    value"


    > Here's a demo program for binary search. It is like the lookdown
    > operator, except that it searches a table of increasing numbers (word
    > values) in DATA eeprom. You enter a number at the keyboard, and the
    > program finds the numbers closest above and below it in the table.
    > This kind of thing is good for interpolation problems or search for
    > free memory. The binary algorithm finds the answer in N steps, given
    > a table with 2^N entries. E.g., a table with 1024 entries is resolved
    > in 10 steps. Algorithm is like a successive approximation ADC. Uses
    > a bunch of math tricks in place of IF-THEN or CASE statements.
    >
    > '{$STAMP BS2}
    > '{$PBASIC 2.5}
    > ' (c) 2001 Tracy Allen, http://www.emesystems.com
    > ' like lookdown operator, except data in eeprom word table
    > ' word values increasing in table.
    > ' User enters a number. The routine finds the closest two values
    > ' in the table such that wx < number < wy
    > ' and the index pointer to the position of wx in the table
    > ' Uses binary search algorithm for fast acquisition.
    > ' Finds value in a 2^N table in N steps.
    > ' number < smallest value in table returns smallest value
    > ' number > largest value in table returns largest value
    >
    > value VAR Word ' number entered by user
    > wx VAR Word ' comparison value from table
    > wy VAR Word ' binary increment (word for large table)
    > wz VAR Word ' index into table (word for large table)
    > sign VAR Bit ' selects up or down for next step in table
    >
    > tablesize CON 22 ' just for example, 22 entries in DATA table
    > tablesize1 CON tablesize-1
    >
    > table DATA Word 2,Word 5,Word 30,Word 35, Word 57, Word 77, Word 99
    > DATA Word 110, Word 125, Word 278
    > DATA Word 678, Word 777, Word 888, Word 999
    > DATA Word 1010, Word 1111, Word 2000, Word 3333
    > DATA Word 4000, Word 5555, Word 6000, Word 7777
    >
    > DO
    > DEBUG CR,CR,"enter a number: "
    > DEBUGIN DEC5 value ' get user to input a number
    >
    > index_check0:
    > wy=DCD NCD tablesize / 2 ' note A
    > wz=wy-1 ' first address to check, halfway point in the
    table
    >
    > index_check1:
    > READ wz MAX tablesize1 * 2 + table, Word wx ' note B
    > IF wx=value THEN index_check8 ' note C
    > sign=wx/(value MIN 1) MAX 1 ' note D
    > wy=wy/2 ' note E
    > wz=-sign^wy+sign+wz ' note F
    > PAUSE 2
    > ' DEBUG CR,DEC wz,TAB, DEC wy,TAB, DEC wx ,TAB,IBIN sign ' show
    > inner workings
    > IF wy THEN index_check1 ' note G
    > index_check8: ' note H
    > IF value>=wx THEN
    > READ wz+1 MAX tablesize1 * 2,Word wy
    > ELSE
    > wy=wx
    > READ wz MIN 1 -1 * 2,Word wx
    > ENDIf
    > DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    > LOOP
    >
    > ' note A: could use a constant here if tablesize is a constant
    > ' =largest power of two less than tablesize
    > ' tablesize does not have to be a power of two.
    > ' note B: limit read to last table address, *2 because 2 bytes per word
    > ' note C: speed up process if exact match is found
    > ' note D: "sign" is 1 iff value<wx, that is, if value fits into a lower
    > ' position in the table. "value min 1" avoids divide by zero.
    > ' note E: wy is successively lower powers of two
    > ' note F: add (sign=0) or subtract (sign=1) wy from wz
    > ' -sign^wy+sign forms the conditional 2s complement of wy
    > ' note G: continue until wy is reduced to zero
    > ' note H: The IF-THEN-ELSE resolves wx<= value < wy
    > ' wz is the index of wx
    > ' note I: show index and table values below and above user value entered
    >
    >
    >
    >
    > To UNSUBSCRIBE, just send mail to:
    > basicstamps-unsubscribe@yahoogroups.com
    > from the same email address that you subscribed. Text in the Subject and
    Body of the message will be ignored.
    >
    >
    > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
    >
  • ArchiverArchiver Posts: 46,084
    edited 2003-06-27 20:38
    Tracy,

    I've started to implement this in my program, and it does work VERY fast
    compared to my initial sequential search.

    However, I noticed that "wz" changes in multiples of two. Let me explain:

    I noticed that your program will work standalone. Upon initial inspection, I
    thought that "wz" would always point to the upper or lower two of the
    indexes found, but it does not. For example, the inputs 56, 57, and 76
    always set wz at the end of the search to "4", even though the wx and wy
    variable are updated to relfect the upper and lower "closest matches".

    I then incorperated this into my program with this assumption. I then read
    the values at that index, and that index minus 1, check which one is
    actually closest, then return that index. However, with the behaviour I
    talked about above, this doesn't work properly. Can you offer a suggestion
    to correct this?

    This will not be a production product, but if I do use your code in the
    future with your permission, I will definately give you credit!

    Thanks,
    Steve Ziuchkovski

    Original Message
    From: "Tracy Allen" <tracy@e...>
    To: <basicstamps@yahoogroups.com>
    Sent: Friday, June 27, 2003 9:52 AM
    Subject: Re: [noparse][[/noparse]basicstamps] Binary search on a lookup table for "closest
    value"


    > Here's a demo program for binary search. It is like the lookdown
    > operator, except that it searches a table of increasing numbers (word
    > values) in DATA eeprom. You enter a number at the keyboard, and the
    > program finds the numbers closest above and below it in the table.
    > This kind of thing is good for interpolation problems or search for
    > free memory. The binary algorithm finds the answer in N steps, given
    > a table with 2^N entries. E.g., a table with 1024 entries is resolved
    > in 10 steps. Algorithm is like a successive approximation ADC. Uses
    > a bunch of math tricks in place of IF-THEN or CASE statements.
    >
    > '{$STAMP BS2}
    > '{$PBASIC 2.5}
    > ' (c) 2001 Tracy Allen, http://www.emesystems.com
    > ' like lookdown operator, except data in eeprom word table
    > ' word values increasing in table.
    > ' User enters a number. The routine finds the closest two values
    > ' in the table such that wx < number < wy
    > ' and the index pointer to the position of wx in the table
    > ' Uses binary search algorithm for fast acquisition.
    > ' Finds value in a 2^N table in N steps.
    > ' number < smallest value in table returns smallest value
    > ' number > largest value in table returns largest value
    >
    > value VAR Word ' number entered by user
    > wx VAR Word ' comparison value from table
    > wy VAR Word ' binary increment (word for large table)
    > wz VAR Word ' index into table (word for large table)
    > sign VAR Bit ' selects up or down for next step in table
    >
    > tablesize CON 22 ' just for example, 22 entries in DATA table
    > tablesize1 CON tablesize-1
    >
    > table DATA Word 2,Word 5,Word 30,Word 35, Word 57, Word 77, Word 99
    > DATA Word 110, Word 125, Word 278
    > DATA Word 678, Word 777, Word 888, Word 999
    > DATA Word 1010, Word 1111, Word 2000, Word 3333
    > DATA Word 4000, Word 5555, Word 6000, Word 7777
    >
    > DO
    > DEBUG CR,CR,"enter a number: "
    > DEBUGIN DEC5 value ' get user to input a number
    >
    > index_check0:
    > wy=DCD NCD tablesize / 2 ' note A
    > wz=wy-1 ' first address to check, halfway point in the
    table
    >
    > index_check1:
    > READ wz MAX tablesize1 * 2 + table, Word wx ' note B
    > IF wx=value THEN index_check8 ' note C
    > sign=wx/(value MIN 1) MAX 1 ' note D
    > wy=wy/2 ' note E
    > wz=-sign^wy+sign+wz ' note F
    > PAUSE 2
    > ' DEBUG CR,DEC wz,TAB, DEC wy,TAB, DEC wx ,TAB,IBIN sign ' show
    > inner workings
    > IF wy THEN index_check1 ' note G
    > index_check8: ' note H
    > IF value>=wx THEN
    > READ wz+1 MAX tablesize1 * 2,Word wy
    > ELSE
    > wy=wx
    > READ wz MIN 1 -1 * 2,Word wx
    > ENDIf
    > DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    > LOOP
    >
    > ' note A: could use a constant here if tablesize is a constant
    > ' =largest power of two less than tablesize
    > ' tablesize does not have to be a power of two.
    > ' note B: limit read to last table address, *2 because 2 bytes per word
    > ' note C: speed up process if exact match is found
    > ' note D: "sign" is 1 iff value<wx, that is, if value fits into a lower
    > ' position in the table. "value min 1" avoids divide by zero.
    > ' note E: wy is successively lower powers of two
    > ' note F: add (sign=0) or subtract (sign=1) wy from wz
    > ' -sign^wy+sign forms the conditional 2s complement of wy
    > ' note G: continue until wy is reduced to zero
    > ' note H: The IF-THEN-ELSE resolves wx<= value < wy
    > ' wz is the index of wx
    > ' note I: show index and table values below and above user value entered
    >
    >
    >
    >
    > To UNSUBSCRIBE, just send mail to:
    > basicstamps-unsubscribe@yahoogroups.com
    > from the same email address that you subscribed. Text in the Subject and
    Body of the message will be ignored.
    >
    >
    > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
    >
  • ArchiverArchiver Posts: 46,084
    edited 2003-06-28 01:11
    Modify the cleanup code that sorts out the two table entries closest
    above and below the target value.

    index_check8: ' note H
    IF value>=wx THEN
    READ wz+1 MAX tablesize1 * 2,Word wy
    wz = wz MAX tablesize1 ' in case value is out of bounds
    ELSE
    wy=wx ' final value wx was greater than target value, swap
    wz = wz MIN 1 - 1 ' adjust wz to next lower value (but not <0)
    READ wz * 2,Word wx ' this is the value less than the target
    ENDIf
    DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    LOOP

    With this modification, wz always will point to the table entry that
    is less than the target value.

    It also operates smoothly if the value entered happens to lie outside
    the bounds of the table, pointing to the lowest or highest table
    element.

    -- Tracy



    >Tracy,
    >
    >I've started to implement this in my program, and it does work VERY fast
    >compared to my initial sequential search.
    >
    >However, I noticed that "wz" changes in multiples of two. Let me explain:
    >
    >I noticed that your program will work standalone. Upon initial inspection, I
    >thought that "wz" would always point to the upper or lower two of the
    >indexes found, but it does not. For example, the inputs 56, 57, and 76
    >always set wz at the end of the search to "4", even though the wx and wy
    >variable are updated to relfect the upper and lower "closest matches".
    >
    >I then incorperated this into my program with this assumption. I then read
    >the values at that index, and that index minus 1, check which one is
    >actually closest, then return that index. However, with the behaviour I
    >talked about above, this doesn't work properly. Can you offer a suggestion
    >to correct this?
    >
    >This will not be a production product, but if I do use your code in the
    >future with your permission, I will definately give you credit!
    >
    >Thanks,
    >Steve Ziuchkovski
    >
    >
    Original Message
    >From: "Tracy Allen" <tracy@e...>
    >To: <basicstamps@yahoogroups.com>
    >Sent: Friday, June 27, 2003 9:52 AM
    >Subject: Re: [noparse][[/noparse]basicstamps] Binary search on a lookup table for "closest
    >value"
    >
    >
    >> Here's a demo program for binary search. It is like the lookdown
    >> operator, except that it searches a table of increasing numbers (word
    >> values) in DATA eeprom. You enter a number at the keyboard, and the
    >> program finds the numbers closest above and below it in the table.
    >> This kind of thing is good for interpolation problems or search for
    >> free memory. The binary algorithm finds the answer in N steps, given
    >> a table with 2^N entries. E.g., a table with 1024 entries is resolved
    >> in 10 steps. Algorithm is like a successive approximation ADC. Uses
    >> a bunch of math tricks in place of IF-THEN or CASE statements.
    >>
    >> '{$STAMP BS2}
    >> '{$PBASIC 2.5}
    >> ' (c) 2001 Tracy Allen, http://www.emesystems.com
    >> ' like lookdown operator, except data in eeprom word table
    >> ' word values increasing in table.
    > > ' User enters a number. The routine finds the closest two values
    > > ' in the table such that wx < number < wy
    > > ' and the index pointer to the position of wx in the table
    >> ' Uses binary search algorithm for fast acquisition.
    >> ' Finds value in a 2^N table in N steps.
    >> ' number < smallest value in table returns smallest value
    >> ' number > largest value in table returns largest value
    >>
    >> value VAR Word ' number entered by user
    >> wx VAR Word ' comparison value from table
    >> wy VAR Word ' binary increment (word for large table)
    >> wz VAR Word ' index into table (word for large table)
    >> sign VAR Bit ' selects up or down for next step in table
    >>
    >> tablesize CON 22 ' just for example, 22 entries in DATA table
    >> tablesize1 CON tablesize-1
    >>
    >> table DATA Word 2,Word 5,Word 30,Word 35, Word 57, Word 77, Word 99
    >> DATA Word 110, Word 125, Word 278
    >> DATA Word 678, Word 777, Word 888, Word 999
    >> DATA Word 1010, Word 1111, Word 2000, Word 3333
    > > DATA Word 4000, Word 5555, Word 6000, Word 7777
    >>
    >> DO
    >> DEBUG CR,CR,"enter a number: "
    >> DEBUGIN DEC5 value ' get user to input a number
    >>
    >> index_check0:
    >> wy=DCD NCD tablesize / 2 ' note A
    >> wz=wy-1 ' first address to check, halfway point in the
    >table
    >>
    >> index_check1:
    >> READ wz MAX tablesize1 * 2 + table, Word wx ' note B
    >> IF wx=value THEN index_check8 ' note C
    >> sign=wx/(value MIN 1) MAX 1 ' note D
    >> wy=wy/2 ' note E
    >> wz=-sign^wy+sign+wz ' note F
    >> PAUSE 2
    >> ' DEBUG CR,DEC wz,TAB, DEC wy,TAB, DEC wx ,TAB,IBIN sign ' show
    >> inner workings
    >> IF wy THEN index_check1 ' note G
    > > index_check8: ' note H
    > > IF value>=wx THEN
    > > READ wz+1 MAX tablesize1 * 2,Word wy
    wz = wz MAX tablesize1 ' in case value is out of bounds
    > > ELSE
    > > wy=wx ' final value wx was greater than target value, swap
    wz = wz MIN 1 - 1 ' adjust wz to next lower value (but not <0)
    READ wz * 2,Word wx ' this is the value less than the target
    > > ENDIf
    > > DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    > > LOOP
    > > IF value>=wx THEN
    >> READ wz+1 MAX tablesize1 * 2,Word wy
    >> ELSE
    >> wy=wx
    >> READ wz MIN 1 -1 * 2,Word wx
    >> ENDIf
    >> DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    >> LOOP
    > >
    >> ' note A: could use a constant here if tablesize is a constant
    >> ' =largest power of two less than tablesize
    >> ' tablesize does not have to be a power of two.
    >> ' note B: limit read to last table address, *2 because 2 bytes per word
    >> ' note C: speed up process if exact match is found
    >> ' note D: "sign" is 1 iff value<wx, that is, if value fits into a lower
    >> ' position in the table. "value min 1" avoids divide by zero.
    >> ' note E: wy is successively lower powers of two
    >> ' note F: add (sign=0) or subtract (sign=1) wy from wz
    >> ' -sign^wy+sign forms the conditional 2s complement of wy
    >> ' note G: continue until wy is reduced to zero
    >> ' note H: The IF-THEN-ELSE resolves wx<= value < wy
    >> ' wz is the index of wx
    >> ' note I: show index and table values below and above user value entered
    >>
    >>
    >>
    >>
    >> To UNSUBSCRIBE, just send mail to:
    >> basicstamps-unsubscribe@yahoogroups.com
    >> from the same email address that you subscribed. Text in the Subject and
    >Body of the message will be ignored.
    >>
    >>
    >> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
    >>
    >
    >
    >To UNSUBSCRIBE, just send mail to:
    > basicstamps-unsubscribe@yahoogroups.com
    >from the same email address that you subscribed. Text in the
    >Subject and Body of the message will be ignored.
    >
    >
    >Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
  • ArchiverArchiver Posts: 46,084
    edited 2003-06-29 08:07
    Tracy,

    This added to the last post does exactly what I wanted. Now my program works
    great, and a lot faster!

    Steve

    Original Message
    From: "Tracy Allen" <tracy@e...>
    To: <basicstamps@yahoogroups.com>
    Sent: Saturday, June 28, 2003 2:11 AM
    Subject: Re: [noparse][[/noparse]basicstamps] Binary search on a lookup table for "closest
    value"


    > Modify the cleanup code that sorts out the two table entries closest
    > above and below the target value.
    >
    > index_check8: ' note H
    > IF value>=wx THEN
    > READ wz+1 MAX tablesize1 * 2,Word wy
    > wz = wz MAX tablesize1 ' in case value is out of bounds
    > ELSE
    > wy=wx ' final value wx was greater than target value, swap
    > wz = wz MIN 1 - 1 ' adjust wz to next lower value (but not <0)
    > READ wz * 2,Word wx ' this is the value less than the target
    > ENDIf
    > DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    > LOOP
    >
    > With this modification, wz always will point to the table entry that
    > is less than the target value.
    >
    > It also operates smoothly if the value entered happens to lie outside
    > the bounds of the table, pointing to the lowest or highest table
    > element.
    >
    > -- Tracy
    >
    >
    >
    > >Tracy,
    > >
    > >I've started to implement this in my program, and it does work VERY fast
    > >compared to my initial sequential search.
    > >
    > >However, I noticed that "wz" changes in multiples of two. Let me explain:
    > >
    > >I noticed that your program will work standalone. Upon initial
    inspection, I
    > >thought that "wz" would always point to the upper or lower two of the
    > >indexes found, but it does not. For example, the inputs 56, 57, and 76
    > >always set wz at the end of the search to "4", even though the wx and wy
    > >variable are updated to relfect the upper and lower "closest matches".
    > >
    > >I then incorperated this into my program with this assumption. I then
    read
    > >the values at that index, and that index minus 1, check which one is
    > >actually closest, then return that index. However, with the behaviour I
    > >talked about above, this doesn't work properly. Can you offer a
    suggestion
    > >to correct this?
    > >
    > >This will not be a production product, but if I do use your code in the
    > >future with your permission, I will definately give you credit!
    > >
    > >Thanks,
    > >Steve Ziuchkovski
    > >
    > >
    Original Message
    > >From: "Tracy Allen" <tracy@e...>
    > >To: <basicstamps@yahoogroups.com>
    > >Sent: Friday, June 27, 2003 9:52 AM
    > >Subject: Re: [noparse][[/noparse]basicstamps] Binary search on a lookup table for "closest
    > >value"
    > >
    > >
    > >> Here's a demo program for binary search. It is like the lookdown
    > >> operator, except that it searches a table of increasing numbers (word
    > >> values) in DATA eeprom. You enter a number at the keyboard, and the
    > >> program finds the numbers closest above and below it in the table.
    > >> This kind of thing is good for interpolation problems or search for
    > >> free memory. The binary algorithm finds the answer in N steps, given
    > >> a table with 2^N entries. E.g., a table with 1024 entries is resolved
    > >> in 10 steps. Algorithm is like a successive approximation ADC. Uses
    > >> a bunch of math tricks in place of IF-THEN or CASE statements.
    > >>
    > >> '{$STAMP BS2}
    > >> '{$PBASIC 2.5}
    > >> ' (c) 2001 Tracy Allen, http://www.emesystems.com
    > >> ' like lookdown operator, except data in eeprom word table
    > >> ' word values increasing in table.
    > > > ' User enters a number. The routine finds the closest two values
    > > > ' in the table such that wx < number < wy
    > > > ' and the index pointer to the position of wx in the table
    > >> ' Uses binary search algorithm for fast acquisition.
    > >> ' Finds value in a 2^N table in N steps.
    > >> ' number < smallest value in table returns smallest value
    > >> ' number > largest value in table returns largest value
    > >>
    > >> value VAR Word ' number entered by user
    > >> wx VAR Word ' comparison value from table
    > >> wy VAR Word ' binary increment (word for large table)
    > >> wz VAR Word ' index into table (word for large table)
    > >> sign VAR Bit ' selects up or down for next step in table
    > >>
    > >> tablesize CON 22 ' just for example, 22 entries in DATA
    table
    > >> tablesize1 CON tablesize-1
    > >>
    > >> table DATA Word 2,Word 5,Word 30,Word 35, Word 57, Word 77, Word 99
    > >> DATA Word 110, Word 125, Word 278
    > >> DATA Word 678, Word 777, Word 888, Word 999
    > >> DATA Word 1010, Word 1111, Word 2000, Word 3333
    > > > DATA Word 4000, Word 5555, Word 6000, Word 7777
    > >>
    > >> DO
    > >> DEBUG CR,CR,"enter a number: "
    > >> DEBUGIN DEC5 value ' get user to input a number
    > >>
    > >> index_check0:
    > >> wy=DCD NCD tablesize / 2 ' note A
    > >> wz=wy-1 ' first address to check, halfway point in the
    > >table
    > >>
    > >> index_check1:
    > >> READ wz MAX tablesize1 * 2 + table, Word wx ' note B
    > >> IF wx=value THEN index_check8 ' note C
    > >> sign=wx/(value MIN 1) MAX 1 ' note D
    > >> wy=wy/2 ' note E
    > >> wz=-sign^wy+sign+wz ' note F
    > >> PAUSE 2
    > >> ' DEBUG CR,DEC wz,TAB, DEC wy,TAB, DEC wx ,TAB,IBIN sign ' show
    > >> inner workings
    > >> IF wy THEN index_check1 ' note G
    > > > index_check8: ' note H
    > > > IF value>=wx THEN
    > > > READ wz+1 MAX tablesize1 * 2,Word wy
    > wz = wz MAX tablesize1 ' in case value is out of bounds
    > > > ELSE
    > > > wy=wx ' final value wx was greater than target value, swap
    > wz = wz MIN 1 - 1 ' adjust wz to next lower value (but not <0)
    > READ wz * 2,Word wx ' this is the value less than the target
    > > > ENDIf
    > > > DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    > > > LOOP
    > > > IF value>=wx THEN
    > >> READ wz+1 MAX tablesize1 * 2,Word wy
    > >> ELSE
    > >> wy=wx
    > >> READ wz MIN 1 -1 * 2,Word wx
    > >> ENDIf
    > >> DEBUG CR,">",TAB,DEC wz,TAB,DEC wx,TAB,DEC wy ' note I
    > >> LOOP
    > > >
    > >> ' note A: could use a constant here if tablesize is a constant
    > >> ' =largest power of two less than tablesize
    > >> ' tablesize does not have to be a power of two.
    > >> ' note B: limit read to last table address, *2 because 2 bytes per word
    > >> ' note C: speed up process if exact match is found
    > >> ' note D: "sign" is 1 iff value<wx, that is, if value fits into a lower
    > >> ' position in the table. "value min 1" avoids divide by zero.
    > >> ' note E: wy is successively lower powers of two
    > >> ' note F: add (sign=0) or subtract (sign=1) wy from wz
    > >> ' -sign^wy+sign forms the conditional 2s complement of wy
    > >> ' note G: continue until wy is reduced to zero
    > >> ' note H: The IF-THEN-ELSE resolves wx<= value < wy
    > >> ' wz is the index of wx
    > >> ' note I: show index and table values below and above user value
    entered
    > >>
    > >>
    > >>
    > >>
    > >> To UNSUBSCRIBE, just send mail to:
    > >> basicstamps-unsubscribe@yahoogroups.com
    > >> from the same email address that you subscribed. Text in the Subject
    and
    > >Body of the message will be ignored.
    > >>
    > >>
    > >> Your use of Yahoo! Groups is subject to
    http://docs.yahoo.com/info/terms/
    > >>
    > >
    > >
    > >To UNSUBSCRIBE, just send mail to:
    > > basicstamps-unsubscribe@yahoogroups.com
    > >from the same email address that you subscribed. Text in the
    > >Subject and Body of the message will be ignored.
    > >
    > >
    > >Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
    >
    >
    > To UNSUBSCRIBE, just send mail to:
    > basicstamps-unsubscribe@yahoogroups.com
    > from the same email address that you subscribed. Text in the Subject and
    Body of the message will be ignored.
    >
    >
    > Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
    >
Sign In or Register to comment.