Floating point numbers with arbitrary radixes (may be negative or nonreal)
julia> using ArbRadixFloatingPoints
julia> radix = 2 - im; precision = 16; num = 5 + 3im;
julia> y = convert(ArbRadixFloat{radix, precision}, num) #Convert a number into an ArbRadixFloat
(1̅.232222222222150)₂ ₋ ₁ᵢₘ × (2 - 1im)²
julia> float(y) #Conver an ArbRadixFloat back to a standard floating point number
4.999999999999999 + 3.0im
julia> convert(ArbRadixFloat{6im, 5}, 1000) #Pretty printing uses base36 with overbars for negative digits
(0.s̅08̅0)₀ ₊ ₆ᵢₘ × (0 + 6im)³
julia> z = convert(ArbRadixFloat{y, precision}, 1000 - 39im) #A stranger example with an ArbRadixFloat radix
([-8, 49, 25, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])₍₁̅.₂₃₂₂₂₂₂₂₂₂₂₂₁₅₀₎₂ ₋ ₁ᵢₘ × ₍₂ ₋ ₁ᵢₘ₎² × ((1̅.232222222222150)₂ ₋ ₁ᵢₘ × (2 - 1im)²)³
julia> float(z) #Still works!
999.9999999999999 - 38.99999999999979im
julia> using ArbRadixFloatingPoints, Quaternions
julia> q1 = Quaternion(1, -2, 0.9, 0); q2 = Quaternion(10, -3.1, 50, -1);
julia> Base.float(q::Quaternion{T}) where T<:AbstractFloat = q #Define missing Quaternion method
julia> Q = convert(ArbRadixFloat{q1,16}, q2) #Printing is messy
(1̅.02̅1̅1̅2̅1̅22̅21̅2̅1111)Qᵤₐₜₑᵣₙᵢₒₙ{Fₗₒₐₜ₆₄}₍₁.₀, ₋₂.₀, ₀.₉, ₀.₀, fₐₗₛₑ₎ × (Quaternion{Float64}(1.0, -2.0, 0.9, 0.0, false))⁴
julia> abs(float(Q) - q2) #pretty lossy but doable
44.33522390835951
ArbRadixFloat
is not a subtype of AbstractFloat
because there's no guarantee that an ArbRadixFloat
is a real number!
Quite a lot of papers have been written on non-integer numerations, complex base systems, and the like.
Strangely, though, the non-integer floating point numbers do not appear to be written down anywhere, even though the generalization from ordinary integer-radixed floating point numbers is obvious to define.
Converting an arbitrary-radixed floating point number to an ordinary binary float is quite straightforward.
The converse, however, is quite tricky to get right!
The current algorithm is implemented in the (unexported) function factorize_leastsquares
.
If we relax the problem of finding a digit expansion to a least squares problem, then the coefficients of the expansion can be found by solving a (massively rank-deficient) linear system of equations.
This package implements a hacky solution to obtain the most significant digit by rounding off the first component of the solution,
and then deflating the problem.
I don't think there is a guarantee of finding the minimum norm solution after rounding off.
In practice, this seems to work quite well.
My first attempt as this conversion is factorize_greedy
, which is quite fragile and generates obviously worse solutions that the current method.
- By default, the digits are allowed to take any value that fits in machine
Int
s, including negative values. Restrictions to nonnegative digits, binary digits, or similar have not been implemented, so many numeration systems, such as Knuth's quater-imaginary system or the balanced ternary system, are not computed by this package. - No arithmetic on these numbers have been implemented. There's so much to do!
- No attempt is made to form normalized numbers. The conversion to
ArbRadixFloat
is known to generate denormalized floats. - The conversion from ordinary binary floating point to
ArbRadixFloat
is not guaranteed to be the best possible norm preserving conversion. - I have no idea how to think about rounding modes for
ArbRadixFloat
s