Shop OBEX P1 Docs P2 Docs Learn Events
fake 32 bit division for dummies — Parallax Forums

fake 32 bit division for dummies

LloydsLloyds Posts: 75
edited 2011-03-27 20:47 in BASIC Stamp
OK folks,
Please don't laugh and point fingers because I know this is something I should be able to handle myself. But I am stumped.

I have a constant

constantA CON 598760 'which is larger than 16 bits. (the 1's place is a zero and is insignificant)

I want to divide it with a variable

variableB VAR word ' that will range between 370 and 2000

result = constantA / variableB ' the result will range from about 300 to 1500

How do I handle this to get an integer result accurate to the 1's place? Knowing what the tenths place remainder is would be nice, but is not really necessary.

Thanks very much,
Lloyd

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-03-26 19:03
    By "accurate", do you mean 4/5 rounded instead of truncated? If so, do this:
    result := (constant + variable >> 1) / variable

    -Phil
  • LloydsLloyds Posts: 75
    edited 2011-03-26 20:21
    Hi Phil,
    I don't seem to be able to get that to work. Was the colon before the = a typo? I get a syntax error.
    Also, with the constant being larger than 16 bits, I get a syntax error of the constant being too large.
    I am still stumped. What do you think?
    Thanks,
    Lloyd
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-03-26 23:50
    Oh, sorry. I thought this was a Propeller question. I didn't notice which forum it was in!

    -Phil
  • Mike GMike G Posts: 2,702
    edited 2011-03-27 12:29
    Not the most sophisticated but it's close. Probably should add modulus logic to reduce the margin of error.

    598760 = 0x922E8
    ' {$STAMP BS2p}
    ' {$PBASIC 2.5}
    
    lowWord   VAR   Word
    highWord  VAR   Word
    result    VAR   Word
    denom     VAR   Word
    
    
    Init:
      lowWord = $22E8
      highWord = $9
    
    
    Main:
    
      denom  = 370
      GOSUB DoMath
      GOSUB ShowResult
      PAUSE 1000
    
      denom  = 2000
      GOSUB DoMath
      GOSUB ShowResult
      PAUSE 1000
    
    GOTO Main
    
    
    DoMath:
      result = ($FFFF / denom) * highWord
      result = result + (lowWord / denom)
    RETURN
    
    
    ShowResult:
      DEBUG CLS, ?result
    RETURN
    
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2011-03-27 14:00
    ' result = 598760 / B
    result = (59876 / B * 10) + ((59876 // B * 10 + 0) / B)
    ' the last +0 is the 1s digit of the constant, which happens to be zero here.

    Here are a couple of links that might help:

    http://emesystems.com/BS2math2.htm#Reciprocal shortcut#2

    http://emesystems.com/BS2math6.htm#Method3 double prec division 63 bits/31 bits
  • LloydsLloyds Posts: 75
    edited 2011-03-27 14:46
    Mike G,
    Cool! I gave it a try and it worked fine but truncated the remainder of the highword division. Came to me after a while.
    I added a step to add the remainder from the highword division to the lowword before doint that division. Then it worked great.


    DoMath:
    result = ($FFFF / denom) * highWord
    remainder = $FFFF - (result * denom)
    result = result + ((lowWord + remainder) / denom)
    RETURN

    There is probably a better way to handle the remainder, but it works.
    Thanks very much!
    Lloyd
  • LloydsLloyds Posts: 75
    edited 2011-03-27 14:51
    Tracy,
    Yes, I see what you are doing. I was thinking of trying something like that but was coming up with something much more complicated.
    Seems like so much of this 16 bit integer math is learning the tricks and then applying them. I am still having some trouble grasping/visualizing some of the math, but progress is happening.

    Thanks everyone,
    Lloyd
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2011-03-27 20:47
    Lloyd,
    You mentioned that you might want to carry out the division to the tenths place. The decimal long division can be placed in a loop, as in the following example:
    Q VAR WORD   ' quotient
    B VAR WORD   ' divisor
    D VAR WORD   ' dividend 
    n VAR NIB
    
      D = 59876   ' start with this, most significant digits of 598760
      B = 370
    fixedPointDecimalDivide:
      Q = 0
       FOR n=0 TO 2
        Q = Q * 10 + (D / B)
        D = D // B * 10 + 0          ' the + 0 would be needed if there other digits.
      NEXT
      IF D / B > 4 THEN Q = Q + 1  ' round off
      DEBUG CR, DEC Q
      ' e.g., Q=16183, decimal point implied, 1618.3 = 598760 / 370
    
Sign In or Register to comment.