# Implementing Rational Numbers to Handle Fractions in Standard ML

### Masaki Haga ・2 min read

Let's implement a data type like `Data.Ratio`

in `Haskell`

that can handle rational numbers (with greater precision than floating point).

## signature

```
signature RATIO =
sig
type ratio = int * int
exception DivideByZero
val fromIntPair : int * int -> ratio
val + : ratio * ratio -> ratio
val - : ratio * ratio -> ratio
val * : ratio * ratio -> ratio
val / : ratio * ratio -> ratio
val > : ratio * ratio -> bool
val < : ratio * ratio -> bool
end
```

The data type name is `ratio`

. It is actually an integer tuple.

Prepare conversion functions `fromIntPair`

, addition, subtraction, multiplication and division of fractions, and comparison operations.

In practice this is an integer tuple, so use `=`

for the equal sign.

## structure

```
structure Ratio : RATIO =
struct
type ratio = int * int
exception DivideByZero
fun fromIntPair (num, 0) = raise DivideByZero
| fromIntPair (0, den) = (0, 1)
| fromIntPair (num, den) =
let fun gcd (x, y) = if x = y then x
else if x > y then gcd (x - y, y)
else gcd (x, y - x)
val g = if den > 0 then gcd (abs num, abs den)
else ~(gcd (abs num, abs den))
in (num div g, den div g)
end
fun (x, y) + (z, w) = fromIntPair (Int.+(Int.*(w, x), Int.*(y, z)), Int.*(y, w))
fun (x, y) - (z, w) = fromIntPair (Int.-(Int.*(w, x), Int.*(y, z)), Int.*(y, w))
fun (x, y) * (z, w) = fromIntPair (Int.*(x, z), Int.*(y, w))
fun (x, y) / (z, w) = fromIntPair (Int.*(x, w), Int.*(y, z))
fun (x, y) > (z, w) = Int.>(Int.*(w, x), Int.*(y, z))
fun (x, y) < (z, w) = Int.<(Int.*(w, x), Int.*(y, z))
end
```

The argument to `fromIntPair`

will call an exception if the denominator is 0, and return`(0, 1)`

if the numerator is 0.

Otherwise, the greatest common divisor is obtained by taking the absolute value and dividing by the greatest common divisor obtained by the numerator and the denominator.

If the denominator is negative, the sign is reversed because only the numerator is signed.

In the four arithmetic operations of fractions, the numerator is calculated with the denominator aligned and then reduced with `fromIntPair`

.

In comparison operations, the numerators are compared after the denominators are aligned.

## execution example

Use the `open`

statement to expand a structure, and use the `local`

statement to avoid hiding the constraints of the original four operations and comparisons.

```
- local open Ratio
= in
= val twoThird =
= let val oneThird = fromIntPair (1, 3)
= in oneThird + oneThird
= end
= end
= ;
val twoThird = (2,3) : int * int
```

## dev.to/you

### Claim your page on DEV before someone else does

### Join DEV Now

Open source

Free forever

Level up every day

🤝