Shop OBEX P1 Docs P2 Docs Learn Events
How to multiply by a fraction — Parallax Forums

How to multiply by a fraction

John AbshierJohn Abshier Posts: 1,116
edited 2010-08-25 18:40 in Propeller 1
I remember (correctly or incorrectly) reading a method using the ** operator to multiply a value by a fraction. I cannot find the post with search. I thought it was

result := n ** (2^32 * f) where (2^32 * f) was calculated off line.

That appears to work for f < 0.5 but fails if f => 0.5 For n := 1000 and f := 0.5 I get -500. For f := 0.9 I get -101.

John Abshier

Comments

  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2010-08-17 08:34
    You're not actually putting in a decimal value are you?
    Then you would be mixing and matching floating point and integer math. That never works out.

    I too remember this, but I think it was in the Basic STAMP book (way back when I was learning on that). I will see if I can look it up. But I think you create a 32-bit fraction, then ** it with the variable to get the upper 32-bits of the result.

    Try something like 8 ** $80000000 .. does that equal 4? This would be the equivalent of 8 * 0.5 if I am thinking about this right.
  • John AbshierJohn Abshier Posts: 1,116
    edited 2010-08-17 08:41
    I am not using a decimal fraction.
    f := .1 : 429496730
    f := .2 : 858993459
    f := .5 : 2147483648
    f := .9 : 3865470566

    John Abshier
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2010-08-17 08:50
    Ya, I had a little chance to mess with it, I ran into the same problem you describe. I think it is because SPIN defaults to signed math, which is not what we want in this case.

    I think you may need to fix the problem with a workaround. Shift the fraction value right one bit, and the integer left one bit.

    Like:
    result := (8 << 1) ** ($80000000 >> 1)
    
  • ericballericball Posts: 774
    edited 2010-08-17 08:54
    Remember that longs in SPIN are signed 32 bit values. Therefore 0.5 * 2^32 = $8000_0000 = -2_147_483_648.
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2010-08-17 09:06
    Yes, it's signed math on the Prop that makes the difference, whereas the Stamp is all positive in calculations.

    Try,
    result := (n * 2) ** (2^31 * f) * 2 where (2^31 * f) is calculated off line.
    given n < 2^30

    Oh, that's exactly what Bob is suggesting.
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2010-08-17 09:16
    Oh, that's exactly what Bob is suggesting.
    But mine is faster :D
  • Tracy AllenTracy Allen Posts: 6,666
    edited 2010-08-17 10:27
    Right on! :rolleyes:

    I'm always tripping over that sign trap when I use my habitual Stamp workarounds.
  • John AbshierJohn Abshier Posts: 1,116
    edited 2010-08-17 13:34
    Thanks.
    This worked for N < 2^30
    PUB MulFrac(_n,_frac)
    '' _n is the number we want to multply by a fraction, n < 2^30 
    '' _frac is the fraction * 2^31
      result := (_n << 1) ** _frac
    

    John Abshier
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2010-08-17 13:57
    I don't know how exactly you will be using this function, but you will need to make sure that the fraction is less than 1. You could add an exception line to just return _n if _frac => 1/1. Or you could expand the function to allow fractions larger than 1 and/or add functionality to more accurately represent the LSB (currently it is always rounded down, you could make it round correctly).
  • John AbshierJohn Abshier Posts: 1,116
    edited 2010-08-17 14:20
    I know that it is only good for fraction < 1. That is all I need right now. The rounding is done when I multiply the decimal fraction * 2^31 on my HP calculator program. _frac is not the decimal fraction; it is the decimal fraction * 2^31. When I have time I may expand to work with something like MulFrac(1000, 2.33), but there are other fish to fry in the next couple of weeks. The use will be to multiply raw sensor values by a scale factor.

    John Abshier
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2010-08-25 12:40
    The attached .java file (= plain text file) contains some
    signed/unsigned routines for fractions using signed integer math.
    You need to convert it to Spin though.
    Also explains the code.

    regards peter
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2010-08-25 13:21
    John,

    Take a look at my umath object in the OBEX. It includes an unsigned 32 * 32 (=64) / 32 mul/div method that lets you multiply an integer by any rational 32/32 fraction.

    -Phil
  • John AbshierJohn Abshier Posts: 1,116
    edited 2010-08-25 18:40
    Peter, Phil

    Thanks. On the road and no internet once I get to my 87 year old Dad's house tomorrow afternoon. Thank you Road Runner for eliminating dial-up and not cutting my monthy bill.

    John Absier
Sign In or Register to comment.