Shop OBEX P1 Docs P2 Docs Learn Events
Basic Stamp Math Puzzle — Parallax Forums

Basic Stamp Math Puzzle

ArchiverArchiver Posts: 46,084
edited 2000-04-12 18:52 in General Discussion
Basic Stamp Math Gurus,

I need your help. I am trying to calculate a ratio of 16-bit numbers
to be used with the '*/' function. I will attempt to explain my
problem with an example:

A=1300
B=500

A/B=2 remainder 300

What is the best way to reduce my ratio so that my remainder is less
than 256?

The answer should be $0299.

TIA,

Roger Byrum

Comments

  • ArchiverArchiver Posts: 46,084
    edited 2000-04-12 01:41
    > I need your help. I am trying to calculate a ratio of
    > 16-bit numbers to be used with the '*/' function.
    > I will attempt to explain my problem with an example:
    > A=1300
    > B=500
    > A/B=2 remainder 300
    > What is the best way to reduce my ratio so that my
    > remainder is less than 256? The answer should be $0299.
    > TIA,
    > Roger Byrum

    Hi Roger,
    It would help to know what you are going to do with the */ operator. What
    do you mean by, "The answer should be $0299"? I have a write-up on how to
    use */ and ** at:
    http://www.emesystems.com/BS2math1.htm

    - Tracy
  • ArchiverArchiver Posts: 46,084
    edited 2000-04-12 14:47
    --- In basicstamps@egroups.com, Tracy Allen <emesys@c...> wrote:
    > > I need your help. I am trying to calculate a ratio of
    > > 16-bit numbers to be used with the '*/' function.
    > > I will attempt to explain my problem with an example:
    > > A=1300
    > > B=500
    > > A/B=2 remainder 300
    > > What is the best way to reduce my ratio so that my
    > > remainder is less than 256? The answer should be $0299.
    > > TIA,
    > > Roger Byrum
    >
    > Hi Roger,
    > It would help to know what you are going to do with the */
    operator. What
    > do you mean by, "The answer should be $0299"? I have a write-up on
    how to
    > use */ and ** at:
    > http://www.emesystems.com/BS2math1.htm
    >
    > - Tracy

    Thank you for the response Tracy.

    I intend to use the */ function to simulate a floating point number.
    An example in the book shows how to use it to calculate PI 3.14=$0324.
    The high byte, $03, is the whole number part, and the low byte, $24,
    is the fractional part. The fractional part is multiplied by 256 to
    arrive at a value for the low byte. It can be though of as a
    fraction with $100 as the denominator: i.e. $24/$100 = ~0.14.

    To clarify my problem, I have two 16 bit variables that constitute my
    ratio. From the example above, the numerator is N=1300 and the
    denominator is D=500. It is my intension to multiply this ratio
    against another 16 bit variable. One solution would be to first
    multiply by the numerator and then divide by the denominator. By
    doing so, I run the risk of overflowing the 16 bit limit on the
    multiplication or at the other extreme, if I use **, the values may
    be too small and I get zero.

    This line of though brought me to the */ function. I loose a little
    accuracy but that won't kill me in my application.

    1300/500 = 2.6 -> $02 (whole number) .6*256=153.6 -> $99 (fraction)

    $0299=665 -> 665/256=2.598 or ~2.6

    I should note that in my application, my 16 bit ratio will routinely
    be greater than and less than 1.

    Sorry if I was so long winded!

    Thanks again,

    Roger
  • ArchiverArchiver Posts: 46,084
    edited 2000-04-12 15:05
    > I intend to use the */ function to simulate a floating point number.
    > An example in the book shows how to use it to calculate PI 3.14=$0324.
    > The high byte, $03, is the whole number part, and the low byte, $24,
    > is the fractional part. The fractional part is multiplied by 256 to
    > arrive at a value for the low byte. It can be though of as a
    > fraction with $100 as the denominator: i.e. $24/$100 = ~0.14.

    Hmm.... that example sounds familiar.

    >
    > To clarify my problem, I have two 16 bit variables that constitute my
    > ratio. From the example above, the numerator is N=1300 and the
    > denominator is D=500. It is my intension to multiply this ratio
    > against another 16 bit variable. One solution would be to first
    > multiply by the numerator and then divide by the denominator. By
    > doing so, I run the risk of overflowing the 16 bit limit on the
    > multiplication or at the other extreme, if I use **, the values may
    > be too small and I get zero.
    >
    > This line of though brought me to the */ function. I loose a little
    > accuracy but that won't kill me in my application.
    >
    > 1300/500 = 2.6 -> $02 (whole number) .6*256=153.6 -> $99 (fraction)
    >
    > $0299=665 -> 665/256=2.598 or ~2.6
    >

    w=N/D ' 2
    w=w*$100 ' get ready
    wf=N//D ' 300 (remainder)
    wf=wf*$100/D ' wf = 153 (truncated 153.6)
    w.lowbyte=wf.lowbyte ' w = $0299

    Y=X*/w

    Is that what you are asking? By the way -- just to mention it -- another
    answer would be
    to use a PAK-I connected to the Stamp with 2 pins -- then you could use real
    floating point:

    fpx=D ' get D (500) into PAK's X reg
    gosub floadint
    gosub fswap ' Swap X and Y registers
    fpx=N ' Now load N as an integer
    gosub floadint
    gosub fdiv ' Divide
    gosub fswap ' Put result in Y
    fpx=X ' Load X (number to be multiplied by N/D)
    gosub floadint
    gosub fmult ' Multiply
    gosub fint ' read integer
    debug ?fpx ' correct answer

    Regards,

    Al Williams
    AWC
    *Floating point math for the Stamp, PIC, SX, or any microcontroller at
    http://www.al-williams.com/awce/pak1.htm
  • ArchiverArchiver Posts: 46,084
    edited 2000-04-12 17:59
    --- In basicstamps@egroups.com, "Al Williams" <alw@a...> wrote:
    > > I intend to use the */ function to simulate a floating point
    number.
    > > An example in the book shows how to use it to calculate PI
    3.14=$0324.
    > > The high byte, $03, is the whole number part, and the low byte,
    $24,
    > > is the fractional part. The fractional part is multiplied by 256
    to
    > > arrive at a value for the low byte. It can be though of as a
    > > fraction with $100 as the denominator: i.e. $24/$100 = ~0.14.
    >
    > Hmm.... that example sounds familiar.
    >
    > >
    > > To clarify my problem, I have two 16 bit variables that
    constitute my
    > > ratio. From the example above, the numerator is N=1300 and the
    > > denominator is D=500. It is my intension to multiply this ratio
    > > against another 16 bit variable. One solution would be to first
    > > multiply by the numerator and then divide by the denominator. By
    > > doing so, I run the risk of overflowing the 16 bit limit on the
    > > multiplication or at the other extreme, if I use **, the values
    may
    > > be too small and I get zero.
    > >
    > > This line of though brought me to the */ function. I loose a
    little
    > > accuracy but that won't kill me in my application.
    > >
    > > 1300/500 = 2.6 -> $02 (whole number) .6*256=153.6 -> $99
    (fraction)
    > >
    > > $0299=665 -> 665/256=2.598 or ~2.6
    > >
    >
    > w=N/D ' 2
    > w=w*$100 ' get ready
    > wf=N//D ' 300 (remainder)
    > wf=wf*$100/D ' wf = 153 (truncated 153.6)
    > w.lowbyte=wf.lowbyte ' w = $0299
    >
    > Y=X*/w
    >
    > Is that what you are asking? By the way -- just to mention it --
    another
    > answer would be
    > to use a PAK-I connected to the Stamp with 2 pins -- then you could
    use real
    > floating point:
    >
    > fpx=D ' get D (500) into PAK's X reg
    > gosub floadint
    > gosub fswap ' Swap X and Y registers
    > fpx=N ' Now load N as an integer
    > gosub floadint
    > gosub fdiv ' Divide
    > gosub fswap ' Put result in Y
    > fpx=X ' Load X (number to be multiplied by N/D)
    > gosub floadint
    > gosub fmult ' Multiply
    > gosub fint ' read integer
    > debug ?fpx ' correct answer
    >
    > Regards,
    >
    > Al Williams
    > AWC
    > *Floating point math for the Stamp, PIC, SX, or any microcontroller
    at
    > http://www.al-williams.com/awce/pak1.htm

    Big Thanks Al! This is exactly what I need.

    Roger Byrum
    Logansport, IN
  • ArchiverArchiver Posts: 46,084
    edited 2000-04-12 18:06
    > > w=N/D ' 2
    > > w=w*$100 ' get ready
    > > wf=N//D ' 300 (remainder)
    > > wf=wf*$100/D ' wf = 153 (truncated 153.6)
    > > w.lowbyte=wf.lowbyte ' w = $0299
    > >
    > > Y=X*/w
    > >

    Actually, I wrote this early. The second line would probably be better
    written:

    w=w<<8

    or even better:

    w.highbyte=w.lowbyte


    Any of the 3 lines ought to work, but the last one is probably (probably)
    faster.

    Come to think of it, I guess
    wf=wf*$100/D would be smarter to write as:

    wf=wf<<8/D

    Can't use the hibyte/lowbyte trick for reasons I will leave as an exercise.

    Regards,

    Al Williams
    AWC
    * Tax special from now to April 17th. Order a copy of Microcontroller
    Projects with Basic Stamps and get an ASP-II free.
    http://www.al-williams.com/awce/sbook.htm
  • ArchiverArchiver Posts: 46,084
    edited 2000-04-12 18:23
    Hi Roger,

    Operators */ and ** are easily applicable to constant fractions (like pi)
    that you can calculate in advance.

    However, it sounds like that is not what you want to do. You are looking
    for a solution to

    Y=X*A/B

    where all three quantities on the right are variables. Is that right?
    That is a different story.

    There as Al pointed out, you may be able to do a division in steps. Here
    is the formula compressed into one line:

    Y = A/B * 256 + (A//B * 256 / B) */ X ' to solve Y=X*A/B

    BTW, the */ operator is commutative: X*/Y = Y*/X. The caveat on the above
    formula is that the value of (A//B*256) has to be less than 65536, which
    means A//B has to be less than 256, which is always satisfied when B is
    less than 256. Also, note that A/B has to be less than 256. Those are
    pretty strong constraints.

    For example, you suggested the fraction A/B=1300/500, and the remainder
    happens to be R=300, so the formula will blow up. (That is true of Al's
    formula too--sorry Al!--it will blow up in the step wf=wf*$100/D, because
    wf=300. The formula as written will return 22, not the correct value, 153.
    Same thing if you write it as wf=wf<<8/D). In order not to blow up, the
    denominator has to satisfy the inequality: 1300-N*X<256, where N and X are
    integers. If N=2, then 650>X>522. Those are the values of X for which
    the remainder is less than 256. But as you see, it is an extremely ad hoc
    result. It only works if you know pretty well in advance what the range of
    the variables is going to be. Integer inequalities are a bear. Maybe that
    was the substance of your original question?

    A more robust approach involves a binary long division. I have some
    examples posted at:
    http://www.emesystems.com/BS2math2.htm
    That is for equations where there is a variable in the denominator. The
    Y=X*A/B problem can be solved with a binary long division followed by a **
    operator. But you still have to think about the constraints! But the main
    constraint is only that 0<B<32768.

    Also at
    http://www.emesystems.com/BS2math1.htm
    there are more examples using */ and ** for dealing with the case when A/B
    is a constant fraction known in advance.


    I hope that helps.

    -- Tracy Allen
    Electronically Monitored Ecosystems
    http://www.emesystems.com
  • ArchiverArchiver Posts: 46,084
    edited 2000-04-12 18:52
    > (That is true of Al's
    > formula too--sorry Al!--it will blow up in the step wf=wf*$100/D, because
    > wf=300. The formula as written will return 22, not the correct
    > value, 153.

    I should know better than to answer anything before 9AM. Of course, you are
    correct, with the numbers supplied, an overflow occurs. Sorry!

    Regards,

    Al Williams
    AWC
    * Tax special from now to April 17th. Order a copy of Microcontroller
    Projects with Basic Stamps and get an ASP-II free.
    http://www.al-williams.com/awce/sbook.htm
Sign In or Register to comment.