Decimal Math - Newbie Discovery

artswan

Member
This is just for information for anyone having trouble with decimal math on Picaxe. I am sure this is already posted in some form on here already, but it's always helpful to us newbies.

I was trying to multiply a variable w0 by 1.47. Tried the recommended ways such as w1 = w0 * 147/100 , etc. Still came up with screwy results, probably due to overflow.

But then I remembered, Picaxe does math Left to Right. I was putting the variable I wanted to multiply by 1.47 (w0) at the beginning of the equation because it looked proper. However, I found I got much better results when I put the variable (w0) at the END.

I rewrote the equation to be w1 = 147/100 * w0. Do the math first, then throw in the variable.

I get much better results this way.

I hope this info helps someone.

:)
 

MartinM57

Moderator
...but unfortunately in PICAXE L->R integer maths, 147/100 equals 1 and so W1 will end up as exactly w0 and you will not have multiplied by 1.47 at all :(

You may want to think again....to avoid "screwy results" due to overflow you need to know the range of possible values of your w0 at the start of the calc. What is the range?
 
Last edited:

artswan

Member
That's interesting, because that is not the result I am getting. The results are tracking accurately on my pressure sensor calculations. Maybe using an 08M2 is making the difference? I should try this on other Picaxes?
 

MartinM57

Moderator
I suggest you have a play in the simulator with your actual (or a subset of it) code - unless you are the first person to discover the hidden floating point mathematical capabilities of the 08M2 ;)
 

westaust55

Moderator
If your application can afford some slight error, using
148 / 100 expressed as 74 / 50 so you then use
W1 = W0 * 74 / 50
may avoid overflow if w0 is not too large (is < ~800 )
 

vttom

Senior Member
74/50 further reduces to 37/25, so you can do:

w1 = w0 * 37 / 25

which will not overflow so long as w0 <= floor(((2^16)-1)/37) = 1771.
 

hippy

Ex-Staff (retired)
You can also use a SELECT-CASE to determine which to use so the error is minimised when w0 is low enough not to overflow ...

Code:
Select Case w0
  Case <= 445 : w1 = w0 * 147 / 100
  Else        : w1 = w0 * 74  / 50
End Select
Where you have N/M, as long as both are even, you can divide both by two without any loss of accuracy, so 74/50 is the same as 37/25.

If w0*37 still overflows you have to again do as westaust55 did and find a close even number pair and divide down by two again, so 37/25 is roughly 36/24, is 18/12, is 9/6 ... is 3/2 because dividing top and bottom by the same doesn't alter accuracy.
 
Last edited:

vttom

Senior Member
Oops. I forgot that the original factor was 1.47 not 1.48. Does the following make sense?

w1 = w0 * (150-3) / 100

which becomes

w1 = w0 * 150 / 100 - w0 * 3 / 100

which becomes

w1 = w0 * 3 / 2 - w0 * 3 / 100

Does this gain back any accuracy?
 

vttom

Senior Member
Oops. That math in the last part isn't quite right. It probably needs to be done in 2 steps:

w1 = w0 * 3 / 100
w1 = w0 * 3 / 2 - w1
 

ckoehn

Member
When knowing what the decimal is, I always do it this way...

Code:
w1=w0*1    'don't need this when it is 1, but do if it is any other whole number
w1=w0*4/10+w1  '.4
w1=w0*7/100+w1  '.07

'result of w0*1.47 is stored in w1
 

vttom

Senior Member
When knowing what the decimal is, I always do it this way...

Code:
w1=w0*1    'don't need this when it is 1, but do if it is any other whole number
w1=w0*4/10+w1  '.4
w1=w0*7/100+w1  '.07

'result of w0*1.47 is stored in w1
Brilliant!
 

morrismarine

New Member
When knowing what the decimal is, I always do it this way...

Code:
w1=w0*1    'don't need this when it is 1, but do if it is any other whole number
w1=w0*4/10+w1  '.4
w1=w0*7/100+w1  '.07

'result of w0*1.47 is stored in w1
So am i right in the assumption that i can do math to a variable w1 or b0 etc and then store the answer into the same variable? that unless i wish to keep the original for use again it will work out right, currently ive allways been storing results in a further slot which as you can imagine eventually causes problems. Thank you to the OP for some education :)
 

hippy

Ex-Staff (retired)
I can see the logic in ...

w1 = w0 * 1
w1 = w0 * 4 / 10 + w1
w1 = w0 * 7 / 100 + w1

But it's never been clear to me if that's any more accurate than other methods. Take for example 77 * 1.47 which should be 113.19, 113 after rounding down ...

77 * 1 = 77
77 * 4 / 10 = 30 (30.8)
77 * 7 / 100 = 5 (5.39)

77 + 30 + 5 = 112

The problem appears to be in the 30.8 rounded down plus other decimal loses which accumulate with no way to ever reclaim those. On the plus side it will handle numbers up to 7281 without any overflow, and it's simple and easy to use.

Not knocking the method as such as there's no close to perfect method without going up to 32-bit maths which gets very complicated and there always likely will be some error somewhere.
 

morrismarine

New Member
Of course...otherwise you might run out of variables ;)
in truth its highly unlikely that im going to run out of variables for awhile, but its good to know as it may allow a tidier solution. Theres likely to be some more equations in the overcurrent protection plans or not if i find a spare OCR relay
 

westaust55

Moderator
So am i right in the assumption that i can do math to a variable w1 or b0 etc and then store the answer into the same variable? that unless i wish to keep the original for use again it will work out right, currently ive allways been storing results in a further slot which as you can imagine eventually causes problems. Thank you to the OP for some education :)
Yes, so the following is valid:
W4 = W4 / 5
 
Top