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

Feature request: GCD for floating-point #279

Open
wadetregaskis opened this issue Feb 2, 2024 · 7 comments
Open

Feature request: GCD for floating-point #279

wadetregaskis opened this issue Feb 2, 2024 · 7 comments

Comments

@wadetregaskis
Copy link

Surprisingly, I can't find any implementation of floating-point GCD for Swift, anywhere.

While there are implementations in other languages - Python has heaps - a lot of them gloss over the important detail of rounding. And for those that don't, porting them to Swift too literally may introduce mathematical errors, depending on how the source language differs from Swift in its handling of reals.

Since this library already has a good GCD implementation for integers (which seems to be a prerequisite for a floating-point variant), perhaps it'd make sense to add a version for FloatingPoint?

@stephentyrone
Copy link
Member

It's not too hard to implement--the usual algorithms can be made to work--but I'm curious what you intend to use it for, since that might influence how we'd expose it.

@stephentyrone
Copy link
Member

Also, what do you expect to happen when one of the values isn't an integer?

@wadetregaskis
Copy link
Author

wadetregaskis commented Apr 24, 2024

My use case is for reverting NSImage's conversion of animation timing information (expressed by NSImage as NSTimeInterval) back to its natural form (integer measures of counts over a timescale). I want to simplify the fraction back to its natural form, which means finding the greatest common divisor (given a small amount of fudge allowance, to compensate from rounding errors introduced by AppKit).

e.g. if the duration of two frames is reported by NSImage as 0.06666666667 and 0.1333333333, I want to determine that the timescale is 15 and the frame durations are 1 and 2, respectively.

The fudge allowance is crucial by the very nature of floating point, which is what makes this notably less trivial than working with integers.

@stephentyrone
Copy link
Member

I think I might prefer to do that via two simpler operations:

  • convert floating-point to simplest rational approximation satisfying some error bound
  • find LCM of denominators

My intuition is that these are much more explicable building blocks than a magical GCD with fudge factor, but I'm open to being convinced.

@wadetregaskis
Copy link
Author

I think that makes sense. Simplifying integer fractions is a common need too.

But, that's essentially what I'm currently doing and it's maybe not perfect. As two separate steps, the degree of approximation used in the conversion to integers is essentially arbitrary. Ideally it'd be just enough - and no more - to produce a sufficiently simple fraction at the end. e.g. 1/15 instead of 9/150.

Of course, there's seemingly always some degree of arbitrariness in this, because you have to pin down what a "sufficiently simple" fraction is. But in some contexts that can have hints - e.g. for animations, as in my use case, it's much more likely that the denominator will be 15, 24, 25, 30, or 60, than any other numbers. Especially larger numbers.

@stephentyrone
Copy link
Member

For this specific use, you can probably first multiply by 300 and call it a day if the result is sufficiently close to an integer, short-cutting all the rest.

@wadetregaskis
Copy link
Author

That was my workaround initially, essentially (I used a million or thereabouts, not 300, but same idea). It works pretty well but isn't perfect.

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