# some ideas by u/DaVinci103 # MIT License, Copyright (c) 2024 Marvin Borner :import std/Logic . :import std/Combinator . :import std/Pair . :import std/Math/Rational Q :import std/Math N # a Real is just a Unary → Rational! # converts a balanced ternary number to a real number number→real [[Q.number→rational 1]] ⧗ Number → Real :test (number→real (+5)) ((+5.0r)) # returns true if two real numbers are equal approximately approx-eq? [[[Q.eq? (1 2) (0 2)]]] ⧗ Number → Real → Real → Boolean # TODO: bigger value?? …≈?… approx-eq? (+100u) # adds two real numbers add φ Q.add ⧗ Real → Real → Real …+… add :test ((+1.0r) + (+0.0r) ≈? (+1.0r)) (true) :test ((+0.0r) + (-1.0r) ≈? (-1.0r)) (true) # subtracts two real numbers sub φ Q.sub ⧗ Real → Real → Real …-… sub :test ((+1.0r) - (+0.5r) ≈? (+0.5r)) (true) :test ((+0.0r) - (-1.0r) ≈? (+1.0r)) (true) # multiplies two real numbers mul φ Q.mul ⧗ Real → Real → Real …⋅… mul :test ((+5.0r) ⋅ (+5.0r) ≈? (+25.0r)) (true) :test ((+1.8r) ⋅ (+1.2r) ≈? (+2.16r)) (true) # divides two real numbers div φ Q.div ⧗ Real → Real → Real …/… div :test ((+8.0r) / (+4.0r) ≈? (+2.0r)) (true) :test ((+18.0r) / (+12.0r) ≈? (+1.5r)) (true) # negates a real number negate b Q.negate ⧗ Real → Real -‣ negate :test (-(+0.0r) ≈? (+0.0r)) (true) :test (-(+4.2r) ≈? (-4.2r)) (true) :test (-(-4.2r) ≈? (+4.2r)) (true) # inverts a real number invert b Q.invert ⧗ Real → Real ~‣ invert :test (~(+0.5r) ≈? (+2.0r)) (true) :test (~(-0.5r) ≈? (-2.0r)) (true) # finds smallest equivalent representation of a real number compress b Q.compress ⧗ Real → Real %‣ compress :test (%[(+4) : (+1)] ≈? (+2.0r)) (true) :test (%[(+4) : (+7)] ≈? (+0.5r)) (true) # increments a real number inc add (+1.0r) ⧗ Real → Real ++‣ inc # decrements a real number dec \sub (+1.0r) ⧗ Real → Real --‣ dec # --- :import std/List L # e^x using Taylor expansion # tex: \sum_{n=0}^\infty \frac{x^n}{n!} unary-exp [[0 &[[[[[[[2 1 0 (Q.add 4 (1 : N.--0)) N.++3]] pow fac]]]]] start [[[[1]]]]]] ⧗ Number → Real pow N.mul 6 4 fac N.mul 1 3 start [0 (+1) (+1) (+1.0q) (+1)] # equivalent to unary-exp but with ternary index using infinite list iteration exp [[L.nth-iterate &[[[[op]]]] start 0 [[[[1]]]] 0]] ⧗ Real → Real start [0 (+1.0r) (+1.0r) (+1.0r) (+1)] op [[[2 1 0 (4 + (1 / 0)) N.++3]] pow fac] pow 6 ⋅ 4 fac (number→real 1) ⋅ 3 # power function: real^number pow-n [L.nth-iterate (mul 0) (+1.0r)] ⧗ Real → Number → Real # e^x using infinite limit # tex: \lim_{n\to\infty}(1+x/n)^n lim-exp [[pow-n [(N.add 2 1) : N.--1] 0]] ⧗ Number → Real # natural logarithm using Taylor expansion # tex: \sum_{n=0}^\infty\frac{2}{2n+1}(\frac{x-1}{x+1})^{2n+1} # error: O((x-1)/2)^{2n+1} ln [[[L.nth-iterate &[[[op]]] start 1] (--1 / ++1 0) [[[1]]]]] ⧗ Real → Real start [0 1 (+0.0q) (+0)] op [0 pow (Q.add 2 go) N.++1] pow Q.mul 3 (Q.mul 4 4) go Q.mul ((+2) : (N.mul (+2) 1)) 3 :test (Q.eq? (ln (+2.0r) (+2)) ((+168) : (+242))) (true) derive [[[[((3 (0 + 1)) - (3 0)) / 1]] ((+1.0r) / 0) 0]] ⧗ (Real → Real) → (Real → Real) # power function: real^real pow [[exp (0 ⋅ (ln 1))]] ⧗ Real → Real → Real …**… pow # square root by x^{0.5} sqrt* \pow (+0.5r) ⧗ Real → Real # Newton's/Heron's method, quadratic convergence # tex: x_{n+1}=\frac{x_n+a/x_n}{2} sqrt [[y [[[N.=?0 guess go]]] (1 0) 0]] ⧗ Real → Real guess (+1.0q) go [Q.div (Q.add 0 (Q.div 2 0)) (+2.0q)] (2 1 N.--0) # Newton's/Heron's method, quadratic convergence # tex: x_{n+1}=\frac{3x_n+a/(x_n^2)}{4} cbrt [[y [[[N.=?0 guess go]]] (1 0) 0]] ⧗ Real → Real guess (+1.0q) go [Q.div (Q.add (Q.mul (+3.0q) 0) (Q.div 2 (Q.mul 0 0))) (+4.0q)] (2 1 N.--0) # hypotenuse hypot [[sqrt ((0 ⋅ 0) + (1 ⋅ 1))]] ⧗ Real → Real → Real # tex: \sum_{n=0}^\infty\frac{2^n n!^2}{(2n+1)!} π/2 [L.nth-iterate &[[[[[op]]]]] start 0 [[[[[3]]]]]] ⧗ Real start [0 (+1) (+0.0q) (+1) (+1) (+1)] op [0 N.++5 (Q.add 4 ((N.mul 3 2) : N.--1)) enum-pow enum-fac denom] enum-pow N.mul 3 (+2) enum-fac N.mul 2 (N.mul 5 5) denom [N.mul 2 (N.mul 0 N.++0)] (N.mul (+2) 5) # ratio of circle's circumference to its diameter π π/2 ⋅ (+2.0r) ⧗ Real # Gauss-Legendre, quadratic convergence # Chudnovsky would be even faster but is ugly (i.e. magic numbers) π-gauss [L.nth-iterate &[[[[op]]]] start 0 final] start [0 (+1.0q) Q.~(sqrt (+2.0r) 1) (+0.25q) (+1.0q)] op [[1 0 b t p] a] a Q.div (Q.add 4 3) (+2.0q) b sqrt [Q.mul 6 5] 6 t Q.sub 3 (Q.mul 2 (Q.pow-n (Q.sub 5 0) (+2))) p Q.mul (+2.0q) 2 final [[[[Q.div (Q.pow-n (Q.add 3 2) (+2)) (Q.mul (+4.0q) 1)]]]] # golden ratio from direct formula φ ++(sqrt (+5.0r)) / (+2.0r) # conjugate golden ratio ψ -(~φ) # golden ratio from fibonacci convergence φ* [(L.index (L.iterate &[[0 : (N.add 1 0)]] ((+0) : (+1))) 0) [[1 : N.--0]]] # real fibonacci fib [((pow φ 0) - (pow ψ 0)) / (sqrt (+5.0r))] # arctan by Taylor expansion, only for |x|<=1 # tex: \sum_{n=0}^\infty(-1)^n \frac{x^{2n+1}}{2n+1} arctan* [[[L.nth-iterate &[[[[op]]]] start 1] (1 0) [[[[3]]]]]] ⧗ Real → Real start [0 1 [[0]] (Q.pow-n 1 (+3)) (+3.0q)] op [0 ((3 Q.add Q.sub) 4 (Q.div 2 1)) \3 enum denom] enum Q.mul 2 (Q.mul 5 5) denom Q.add 1 (+2.0q) # actual arctan for arbitrary x arctan [[Q.sub (π/2 0) (arctan* [Q.div (+1.0q) (2 1)] 0)]] ⧗ Real → Real # TODO: atan2 atan2 [0] ⧗ Real → Real