We should stop this limited-precision dyadic nonsense and go back to first principles.
Natural := Zero | Succ of Natural
Integer := Positive of Natural | Negative of Natural
## Negative(0) |=> error in constructor
Rational := {num:Integer, denom:Integer}
## denom <= 0 || gcd(num, denom) != 1 |=> error in const.
Real := (Rational, () => Real)
## Lazy Cauchy Sequence-- user is responsible for convergence.
Complex := {re:Real, im:Real}
Quaternion := {re: Real, i:Real, j:Real, k:Real}
Octonion := ... ## NOW we can use FP because octonions
## are non-associative anyway!
Example usage (still pseudocode):
$ realMath.sqrt(Positive(Succ(Succ(Zero)))
-> (Rational{num = Positive(Succ(Succ(Zero)))
denom = Positive(Succ(Zero))},
#<fn () => Real@f73d>) ## function produces (3/2, fn)
## Of course, with a proper type system, we'd never let sqrt return a Real! Sorry.
## It should be List[Complex], like so.
$ realMath.sqrt(Negative(Succ(Zero))
-> Cons(Complex{re = (Rational{num = Positive(Zero),
denom = Positive(Succ(Zero))},
#<fn ...>,
im = (Rational{num = Negative(Succ(Zero)),
denom = Positive(Succ(Zero))},
#<fn ...>)},
Cons(Complex{...}, ## The other root...
Nil))