Math/Rational.bruijn
# ideas by u/DaVinci103
# MIT License, Copyright (c) 2024 Marvin Borner
# (p : q) ⇔ (p / (q + 1))
:import std/Logic .
:import std/Combinator .
: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)
# returns true if a rational number is greater than another
gt? &[[&[[N.gt? (N.mul 3 N.++0) (N.mul N.++2 1)]]]] ⧗ Rational → Rational → Boolean
…>?… gt?
# returns true if a rational number is less than another
lt? &[[&[[N.lt? (N.mul 3 N.++0) (N.mul N.++2 1)]]]] ⧗ Rational → Rational → Boolean
…<?… lt?
# returns true if a rational number is positive
positive? \gt? (+0.0) ⧗ Rational → Boolean
>?‣ positive?
# returns true if a real number is negative
negative? \lt? (+0.0) ⧗ Rational → Boolean
<?‣ negative?
# returns true if a rational number is zero
zero? &[[N.=?1]] ⧗ Rational → Boolean
=?‣ zero?
# negates a rational number if <0
abs &[[N.|1 : N.|0]] ⧗ Rational → Rational
|‣ abs
# 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 N.++2 1)
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)
reduce [[[(N.div 2 0) : N.--(N.div 1 0)] (N.gcd 1 0)]] ⧗ Number → Number → Rational
add' &[[&[[reduce p q]]]]
p N.add (N.mul 3 N.++0) (N.mul N.++2 1)
q N.mul N.++0 N.++2
# subtracts two rational numbers
sub &[[&[[p : q]]]] ⧗ Rational → Rational → Rational
p N.sub (N.mul 3 N.++0) (N.mul N.++2 1)
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)
# increments a rational number
inc add (+1.0) ⧗ Rational → Rational
++‣ inc
# decrements a rational number
dec \sub (+1.0) ⧗ Rational → Rational
--‣ dec
# approximates a rational number to n digits
approximate &[[[&[[int : float]] (N.quot-rem 2 N.++1)]]] ⧗ Rational → Number → (List Number)
int 1
float N.number→list (N.div (N.mul 0 (N.pow (+10) 2)) N.++3)
# 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