swift-numerics icon indicating copy to clipboard operation
swift-numerics copied to clipboard

Feature request: GCD for floating-point

Open wadetregaskis opened this issue 1 year ago • 7 comments
trafficstars

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?

wadetregaskis avatar Feb 02 '24 03:02 wadetregaskis

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 avatar Apr 15 '24 18:04 stephentyrone

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

stephentyrone avatar Apr 24 '24 12:04 stephentyrone

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.

wadetregaskis avatar Apr 24 '24 16:04 wadetregaskis

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.

stephentyrone avatar Apr 24 '24 20:04 stephentyrone

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.

wadetregaskis avatar Apr 24 '24 20:04 wadetregaskis

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.

stephentyrone avatar Apr 24 '24 20:04 stephentyrone

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.

wadetregaskis avatar Apr 24 '24 21:04 wadetregaskis