LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Change/add math vi's to prevent rounding errors

I still disagree that this issue has anything to do with NI.

You admit yourself it's possible to write your own VIs, and have already done so.

If you're using a certain set of tools, you need to be aware how they work, and how they don't work.  Othewise things go wrong.

Floating point numbers are a numeric tool.  They allow for usage of a large numeric range with the offset that many values are only approximations.  You can't have one without the other at the moment (Who known what the future holds).  We as programmers need to know where the limitations are and code appropriately.

Your gripe seems to be more on the actual nature of IEEE754 nomenclature.  This has nothing whatsoever to do with NI, it's an internationally accepted standard way of doing things.

Generally, if absolute comparisons (Q&R would fall into this category if you can't accept the results rounding gives you) are needed, one generally tries to stick to integer values (A U64 stretches to 19 digits).  It requires thinking more about how to handle your numbers, but it generally is easier than making a whole set of workarounds like this.

Having polymorphic VIs to switch between an accepted internationally recognised numeric operation and a wholly non-standard operation is a very bad idea.  It sounds like a very Microsoft way of doing things (And that's not meant in a good way).

Please re-evaluate your code to see if you can't use integer math to solve your problems.  It seems like you're complaining because you're actually using the wrong tools for the job.

Shane.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
0 Kudos
Message 31 of 45
(1,639 Views)
Hi Anthony,

to keep up with Shane suggestion... Your problem is like this:
You want to have numbers with high precision (doing math and comparisons) but you use a limited precision datatype. Now you're complaining about problems arising from this limitation...

So the solution would be to use some datatype that gives you the needed precision. This could be some (U)Int with a fixed-point arithmetic. There are also software packages allowing for arbitrary precision (i.e. here or here). But still my advice is: make up your own subvis giving you the precision you need. No need to change standard functions...
Best regards,
GerdW


using LV2016/2019/2021 on Win10/11+cRIO, TestStand2016/2019
0 Kudos
Message 32 of 45
(1,631 Views)
Somehow I thought this was going to become another back and forth debate over something that one person found that he needs and feels should be implemented as a general rule. I did wonder whether this was going to become another 9-page thread that didn't seem to come to any conclusion.

The crux of the matter seems to be that Anthony doesn't like the way the built-in operations work. He claims they're wrong/imprecise/misleading/whatever. Others say they're not, and that they operate exactly the same way as other programming languages, so there's no need to mess with them. He believes there should either be "rounded" versions of some of the operators, or a way to configure the operators such that you select which way they operate. He believes that it would improve the LabVIEW language, and as such, believes it's in NI's interest to add this functionality. Others say that you shouldn't mess with the built-in operators, and that if Anthony doesn't like the operators, he should write his own (which he already has), preferably under open source, like the OpenG libraries so others can use them.

Have I missed anything?

Assuming I haven't, who's right? Well, if I may dare, both sides are right. And I think that's where the problem lies. Do the operators behave in an unexpected manner under certain circumstances? Depends on what you're expecting, doesn't it? So, to claim that they're wrong/imprecise/misleading/whatever, or that they're right/precise/predictable/whatever isn't the real question.

In my second response I asked:

    "I think that the original point of your message should be the focus here: whether there is a benefit in providing alternate versions of some of these primitives"

Anthony's argument seems to be that he thinks there is. Others say that there isn't, using the "don't mess with the existing functions" argument as the counter-argument, or that it will simply confuse people to have two versions of functions. In my mind, the real question is whether or not it's beneficial for NI to spend the time investigating, debating, and implementing this issue, which will clearly cause even more consternation in the general public if this discussion is any indication, or whether Anthony should simply provide alternate versions of these operations and make them available under open source so they can be tested and refined.

Personally, I'd rather have NI spend the time on other issues, as this issue is far bigger than LabVIEW, as has been pointed out already. So, in the interest of dousing a few flames, may I humbly say that I think Anthony provides a reasonable point as to the need, however small (sorry, Anthony, but I think you really are in the minority on this one), for alternate ways for the operations of these functions to make them work a little more like "regular" math on paper. I agree with the already mentioned route of simply providing these functions under open source. This way, those who need them can use them. Everybody else can be sure that they're using operators that work exactly the same way as they do in other programming languages. Yes, it's true that they probably won't be as fast as what NI would be able to implement as native primitives, but there's practical issues to consider here, and like I said, I would rather have NI spend its time on other matters.

Anthony, a suggestion: I think some of the strong anti responses you got were caused by your original stance:

    "Although the Labview math VI's follow the IEEE standards, this makes for some completely useless VI's."

This is not a good way to start a discussion, whatever your personal/professional feelings may be on the way the operators work.


OK, time for me to get off the soapbox. Next...
0 Kudos
Message 33 of 45
(1,607 Views)

In hopes of making progress on the technical aspects of implementation, I did a little playing around with the modified Q-R posted earlier in the thread.  Some observations / questions / comments:

1.  My own preference for handling negative x and/or y terms is not always the same as that produced by the floor() rounding function.  I would personally like to optionally specify the use of a "round toward 0" vi in place of the floor() function.  [My simple implementation of "round toward zero" is to compare the input >= 0.  If true use floor(), if false use ceil().]

   Example:  I've had apps with encoders measuring cumulative angles over thousands of revs.  I have a custom control that contains a simple numeric and a round dial guage.  If I start at position 0 and rotate +390, the Q-R will break that down as +1 rev and an additional  +30 degrees.   If I were to rotate by -390, the floor() version of Q-R would break that down as -2 revs and an additional +330 degrees.  In these cases, I'd prefer a "round-toward-zero" version of Q-R that would report -1 rev and an additional -30 degrees.  

   I would propose this as a non-default behavior that can specified on an input terminal of a modified Q-R.    Unless there are specific compelling mathematical reasons why "remainders" should only be expressed as values >= 0...

   That would cover the negative numerator case for me.   Negative denominators would also need to be handled in a clear, consistent way but I myself can't think of a use case for them and have no reason to suggest any different treatment than outlined above.

2.   Using specified # of significant digits does a nice job of producing an expected integer quotient.   However, I'm not so sure about the way a remainder term can have a value many orders of magnitude smaller than the rightmost significant figure of the numerator.  

Let's say your numerator is in the order of 10e6 and denominator is order of 10e0.  You specify 10 significant figures.  Ok, you get your quotient,  round to 10 significant figures, then round to integer.   Then, to find the remainder, you subtract IQ * denom from numerator.   So now you've got a subtraction of two values in the order of 10e6.   In some cases, the result may be a difference in the order of 10e-9 which is reported as R, the remainder.

     So, we've specified that we only want to consider 10 significant figures when computing the integer quotient IQ.  But our remainder R demonstrates that when subtracting order 10e6 values, we treated order 10e-9 values as significant, implying 15 significant figures.  Wouldn't it be more consistent to round off the R term after subtraction at the 10e-4 place, which is 10 significant figures over from the order 10e6 values being subtracted?

    I've gone back and forth on this, but I lean toward thinking that if there's a modified Q-R with an input spec about significant figures, then the rules for significant figures should be followed both for the division which produces the IQ term *AND* for the subtraction which produces the R term.

3.  What are good defaults for the # of significant figures to use for DBL's?   I mostly deal with measurement data.  The stuff that comes off an A/D converter rarely has more than 5 or 6.  However, if I measure encoder angles in degrees, significant digits aren't really the best measure of precision.  Instead I get absolute precision down to a specific power of 10 decimal position, like maybe the 10e-3 place.   The number of additional significant digits to the left of the decimal is, in principle, unbounded.

     Other considerations are the amount of error that can creep into the low-order bits from other common processing functions.   I think of filters first, though a good argument can be made that the choice to perform filtering  implies a wanton disregard for the original data's lowest significant digits anyway. 

-Kevin P.

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 34 of 45
(1,586 Views)
This post is getting pretty hypothetical.

Kevin, I still have a strong suspicion that simply limiting the "significant digits" won't work bacause what happens when X.999...99 gets rounded to (X+1).000...01?

I find the discussion around the fact that the NI primitives being "wrong" and "unacceptable" to be outright silly.
I regard the question as to whether NI should do this for us as unfavourable compared to NI spending time on bug-fixes.  Lots of bug-fixes because this is NOT a trivial task to do properly.
I also find the discussion in general about the pitfalls of floating point numbers in itself very helpful, because it highlights something too few people really understand as this post truly illustrates.
Finally, every programmer should understand the bits of what he's doing on this level.  People should understand floating point notation and how it works.  This is akin to a mechanic knowing how an oil filter works.  It's just something which should (in my opinion) be a gimme.

Once again, use the right tool for the job.  If you can't deal with approximations, do integer math.

Shane.

PS IEEE754 is currently under revision.  Have a look at IEEE754r.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
0 Kudos
Message 35 of 45
(1,579 Views)
Shane,

I'd rather have NI worry about other bigger things too.  I'm just using this thread as a sandbox for attempting to hash out an attempt at a decent user-defined implementation that could be proposed for OpenG.  I share concern about corner cases and unanticipated odd behavior.  I'm not confident that I myself would come up with the ideal implementation, so I'm hoping to suck a little mindshare out of others who follow the thread.

I'm intentionally focusing on implementation details with hopes of derailing the opinion-slinging... Smiley Wink

Shane wrote: "Kevin, I still have a strong suspicion that simply limiting the "significant digits" won't work bacause what happens when X.999...99 gets rounded to (X+1).000...01?
I'm not sure I follow.  Signif digits aren't just truncated, there's a step of rounding to integer.   And integer values can be represented exactly in floating point.  (Right?  Maybe I need to look at the raw bit patterns...)   .   Maybe the modified Q-R should return an integer datatype for IQ?

One other point I've been kind of assuming but which should be stated -- these kind of rounding functions don't generally belong in the middle of a calculation chain. They should be at the end, just before displaying a result or writing to file or something.

-Kevin P.




ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 36 of 45
(1,551 Views)
Kevin,

Yes, everything possible in a I32 can be represented in a DBL which has 56 bits for it's mantissa.  But a I64 can't be.  AFAIK, the EXT on Intel has just enough to cover a I64 (63 bits mantissa and 1 sign bit).  If you have a DBL representing a value bayond the bounds of its 56 bit mantissa, then NO it cannot be represented exactly by a DBL.  Even a whole number MAY be rounded to the next nearest floating point number and the fun begins (powers of two are quite resilient to rounding).

These values are only useable if there is no fractional part to the number.  Once even a single digit enters the equation after the decimal point, this is no longer guaranteed and we've entered real floating point space.

I had a problem with this years ago where I was reading a file index from a header.  I didn't check that I was reading it as SGL and was left scratching my head that certain file indices (seemed intermittent) were being loaded wrong.  Turns out I ran into exactly this problem.  I was reading my Index shifted due to approximations within the SGL data type.  I'll never forget it since that happened 🙂

I guess I maybe misunderstood what was meant by hacking off significant digits.  I understood it as simply ignoring 1 or 2 LSBs of the mantissa.  In this case, I still think it can lead to persistent errors.  The rounding is not that easy to circumvent I reckon.

Bearing in mind that the norm at the heart of all this IEEE754 is in revision, maybe we should pay THAT some attention instead of this topic......

Shane.
Using LV 6.1 and 8.2.1 on W2k (SP4) and WXP (SP2)
0 Kudos
Message 37 of 45
(1,540 Views)
For people who want to use the vi's discussed.  I have the latest versions here.  
 
changes:
  • Quotient and Remainder:   Added choice for 'round toward - infinity'  or 'round toward zero' like Kevin suggested.
  • Round to # sign. digits:  The vi uses the floor operation itself, and thus needed an extra safeguard.  Changed the icon.   

I think both vi's should be completely safe now.  I did some testing, and both are still very fast, especially considering the typial usage.

For easy use with the comparison primitives, I added a 'Round two values to # sign. digits', so that you can easily create the following construction:

I think that's a nice small construction, which make it easy to use.   This prevent having to make a complete set of replacement vi's.  Now, you can't do this trick for QR, so that still needs to be replaced completely.  

I wonder... is it possible to make a polymorphic vi like 'build array' yourself, where you can pull to make it bigger?  

0 Kudos
Message 38 of 45
(1,510 Views)
Hi Anthony,

can you add LV8.2 versions as well?
Best regards,
GerdW


using LV2016/2019/2021 on Win10/11+cRIO, TestStand2016/2019
0 Kudos
Message 39 of 45
(1,505 Views)

Ah yes...  I every time forget about this Labview version thing.  I'll better post Labview 8.0 versions, otherwise I get that a request for that one as well.  Smiley Wink

P.S.  because I frequently use values with units, I choose to add a polymorphic units to the round vi's.

0 Kudos
Message 40 of 45
(1,499 Views)