Math/Rational.bruijn


# ideas by u/DaVinci103
# MIT License, Copyright (c) 2024 Marvin Borner

# (p : q) ⇔ (1 / (q + 1))

:import std/Logic .
:import std/Combinator .
:import std/Logic .
:import std/Pair .
:import std/Math N

# converts a balanced ternary number to a rational number
number→rational [0 : (+0)] ⧗ Number → Rational

:test (number→rational (+5)) ((+5.0))

# returns true if two rational numbers are equal
eq? &[[&[[N.eq? (N.mul 3 N.++0) (N.mul N.++2 1)]]]] ⧗ Rational → Rational → Boolean

…=?… eq?

:test (((+1) : (+3)) =? ((+2) : (+7))) (true)
:test ((+0.5) =? (+0.5)) (true)
:test ((+42.0) =? (+42.0)) (true)
:test ((+0.4) =? (+0.5)) (false)

# finds smallest equivalent representation of a rational number
compress &[[[(N.div 2 0) : N.--(N.div N.++1 0)] (N.gcd 1 N.++0)]] ⧗ Rational → Rational

%‣ compress

:test (%((+4) : (+1)) =? (+2.0)) (true)
:test (%((+4) : (+7)) =? (+0.5)) (true)

# adds two rational numbers
add &[[&[[p : q]]]] ⧗ Rational → Rational → Rational
	p N.add (N.mul 3 N.++0) (N.mul 1 N.++2)
	q N.add (N.mul 2 0) (N.add 2 0)

…+… add

:test ((+0.5) + (+0.5) =? (+1.0)) (true)
:test ((+1.8) + (+1.2) =? (+3.0)) (true)
:test ((-1.8) + (+1.2) =? (-0.6)) (true)

# subtracts two rational numbers
sub &[[&[[p : q]]]] ⧗ Rational → Rational → Rational
	p N.sub (N.mul 3 N.++0) (N.mul 1 N.++2)
	q N.add (N.mul 2 0) (N.add 2 0)

…-… sub

:test ((+0.5) - (+0.5) =? (+0.0)) (true)
:test ((+3.0) - (+1.8) =? (+1.2)) (true)
:test ((+1.8) - (-1.2) =? (+3.0)) (true)

# negates a rational number
negate &[[N.-1 : 0]] ⧗ Rational → Rational

-‣ negate

:test (-(+0.0) =? (+0.0)) (true)
:test (-(+4.2) =? (-4.2)) (true)
:test (-(-4.2) =? (+4.2)) (true)

# multiplies two rational numbers
mul &[[&[[p : q]]]] ⧗ Rational → Rational → Rational
	p N.mul 3 1
	q N.add (N.mul 2 0) (N.add 2 0)

…⋅… mul

:test ((+5.0) ⋅ (+5.0) =? (+25.0)) (true)
:test ((+1.8) ⋅ (+1.2) =? (+2.16)) (true)

# finds the multiplicative inverse of a rational number
invert &[[N.compare-case eq gt lt 1 (+0)]] ⧗ Rational → Rational
	eq Ω
	gt N.++0 : N.--1
	lt N.-(N.++0) : N.--(N.-1)

~‣ invert

:test (~(+0.5) =? (+2.0)) (true)
:test (~(-0.5) =? (-2.0)) (true)

# divides two rational numbers
div [[1 ⋅ ~0]] ⧗ Rational → Rational → Rational

…/… div

:test ((+8.0) / (+4.0) =? (+2.0)) (true)
:test ((+18.0) / (+12.0) =? (+1.5)) (true)

gt? &[[&[[(N.gt? 1 3) ⋀? (N.gt? 0 2)]]]]

lt? &[[&[[(N.lt? 1 3) ⋀? (N.lt? 0 2)]]]]

# increments a rational number
inc add (+1.0) ⧗ Rational → Rational

++‣ inc

# decrements a rational number
dec \sub (+1.0) ⧗ Rational → Rational

--‣ dec

# TODO: Regression? Importing this into . won't find Q.eq? anymore

:import std/List L

# power function: rational^number
pow-n [L.nth-iterate (mul 0) (+1.0)] ⧗ Rational → Number → Rational