Skip to content

Commit f9f74a9

Browse files
committed
Draft Rational implementation
1 parent ecb4606 commit f9f74a9

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

text/0000-expand-math.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,52 @@ I foresee this as a primitive `Constant` with methods for each value (e.g., `Con
5757

5858
### `math/rational`
5959

60+
<<<<<<< HEAD
6061
`math/rational` should decide backing precision on `create[A: Real]` and return precision on `apply[B: Number]` -- `let x = Rational.create[U64](where numerator = 2)` gives a type which is represented by embedded `U64`/`U64` and starts with a value of `2`/`1` which can then be returned via `x.apply[F32](): F32 => F32(2) / F32(1)`. `Rational` should be parameterized only on `Real` types and track sign via an embedded field.
62+
=======
63+
`math/rational` should decide backing precision on `create[A: UnsignedInteger]` and return precision on `apply[B: Number]` -- `let x = Rational.create[U64](where numerator=2)` gives a type which is represented by `U64(2)`/`U64(2)` which can then be returned as any valid `Number`. `Rational` should be parameterized only on `UnsignedInteger` types and track sign via an internal field.
64+
65+
```pony
66+
// Parameterized on unsigned integers as negative status is tracked by field
67+
class Rational[A: UnsignedInteger[A] val = USize]
68+
var numerator: A
69+
var denominator: A
70+
var negative: Bool = false
71+
72+
// Allow for creating Rationals from signed or unsigned integer arguments
73+
new create[B: Integer[B] val = ISize](n: B, d: B = 1)? =>
74+
// Error if denominator is zero
75+
if d == B.from[U8](0) then error end
76+
77+
// Produce unsigned equivalents of arguments
78+
// NOTE: this produces an error of form
79+
// Error:
80+
// main.pony:XX:YY: type argument is outside its constraint
81+
// This is because Integer is not a subtype of UnsignedInteger
82+
let n': A = if n < B.from[U8](0) then A.from[B](-n) else A.from[B](n) end
83+
let n': A = if n < B.from[U8](0) then A.from[B](-n) else A.from[B](n) end
84+
let d': A = if d < B.from[U8](0) then A.from[B](-d) else A.from[B](d) end
85+
86+
// Find greatest common divisor and reduce fraction
87+
let divisor: A = try GreatestCommonDivisor[A](n', d')? else A.from[U8](1) end
88+
numerator = n' / divisor
89+
denominator = d' / divisor
90+
91+
// Set negative field if numerator, but not denominator is negative
92+
if (n < B.from[U8](0)) and (B.from[U8](0) < d) then
93+
negative = true
94+
end
95+
96+
fun string(): String =>
97+
// Size of 10 here is a placeholder for determining the size needed
98+
let output = recover String(10) end
99+
if negative then output.append("-") end
100+
output.append(numerator.string())
101+
output.append(" / ")
102+
output.append(denominator.string())
103+
output
104+
```
105+
>>>>>>> Draft Rational implementation
61106
62107
Changing the underlying precision "in-place" is done via a `prec[C: Real]` method which creates a new instance with a different precision.
63108

0 commit comments

Comments
 (0)