Skip to content

Change AFix division #1722

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

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open

Change AFix division #1722

wants to merge 1 commit into from

Conversation

thajohns
Copy link

@thajohns thajohns commented May 2, 2025

Context, Motivation & Description

The AFix / operator appears to have not been changed since the original implementation of AFix, and I'm skeptical that it was ever used -- its range and exponent on the result didn't really make sense.. It includes a warning against its use. I have changed it to be suited to the use I need it for, but left the warning in place.

I don't have time to write a unit test right now, but it might be in a followup PR if I can find the time. The best I can say about it is: it works in simulation as part of a codebase that I unfortunately cannot share.

Checklist

  • Unit tests were added
  • API changes are documented

@thajohns
Copy link
Author

thajohns commented May 2, 2025

Also, there's not an obvious answer to what the semantics of AFix division should be. I think it's clear that the exp of the quotient should be something from the dividend minus something from the divisor. It might make sense to pad out the dividend so that the quotient's exp is dividend.exp - divisor.maxExp; but right now the use can do that by padding the dividend first, whereas if it were moved into this function the user wouldn't be able to do what this function does now.

@Dolu1990
Copy link
Member

Dolu1990 commented May 3, 2025

and I'm skeptical that it was ever used

Right ^^

Also, there's not an obvious answer to what the semantics of AFix division should be

I agree.
Hmmm, what's about the division require the user to expliclitly specify the AFix format he want the result in ?
So in other words, the division function take no decision, and only follow parameters specified.

@thajohns
Copy link
Author

thajohns commented May 4, 2025

Hmmm, what's about the division require the user to expliclitly specify the AFix format he want the result in ?
So in other words, the division function take no decision, and only follow parameters specified.

Such as in fixTo()? I think that's not a great idea, because I at least often use arithmetic functions like this one to construct new types, such as the one that would be an input in this case. Also, having such a third argument would preclude / being a binary operator, right? That being said, it certainly makes sense to have an additional function that divides to a desired range and precision.

I haven't looked at any good examples of how this has been done elsewhere, and I don't have a good answer to how it should be done, but here are some of my thoughts on what might be a good default behavior of the / binary operator:

Quotient Representable Range

Since we know the representable range of the dividend and the smallest nonzero value of the divisor, there's an obvious candidate for the representable range of the quotient. Division can produce some very large numbers over a very small part of its domain, unlike other operators. However, in most real-world uses of fixed-point division, the divisor probably never approaches zero too closely (i.e. no singularities). So, a careful user could use the minValue (or maxValue) of the divisor to limit the representable range of the quotient. Unfortunately, in this implementation, I didn't take that detail into account (in fact, I hadn't thought of it until now), but it should probably find its way into the final form of this function.

There are certainly some applications where we don't want that entire range, but one could make the same argument about * or any of the other binary operators -- and in those cases, the saturation is left to the user. I think we should do something similar with /.

Quotient Precision

Obviously some sort of compromise has to be made since divisions can produce arbitrarily precise nonzero bits. In this PR, the number of bits of the quotient is the same as that of the dividend. A user who wants more precision can pad the dividend out (e.g. (dividend <<| padBits >> padBits) / divisor -- I couldn't find a better way). That might work if adapted for the small representable range of the divisor described above.

The conventional rules of significant figures, where the number of digits of a quotient is the minimum of the number of digits in the two operands, don't seem appropriate here, since one could imagine a division by a small integer, for example, where the result should still have many digits. (Of course, one could add trailing zeros to the integer to indicate that it is precisely an integer, but that seems unnecessary.)

Some ideas that seem reasonable:

  • for each order of magnitude (base 2) of the divisor, have a range of bits with the width of the divident. The ranges of bits overlap, so quotients.numWidth = dividend.numWidth + (number of orders of magnitude of range of divisor). I believe this is on the cusp of being precise enough to have the property that, for all dividends, the leading nonzero bit of the divisor can affect the quotient.
  • quotients.numWidth = dividend.numWidth + divisor.numWidth. (That's equivalent to a range of divisor.numWidth + (number of bits in the least precise representable order of magnitude of the divisor) bits for each order of magnitude of the divisor.) If my reasoning is right, this is on the edge of having the property that, for all dividends, changing any bit of the divisor can affect the quotient.

I'd love to hear others' thoughts on those possibilities.

@Dolu1990
Copy link
Member

Dolu1990 commented May 8, 2025

Also, having such a third argument would preclude / being a binary operator, right?

Yes

That being said, it certainly makes sense to have an additional function that divides to a desired range and precision.

Right, i think the API should have started from that end instead of having a "/" operator.

Division can produce some very large numbers over a very small part of its domain, unlike other operators

Right, that make it very special. And make me think that there is no good compromise, excepted explicitly asking the user which range he want the result in. Just providing a "/" operator is too "handwavy".

Some ideas that seem reasonable:

Hmm, those could be additional function / operator, which internaly use the explicit division function (the one with with explicit range)

So overall, no "/" operator, but instead one very explicit division function, and posibly other precooked alternative division function (which use the explicit division internaly)
?

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

Successfully merging this pull request may close these issues.

2 participants