Host Engineering Forum

General Category => Do-more CPUs and Do-more Designer Software => Topic started by: Mike Nash on August 21, 2015, 05:55:19 PM

Title: Integer MATH Issue
Post by: Mike Nash on August 21, 2015, 05:55:19 PM
I just realized what I have been seeing in a MATH box with integer numbers while playing with ModbusTCP to another device.

MATH Result N101 3.1416*N100

For N100=10430 N101=32766
For N100=10431 N101=-32766

In other words, the MATH instruction is just chopping off the upper result bits and calling that good. If the result is going to V101 it returns 32770. D101 returns 32769.

I am reading N100 from the other device, doing that one MATH instruction and writing it back to another location in that same device. The other device also does the math and returns 32767 if the result is greater than or equal to 32767 - which is the desired behavior.

Note: yes that is just a pi value I was playing around with. Interestingly 0-9999 gives expected results but 10000 returns 31415. (Decimals are implied in the other device.)

This has nothing to do with the other device as I am looking at these values in Data View.

So... what should be happening and what is the fix to get the value properly clamped or flagged or something without a whole bunch of extra logic?
Title: Re: Integer MATH Issue
Post by: franji1 on August 21, 2015, 08:00:02 PM
The processor does all integer arithmetic as 32-bit 2's complement.  Hence, if you need it to fit in a 16 bit signed integer, and want it to max-out at 32767, just do the following:

MIN(32767, 3.1416 * N100)

This will work great when N100 is a large positive number.  But since N100 is signed, you can have the same issue on the negative side.  The lowest negative 16 bit integer value is -32768, so combine the answer above with the following:

MAX(-32768, MIN(32767, 3.1416 * N100))

The issue regarding the "rounding" problem is that computers are unable to represent most floating point numbers to exact precision.  I like to give the example of 1/3 as a float would require an infinite amount of memory.  You have 32 bits to represent really small numbers and really large numbers.  Hence, you might have entered "3.1416", but internally, the closest it could get was 3.1415998 (not sure, only guessing).  So in your expression, you end up with 31415.998, and when stored as an integer, it is TRUNCATED, so you end up with 31415, not 31416.  Algebraically, it should be 31416, but in computers, they can only "approximate" floating point numbers.

The work-around when storing floating point results into an integer?  Use ROUND, i.e. ROUND(3.1416 * N100).  This will give you more precise answers on that Least Significant Digit.

So, your final expression should be:

MAX(-32768, MIN(32767, ROUND(3.1416 * N100)))
Title: Re: Integer MATH Issue
Post by: Mike Nash on August 21, 2015, 08:50:08 PM
So when do we get a nice clean instruction that knows N's are -32768 to 32767 and V's are 0-65535, no more and no less? Hint, hint.

This one hasn't gotten me before because I have used reals or DINTS from the start with Do-more. Yes I realize about the "not exact" issue with the reals and I am OK with that. I just thought it odd that it was only 10000 that was an issue in this case and that D101 did not match V101 for N100 = 10431. But now I have gone back in and tried all of this again except using two copies of v1.4 instead of v1.3 and both the simulator and a real H2-DM1E (still at 1.3) both give the same result of 32770. I guess I'll have to close those and try in v1.3 again.

BTW ROUND does work, but it makes a lot of the results for the other device not match the Do-more results rather than just the one at 10000. I think that's on the other end. Just can't win. ;) That was all just playing with the Modbus/TCP and doing it over VPN and learning how to send emails and all of that other fun stuff.

Thanks for the help. I did look in the help files and didn't see any mention of that behavior before I posted. That was one advantage of BCD. I knew where I was going to need a double ahead of time, because of well... experience from slogging through all the possible mistake iterations.

So I went back and tried v1.3 and the oddball 32769 for D101 didn't occur. Strange. Maybe I was bitten by the "not starting from scratch" thing again as I know it was there earlier.
Title: Re: Integer MATH Issue
Post by: BobO on August 21, 2015, 11:53:20 PM
So when do we get a nice clean instruction that knows N's are -32768 to 32767 and V's are 0-65535, no more and no less? Hint, hint.

I haven't been following this that closely, but are you wanting to limit the MATH result to the target element's range, rather than the normal behavior of just grabbing the lower n bits?

Franj...maybe we could look at adding a flag to the MATH box that would use an alternate bounded output instruction. I suspect our C/C++ view of the world violates the mental model of many PLC users, and a bounds limited output would more directly fit their view of the problem. Controller side would be pretty easy.
Title: Re: Integer MATH Issue
Post by: Mike Nash on August 22, 2015, 10:31:09 AM
I haven't been following this that closely, but are you wanting to limit the MATH result to the target element's range, rather than the normal behavior of just grabbing the lower n bits?

Franj...maybe we could look at adding a flag to the MATH box that would use an alternate bounded output instruction. I suspect our C/C++ view of the world violates the mental model of many PLC users, and a bounds limited output would more directly fit their view of the problem. Controller side would be pretty easy.

I'm not sure I understand exactly what you were asking/suggesting to Franj. I think for my part if it had to be either 1) it limits or 2) it simply masks the output, I would choose limits for WX, WY, N and V type registers. We could always bit-wise AND (&) a D type to get the lower bits only.

Having a tick box in the MATH instruction to select results type would be cool. Or even rolling that MAX-MIN into a new instruction that could be used inside the MATH box (Or Outside even) that cleaned it up (so it is more obvious what you are doing) would work. Oh wait, CLAMP works for outside the MATH instruction, but it requires an extra memory word for the intermediate result.

I'm hoping others chime in on what they would like/expect here. Process control type work often ends up with results going beyond the allowed range and in those cases clamping is best (like say a PID output that "rolled over" and then gives a bogus output rather than clamping at MIN or MAX.) Really, the only time I would use N or V is when I need to send results or get input from some other device that only has those data types.

You know, while I am wishing, if we just had the ability to throw in our own limits clearly in the MATH instruction, this would be huge for the type work I do. Quite a bit of my ladder gets devoted to range checking before the math or clamping afterwards that it gets hard to find the trees for the forest. Something like the CLAMP instruction but the INPUT is a MATH type box.

In the meantime, I'll be using that MAX and MIN logic, it's just a little harder to read quickly.
Title: Re: Integer MATH Issue
Post by: Controls Guy on August 22, 2015, 11:39:26 AM
Some of this stuff goes away once we can do our own boxes.   If you find you do scaling with clamped outputs a lot, write a box and name it!  I'd rather see that (and left rail boxes that produce an output leg) than a lot of enhancements to existing instructions, cause that solves more problems.  I've been doing that in Siemens TIA, and it really cleans up the programs.
Title: Re: Integer MATH Issue
Post by: BobO on August 22, 2015, 11:41:20 AM
I'm not sure I understand exactly what you were asking/suggesting to Franj. I think for my part if it had to be either 1) it limits or 2) it simply masks the output, I would choose limits for WX, WY, N and V type registers. We could always bit-wise AND (&) a D type to get the lower bits only.

Having the following selected by a flag:
Normal Behavior: N0 = TopOfStack:W0
Optional Behavior: N0 = CLAMP(TopOfStack, -32768, 32787)

The optional behavior would be completely generalized to the range of the target element.

Having a tick box in the MATH instruction to select results type would be cool. Or even rolling that MAX-MIN into a new instruction that could be used inside the MATH box (Or Outside even) that cleaned it up (so it is more obvious what you are doing) would work. Oh wait, CLAMP works for outside the MATH instruction, but it requires an extra memory word for the intermediate result.

I'm hoping others chime in on what they would like/expect here. Process control type work often ends up with results going beyond the allowed range and in those cases clamping is best (like say a PID output that "rolled over" and then gives a bogus output rather than clamping at MIN or MAX.) Really, the only time I would use N or V is when I need to send results or get input from some other device that only has those data types.

You know, while I am wishing, if we just had the ability to throw in our own limits clearly in the MATH instruction, this would be huge for the type work I do. Quite a bit of my ladder gets devoted to range checking before the math or clamping afterwards that it gets hard to find the trees for the forest. Something like the CLAMP instruction but the INPUT is a MATH type box.

In the meantime, I'll be using that MAX and MIN logic, it's just a little harder to read quickly.

I am also a fan of adding a CLAMP(Exp, Min, Max) instruction to the MATH box. It wouldn't be hard since it follows the same pattern as the IF() instruction.

The justification for the flag to limit to the target range is just simplicity. The way Do-more works is pretty consistent with the way high level languages like C/C++ do things. One difference is that we automatically promote all integers to 32 bit signed as they are pushed to the stack, while C/C++ would not promote until you used a larger size in the expression. The output behavior of just grabbing the lower n bits is the same. C/C++ would give you a compiler warning, but processes it the same way Do-more does. While that is the way the wide world of C/C++ programmers do it, that probably doesn't fit the mental model of many PLC programmers. The optional behavior I mentioned would likely better fit their view of the problem.


Changing the subject slightly...

Host has recently become acutely aware of the fact that, as developers, we do not see the world the same way our users do. While we've always known that, the "acute awareness" is in us finally seeing that to the extent that we can adapt the product to the user's mental model, the product becomes more intuitive.

Do-more is powerful. Do-more is extensive. Some might argue otherwise, but I don't think Do-more is particularly 'hard', in that once you know how something works, it isn't difficult to use...but...some of it is not as intuitive as it could be. Our question over the next year or so is to identify as many un-intuitive things as possible and make them more so. I would love any feedback y'all are willing to give.

In the end, a user's satisfaction with a product is directly related to how well the product solved their problem and how pleasant the experience doing so was. We see a very common thread with Do-more users: It takes them a bit to learn the Do-more Way, but once they do, they are very satisfied with it. Our goal is to eliminate the first part of that and move straight to the second.
Title: Re: Integer MATH Issue
Post by: BobO on August 22, 2015, 11:46:18 AM
Some of this stuff goes away once we can do our own boxes.   If you find you do scaling with clamped outputs a lot, write a box and name it!  I'd rather see that (and left rail boxes that produce an output leg) than a lot of enhancements to existing instructions, cause that solves more problems.  I've been doing that in Siemens TIA, and it really cleans up the programs.

I don't disagree...but...some of these enhancements are simple things that help a wide range of users. User instructions are certainly the most flexible, but there is a pretty substantial group of users that aren't to that level.

Left rail boxes? Have you mentioned that before? If so, I've missed it.
Title: Re: Integer MATH Issue
Post by: Mike Nash on August 22, 2015, 12:17:03 PM
Some of this stuff goes away once we can do our own boxes.   If you find you do scaling with clamped outputs a lot, write a box and name it!

Yeah, I did this with RSLogix 5000. That was sweet and is why I would like Do-more to have Add On Instructions. But having to do that is just so irksome since it seems like an obvious desire/need coming from the analog world only to find just "wrong" behavior in the digital world. 32767 + 1 should not be a negative number result.

Having min and max output clamps just right there and ready in the MATH box would be SOOOO clean.
Title: Re: Integer MATH Issue
Post by: Mike Nash on August 22, 2015, 12:24:58 PM

Having the following selected by a flag:
Normal Behavior: N0 = TopOfStack:W0
Optional Behavior: N0 = CLAMP(TopOfStack, -32768, 32787)

The optional behavior would be completely generalized to the range of the target element.

Yes please!


Quote
I am also a fan of adding a CLAMP(Exp, Min, Max) instruction to the MATH box. It wouldn't be hard since it follows the same pattern as the IF() instruction.

Yes please!


Quote
In the end, a user's satisfaction with a product is directly related to how well the product solved their problem and how pleasant the experience doing so was. We see a very common thread with Do-more users: It takes them a bit to learn the Do-more Way, but once they do, they are very satisfied with it. Our goal is to eliminate the first part of that and move straight to the second.

And yes it is a pleasure to use. That's why I have been playing with it while on vacation.  ;D
Title: Re: Integer MATH Issue
Post by: Controls Guy on August 22, 2015, 01:45:51 PM
I don't disagree...but...some of these enhancements are simple things that help a wide range of users. User instructions are certainly the most flexible, but there is a pretty substantial group of users that aren't to that level.

Granted.  I realize there's an order of magnitude difference in complexity between the two enhancements, both for you to build and for people to use, but I bet it will diminish requests like this once you can do it.

In a sense this mirrors my experience with Siemens vs Do-More.  They lack a lot of the built-in stuff that Do-More has, like statistical stuff like average and stdev, so I had to write my own.  (I've also used user boxes for general purpose recurring ladder snippets like debouncing or interpolating a pulse input)  More flexible in the long term, but at the very moment you run into the need for the first time, it's more time-consuming.  (Also their MATH box, while a big advance since they never had one at all before, is not as good as yours or AB's)

Siemens also adheres to the GE paradigm where every box has one or more inputs and one or more wireable outputs, so there's not such a strong distinction between left and right-rail boxes in that concept.  You often end up stringing boxes horizontally with the output of one feeding the input of the next.  I'm not advocating it at all, just noting that it's a little different concept that makes less of a distinction between left and right-rail boxes.

Quote
Left rail boxes? Have you mentioned that before? If so, I've missed it.

Nope!  What Mike was talking about reminded me of built-in AB left rail boxes like LIM, which has a max and min, so it's two compares in one box.  There are always going to be things that other brands have built-in that your own brand doesn't, but the idea of user-defined left rail boxes occurred to me as a way to get around that (and far past that in fact).
Title: Re: Integer MATH Issue
Post by: Controls Guy on August 22, 2015, 01:48:13 PM
I am also a fan of adding a CLAMP(Exp, Min, Max) instruction to the MATH box. It wouldn't be hard since it follows the same pattern as the IF() instruction.

I really like that solution.  It empowers the MATH box without cluttering the UI.  Very cool.