Shop OBEX P1 Docs P2 Docs Learn Events
Simple math question — Parallax Forums

Simple math question

turbosupraturbosupra Posts: 1,088
edited 2010-10-20 10:52 in Propeller 1
I keep getting 0 when I do this math equation (an example value of Leading1toLeading2EdgeTime is 54382720)



rpml1tol2 := ((1/((Leading1toLeading2EdgeTime/clkfreq) * 36)) * 60)

final value should be 2.451759186251319046442203209647 or rounded to 2

Does anyone have a code example of how to do that? Am I missing something with float here?

Comments

  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-10-16 08:25
    If you're running at 80MHz then this is a problem:

    Leading1toLeading2EdgeTime/clkfreq

    By my calculator with your value (54382720) the answer is 0.6 and change which will be rounded to zero.

    Looking at your equation it works on a calculator because you're dealing with fractional values -- you're going to have to rearrange the formula to work within decimal division constraints.
  • turbosupraturbosupra Posts: 1,088
    edited 2010-10-16 08:33
    Hi JonnyMac

    Thanks for the reply ... is there no way to work with a value less than 1?

    JonnyMac wrote: »
    If you're running at 80MHz then this is a problem:

    Leading1toLeading2EdgeTime/clkfreq

    By my calculator with your value (54382720) the answer is 0.6 and change which will be rounded to zero.

    Looking at your equation it works on a calculator because you're dealing with fractional values -- you're going to have to rearrange the formula to work within decimal division constraints.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-10-16 08:35
    You can always use one of the floating point objects in the Spin library (e.g. Float32).

    -Phil
  • turbosupraturbosupra Posts: 1,088
    edited 2010-10-16 08:46
    Hi Phil,

    I searched for over an hour on the forum before posting, trying to find an example that would apply to what I'm doing and I was unable to make anything work.

    I believe I would include Float32 in the obj section, how would I insert the references/calls to it in my code though?

    You can always use one of the floating point objects in the Spin library (e.g. Float32).

    -Phil
  • John AbshierJohn Abshier Posts: 1,116
    edited 2010-10-16 08:48
    Rearranging the formula to (clkfreq * 60)/(Leading1toLeading2EdgeTime * 36)
    Assuming a clkfreq of 80,000,000 the constants evaluate to 133,333,333.333
    Now the formual is 133,333,333/Leading1toLeading2EdgeTime which equals 2 in integer math.
    If you need more precision use 13,333,333,300/Leading1toLeading2EdgeTime which equals 245 in units of 1/100th.

    John Abshier
  • Dave HeinDave Hein Posts: 6,347
    edited 2010-10-16 08:57
    60 times 80,000,000 is 4.8 billion, which will overflow in a 32-bit long. Divide 60 and 36 by 12, and you'll be OK. So the equation would be.

    (clkfreq * 5)/(Leading1toLeading2EdgeTime * 3)

    This will truncate to the nearest integer value. If you want to round you will need to use the following:

    ((clkfreq * 5) + (Leading1toLeadin2EdgeTime *3 / 2))/(Leading1toLeading2EdgeTime * 3)

    Dave
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-10-16 09:05
    That won't work, John, because clkfreq * 60 rolls past POSX. I rearranged and simplified to this:
    rpm := clkfreq / (le1tole2 * 6 / 10)
    

    ... and the answer is 2. Changing to:
    rpm := clkfreq / (le1tole2 * 6 / 1000)
    

    ... gives 245 which provides additional resolution, though one will have to experiment with the full range of possible values to prevent any rollover/rollunder problems. You could do this to keep 1/100ths resolution and extend the possible range of le1tole2:
    rpm := clkfreq / (le1tole2 * 3 / 2000)
    
  • turbosupraturbosupra Posts: 1,088
    edited 2010-10-16 09:11
    Thank you all very much, I was pulling my hair out on this :)


    Should I heed this as a warning to learn more about floating point math and the propeller, or is there always a simple work around like this?



    Rearranging the formula to (clkfreq * 60)/(Leading1toLeading2EdgeTime * 36)
    Assuming a clkfreq of 80,000,000 the constants evaluate to 133,333,333.333
    Now the formual is 133,333,333/Leading1toLeading2EdgeTime which equals 2 in integer math.
    If you need more precision use 13,333,333,300/Leading1toLeading2EdgeTime which equals 245 in units of 1/100th.

    John Abshier
    Dave Hein wrote: »
    60 times 80,000,000 is 4.8 billion, which will overflow in a 32-bit long. Divide 60 and 36 by 12, and you'll be OK. So the equation would be.

    (clkfreq * 5)/(Leading1toLeading2EdgeTime * 3)

    This will truncate to the nearest integer value. If you want to round you will need to use the following:

    ((clkfreq * 5) + (Leading1toLeadin2EdgeTime *3 / 2))/(Leading1toLeading2EdgeTime * 3)

    Dave
    JonnyMac wrote: »
    That won't work, John, because clkfreq * 60 rolls past POSX. I rearranged and simplified to this:
    rpm := clkfreq / (le1tole2 * 6 / 10)
    

    ... and the answer is 2. Changing to:
    rpm := clkfreq / (le1tole2 * 6 / 1000)
    

    ... gives 245 which provides additional resolution, though one will have to experiment with the full range of possible values to prevent any rollover/rollunder problems. You could do this to keep 1/100ths resolution and extend the possible range of le1tole2:
    rpm := clkfreq / (le1tole2 * 3 / 2000)
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-10-16 09:15
    turbosupra wrote:
    Should I heed this as a warning to learn more about floating point math and the propeller, or is there always a simple work around like this?
    I've used the float routines exactly once. So, yes, there's usually a way to rearrange your formulas so they can be computed with integer math. But sometimes, as in my singular case, the float methods are essential.

    -Phil
  • Mike GreenMike Green Posts: 23,101
    edited 2010-10-16 09:34
    The Float32 object comes with pretty good documentation with some examples. Do have a look at it.
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2010-10-18 18:31
    It's not hard to achieve more precision using integer math. The attached program shows a method to print out the answer from your first post,
    2.451759186251319046442203209647
    with 31 digits to the right of the decimal point. That is fine if you just want to display the result, but a second method computes it as a fixed point number that you can use in followup calculations,
    24517592
    with implied 7 digits rounded off to the right of the decimal point.

    The core of the algorithm is simple long division:
    result := y / x    ' this is the integer part, left of the decimal point
      repeat ix from 1 to n   ' kick out digits to right of decimal point
        y := y // x * 10
        result := (result*10) + (y /x) ' shift digits left and accumulate
    
    where the first step is the integer part of the result and the loop shifts in n digits to the right of the decimal point.
  • turbosupraturbosupra Posts: 1,088
    edited 2010-10-20 10:52
    Thanks Tracy!

    I'll have to try this, this weekend. I would really like to get floats working in my program, as it is becoming apparent I will need them.
Sign In or Register to comment.