Map component

Any bugs you encounter with Flowcode should be discussed here.
mnfisher
Valued Contributor
Posts: 953
http://meble-kuchenne.info.pl
Joined: Wed Dec 09, 2020 9:37 pm
Has thanked: 104 times
Been thanked: 507 times

Map component

Post by mnfisher »

Just tried the map component in a small sample of code and there are a couple of problems..

Firstly - and most awkwardly - I got caught by an overflow error. I had a MapInt(.val, 19, 998, 0, 672, true) and didn't get the results I expected as .val increased.

MapInt overflows when .val gets too large (for example - (919 - 19) * (998 - 0) overflows the 16 bit values used if the MapInt function. The workaround is easy in this case - use the MapULong - however - it means that the 'range' of the MapByte and MapInt functions isn't as 'wide' as the user might expect.
It might be possible to avoid these by rearranging the calculations - alternatively the Map functions should use wider variables for the calculations.

Secondly the ClampMinMax argument is a bool - but the tooltip has 1 = Yes 2 = No. The code seems to treat these (correctly) as a bool (so 1 (or better true!) Yes and 0 (false) no.

Martin

medelec35
Matrix Staff
Posts: 1449
Joined: Wed Dec 02, 2020 11:07 pm
Has thanked: 509 times
Been thanked: 471 times

Re: Map component

Post by medelec35 »

Hi, Martin
Thank you for the spot.
I have fixed it best I can.
I will have a word with Ben tomorrow to see if he agrees with the fix, or something better will be required.
Martin

medelec35
Matrix Staff
Posts: 1449
Joined: Wed Dec 02, 2020 11:07 pm
Has thanked: 509 times
Been thanked: 471 times

Re: Map component

Post by medelec35 »

I have attached the updated component if you would like to try it out?
I have removed Long and Ulong.
Edit: It was decided that Long and Ulong can be restored within the map component.
Attachments
MapFunction.zip
(2.55 KiB) Downloaded 156 times
Martin

medelec35
Matrix Staff
Posts: 1449
Joined: Wed Dec 02, 2020 11:07 pm
Has thanked: 509 times
Been thanked: 471 times

Re: Map component

Post by medelec35 »

Hi, Martin.
The updated component is now available via Updates.
Can you let me know if it's any better please?
Martin

mnfisher
Valued Contributor
Posts: 953
Joined: Wed Dec 09, 2020 9:37 pm
Has thanked: 104 times
Been thanked: 507 times

Re: Map component

Post by mnfisher »

Thanks Martin,

I think I can guess what has changed ;) - will give it a try!

Martin

mnfisher
Valued Contributor
Posts: 953
Joined: Wed Dec 09, 2020 9:37 pm
Has thanked: 104 times
Been thanked: 507 times

Re: Map component

Post by mnfisher »

Looks good now. Just tested several cases in simulation and all good (including negative numbers in the case of the MapInt fns)
I agree - keeping the 'long' variants is good - although it's possible to 'catch' them out - I don't think it's likely in a MCU environment

One 'oddity' - setting inmin and inmax to the same value gives a division by 0 (I know - it's an edge case but someone is going to try it :twisted: ) and in simulation it opens the error lists view - but doesn't describe the error or show where it is? (But no - please don't add a test for this in the map function - just interesting that the simulation engine doesn't seem to catch the exception correctly)

Martin

medelec35
Matrix Staff
Posts: 1449
Joined: Wed Dec 02, 2020 11:07 pm
Has thanked: 509 times
Been thanked: 471 times

Re: Map component

Post by medelec35 »

Thank you for testing, Martin.
The Ardunio version uses five longs for whatever values you enter.
I have managed to avoid that.
For example, bytes use no longs, and integers only use one long.
It helps to reduce valuable memory.
Martin

mnfisher
Valued Contributor
Posts: 953
Joined: Wed Dec 09, 2020 9:37 pm
Has thanked: 104 times
Been thanked: 507 times

Re: Map component

Post by mnfisher »

A little bit of testing shows a possible 'gotcha' in using simulation.

The simulation engine doesn't seem to use the correct size of variable - so for example

Code: Select all

byte a,b
a = 127
b = a * 4 / 4
What does b = ?

In simulation it is 127 ! However, you won't get this when running on a MCU. --- Actually you do - see next message!

This also applies to 16 bit numbers - simulation seems to use 32 bit for all the maths.

Note

Code: Select all

b = 300
Does give the expected result - it looks like it is just 'intermediate' (temp) values used in calculations that are wrong.

This does mean that calculations that appear correct in simulation might give unexpected results when run on hardware..

Martin

mnfisher
Valued Contributor
Posts: 953
Joined: Wed Dec 09, 2020 9:37 pm
Has thanked: 104 times
Been thanked: 507 times

Re: Map component

Post by mnfisher »

- and testing on hardware you do get 127 !!!

The compiler seems to optimise out the * 4 / 4 - or (probably) uses a 16 bit register for the maths here.

However - stepping up to 16 bit...

Code: Select all

uint a, b, c
a = 38000
c = 4
b = (a * 4) / c
Gives 38000 in sim and 5232 on hardware..

Martin

Steve-Matrix
Matrix Staff
Posts: 1244
Joined: Sat Dec 05, 2020 10:32 am
Has thanked: 167 times
Been thanked: 277 times

Re: Map component

Post by Steve-Matrix »

mnfisher wrote:
Wed Sep 29, 2021 9:41 am
...it looks like it is just 'intermediate' (temp) values used in calculations that are wrong.
I think you are right. It looks like the simulation is 'promoting' the intermediate value of the calculation to something wider than a byte. I must admit the rules for integer arithmetic promotion in C are quite complicated and I think things may have changed as the language has developed. Plus you may be hitting issues with 'machine-dependence' (i.e. some C calculations on an 8-bit micro may be inherently different to C on a 64-bit PC due to default integer/register sizes).

You might also be hitting issues with compiler optimisations where constant operands are evaluated at compiler time to make the actual runtime calculation faster and take less memory.

I'd like to use a similar example "b = a * 4 / 3" to illustrate a couple of things that can help in this situation to avoid odd arithmetic bugs and improve readability of the code.

I find brackets to be beneficial, even in trivial cases like this, to improve code understanding. So in this example, does "b = (a * 4) / 3" or "b = a * (4 / 3)" make more sense? The former is the way the compiler will interpret it when there are no brackets, but I find it helps understand the intention of the calculation. And it shows a couple of things that could go wrong.

In the latter, "4 / 3" will be done first and because these are integers then the result will be "1". This is a common gotcha for inexperienced programmers who may expect the intermediate result to be "1.33333"

And in the former, it highlights that one of the intermediate results will be "a * 4" and so the issue of integer promotion will come into play here and you may get truncation errors. So you need to ensure the size of your variable "a" (and the size of the variable receiving the result) is big enough to contain all expected values.

Post Reply