Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cordic chapter: rounding requires corrections #21

Open
japm48 opened this issue Mar 14, 2021 · 3 comments
Open

cordic chapter: rounding requires corrections #21

japm48 opened this issue Mar 14, 2021 · 3 comments

Comments

@japm48
Copy link

japm48 commented Mar 14, 2021

I believe there is misleading or even factually incorrect info in "3.5.3 Overflow, Underflow, and Rounding". I think most of that is because in the examples only one bit is dropped and then half of the cases are ties.

In particular: the behaviour of round() and lrint() (for lrint we have to assume FE_TONEAREST mode is set, more info here) are actually rounding to the nearest integer and they only differ in the case of ties.

All the variants are well explained in: https://en.wikipedia.org/wiki/Rounding#Rounding_to_integer

@japm48
Copy link
Author

japm48 commented Mar 14, 2021

I provide here a quick explanation (you are free to copy it if you wish). To avoid confusion I believe it is better to think that the output is an integer (the radix point is after the last digit), instead of a fixed-point number, so the difference is just a simple shift.

First, there should be a distinction between directed rounding (i.e. towards or away from a reference value), and rounding to the nearest integer (or nearest representable number if we are dealing with fixed-point numbers).

In directed rounding we have:

  • round towards negative infinity: floor. -1.4 → -2, 1.5 → 1
  • round towards positive infinity: ceiling. -1.4 → -1, 1.5 → 2
  • round towards zero: truncate. -1.4 → -1, 1.5 → 1
  • round away from zero: does not have a dedicated C function, this would behave like -truncate(-x). -1.4 → -2, 1.5 → 2

All of these methods introduce a bias (average error).

For nearest integer rounding methods, the bias is a lot smaller than directed rounding. There are many variants, but all of them produce these example results: -1.3 → -1, -0.7 → -1, 1.6 → 2, 2.1 → 2.
The difference only occurs when there is a tie.

Some of them are:

  • round half towards positive infinity: -0.5 → 0, 1.5 → 2
  • round half towards negative infinity: -0.5 → -1, 1.5 → 1
  • round half away from zero, this is round(): -0.5 → -1, 1.5 → 2
  • round half to even (*rint with fesetround(FE_TONEAREST)): -1.5 → -2, -2.5 → -2, 1.5 → 2, 2.5 → 2

Also, it would be interesting to explain the Quantization Modes in Vivado HLS.

@stephenneuendorffer
Copy link
Collaborator

Hi, Thanks for the comment! It's not clear to me what exactly you're suggesting is incorrect? You're probably right that we should clarify that lrint() uses the currently set rounding mode, so we've assumed that the default rounding mode has not been changed. I see a few other things that could potentially be cleaned up here, but I think they are more clarity issues than anything else. One of the challenges in this section is to try to identify some correspondence with IEEE rounding modes (both directed rounding modes and round-to-nearest-even), while not suggesting that ap_fixed implements the IEEE standard. I think a few more examples might make it easier to see the patterns in how these different rounding modes work, but one of the key things I was trying to get across in this section is that rounding modes can be extended to work on fixed-point numbers.

@japm48
Copy link
Author

japm48 commented Mar 27, 2021

My apologies, I completely forgot to answer.

we've assumed that the default rounding mode has not been changed

You are right, that's the default rounding mode for lrint(), I didn't know that. To my defense: apparently, there is no default defined in standard C (and possibly in C++), although different default modes are pretty rare.

One of the challenges in this section is to try to identify some correspondence with IEEE rounding modes (both directed rounding modes and round-to-nearest-even), while not suggesting that ap_fixed implements the IEEE standard [...]

Good point.


What I think is misleading are the following parts:

or to larger absolute values (called rounding away from zero or rounding to
infinity and corresponding to the round() function)).

This is presented as the opposite of trunc which is "round away from zero"; this is actually incorrect as there is no function (AFAIK) to do that. round() is actually "round half away from zero" which only behaves as suggested for interval midpoints, for the rest of values it returns the nearest representable number.

And also:

A better approach is called rounding to nearest even,
convergent rounding, or banker's rounding and is implemented in the lrint() function.

Similar argument: this is a variant of round() (i.e. round to nearest) where the only difference occurs for midpoint values. The majority of the error minimization comes from selecting the nearest number, not because it selects even numbers in case of a tie (although it is true that for this reason, it is slightly better than round()).

Also, I believe that in

None of these operations always minimizes the error caused by rounding, however.

it should be more precise to say "average error" or "error bias" instead of just "error".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants