I've been working on an arbitrary-precision floating-point package and tried to make it compliant with the FloatingPoint protocol and quickly realized it wasn't possible.
For example, what is the value of pi when you have arbitrary-length numbers? Should I even attempt to adhere to a protocol? Is there anything in place for arbitrary-precision numbers? So far, I haven't found anything. If anyone has been working in this area, please share.
Such a protocol would need, at a minimum, to allow calculations to a given precision using a specified rounding mode. Any operations, such as calculating pi, would need to support this requirement. As well this new protocol would be independent of a particular numeric radix, much as the existing FloatingPoint protocol. Obviously there can be no maximum number with arbitrary precision, nor do methods like next larger number seem to apply. What would be appropriate parameters to characterize arbitrary-precision floating-point numbers? Generally they do all seem to have a limited size exponent, typically an Int, so perhaps a minimum and maximum exponent might be useful?
I think you'd have to decide on a value of Self with sufficiently high precision, suitable for most of your use cases. The protocol requirement is static and since the real value of π obviously can't be represented with finite precision, you'd have to make some best effort at a value that users of your library can live with. And document your decision.
I guess I'd just implement .pi as a static var with some well-documented value, and then additionally provide a static pi(precision:) function for users who care. I guess consumers of your library would probably write:
let diameter: ArbitraryPrecisionFloat = ...
let circumference = diameter * .pi(precision: diameter.precision)
Rather than using some third party generic algorithm over floats which uses .pi implicitly.
Another option is to implement these constants using some alternate backing with deferred calculations, and then use same-precision semantics which derives the precision from the other operand in the implementation of your arithmetic operators.
So, in essence, you're suggesting having a static precision that is user adjustable either by recompiling the library with a different precision or is dynamically settable.
In some ways, this would address the protocol issues I was having by making everything dynamic based on the user-selected precision.
This is the approach that is currently implemented in the library I found and am planning to modify. The Java arbitrary-precision libraries also seem to take this approach. An advantage here is that you can still support your first approach with an implied global precision while still allowing users to dynamically change the precision when they wish.
As an example, many arbitrary-precision algorithms use a dynamic precision approach that starts with a low precision that gradually increases as the required precision is approached with an iterative algorithm. Using dynamic precision apparently saves a lot of calculation time over just having a fixed precision set to the maximum.