apple / swift-numerics

Advanced mathematical types and functions for Swift

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature request: GCD for floating-point

wadetregaskis opened this issue · comments

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?

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.

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

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.

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.

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.

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.

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.