251 lines
4.9 KiB
Text
251 lines
4.9 KiB
Text
|
|
PI := 3.14159265358979323
|
|
E := 2.718281828459045235360287471352
|
|
|
|
# abs(x)
|
|
# x: number
|
|
# Get the absolute value of a number. If x is negative, the returned
|
|
# value is positive and equal to `-x`. If x is positive or zero, the
|
|
# returned value is x.
|
|
fn absf(x: float) -> float {
|
|
# if the number is negative
|
|
if x < 0.0 {
|
|
# negate it so it's positive
|
|
return -x
|
|
}
|
|
|
|
return x
|
|
}
|
|
|
|
fn absi(n: int) -> int {
|
|
if n < 0 {
|
|
-n
|
|
} else {
|
|
n
|
|
}
|
|
}
|
|
|
|
DERIVE_DX := 0.00000001
|
|
fn derive(f: fn(float) -> float, x: float) -> float {
|
|
return (f(x + DERIVE_DX) - f(x))/DERIVE_DX
|
|
}
|
|
|
|
NEWTONS_ACC := 0.000000000001
|
|
fn newtons(f: fn(float) -> float) -> float {
|
|
pg := 0.0
|
|
g := 1.0
|
|
|
|
while absf(g - pg) > NEWTONS_ACC {
|
|
pg = g
|
|
g = pg - f(pg) / derive(f, pg)
|
|
}
|
|
|
|
return g
|
|
}
|
|
|
|
MAX_SQRT_DX := 0.0000001
|
|
|
|
# sqrt(x)
|
|
# x: number
|
|
# Calculate the approximate square root using newton's method until
|
|
# the accuracy has increased by less than the variable `MAX_SQRT_DX`.
|
|
fn sqrt(x: float) -> float {
|
|
ng := x
|
|
g := 1.0
|
|
|
|
while absf(g - ng) > MAX_SQRT_DX {
|
|
g = ng
|
|
|
|
# create new guess
|
|
ng = (g + x / g) / 2.0
|
|
}
|
|
|
|
g
|
|
}
|
|
|
|
# floor(x)
|
|
# x: number
|
|
# Return the whole number part of the number. if x is a whole number,
|
|
# the returned value is x. If x is not a whole number, the closest
|
|
# whole number which is less than or equal to x is returned.
|
|
|
|
|
|
# ceil(x)
|
|
# x: number
|
|
# Return the whole number part of the number. if x is a whole number,
|
|
# the returned value is x. If x is not a whole number, the closest
|
|
# whole number which is greater than or equal to x is returned.
|
|
|
|
|
|
# round(x)
|
|
# x: number
|
|
# Return the closest whole number to the value x.
|
|
fn round(x: float) -> float {
|
|
f := floor(x)
|
|
|
|
if x - f > 0.5 {
|
|
return f + 1.0
|
|
}
|
|
|
|
return f
|
|
}
|
|
|
|
# mod(x, n)
|
|
# x: number; any number
|
|
# n: number; the number to divide by
|
|
# Return the rest from a division of x by n.
|
|
fn mod(x: float, n: float) -> float {
|
|
if x == 0.0 {
|
|
return 0.0
|
|
}
|
|
|
|
if x < 0.0 {
|
|
while x + n <= 0.0 {
|
|
x = x + n
|
|
}
|
|
} else {
|
|
while x - n >= 0.0 {
|
|
x = x - n
|
|
}
|
|
}
|
|
|
|
return x
|
|
}
|
|
|
|
# sm_exp(x)
|
|
# x: number; any number between 0 and 1
|
|
# Get an approximate value of e raised to the power of x.
|
|
# This value is only reasonable if 0<x<1.
|
|
# It is approximated using the taylor series of e**x.
|
|
SM_EXP_ACC := 0.00000000001
|
|
fn sm_exp(x: float) -> float {
|
|
p_tot := 0.0
|
|
tot := 1.0
|
|
n := 1
|
|
x_pow := x
|
|
f := 1.0
|
|
|
|
while absf(tot - p_tot) > SM_EXP_ACC {
|
|
p_tot = tot
|
|
t := x_pow / f
|
|
tot = tot + t
|
|
f = f * float(n+1)
|
|
x_pow = x_pow * x
|
|
n = n + 1
|
|
}
|
|
|
|
return tot
|
|
}
|
|
|
|
# exp(x)
|
|
# x: number; any number
|
|
# Get an approximate value of e raised to the power of x.
|
|
fn exp(x: float) -> float {
|
|
n := absf(x)
|
|
tot := 1.0
|
|
while n >= 1.0 {
|
|
tot = tot * E
|
|
n = n - 1.0
|
|
}
|
|
|
|
if n > 0.0 {
|
|
tot = tot * sm_exp(n)
|
|
}
|
|
|
|
if x < 0.0 {
|
|
1.0/tot
|
|
} else {
|
|
tot
|
|
}
|
|
}
|
|
|
|
# ln(x)
|
|
# x: number; any number
|
|
# Get the approximate value of the natural logarithm
|
|
# This function uses newton's method to approximate.
|
|
LN_ACC := 0.0000000001
|
|
fn ln(x: float) -> float {
|
|
pg := 0.0
|
|
g := 1.0
|
|
|
|
while absf(pg - g) > LN_ACC {
|
|
pg = g
|
|
g = pg + x / exp(pg) - 1.0
|
|
}
|
|
|
|
return g
|
|
}
|
|
|
|
# pow(x, p)
|
|
# x: number; any number. The base
|
|
# p: number; the value of the exponent
|
|
# Raise any number to any power (x^p)
|
|
fn pow(x: float, p: float) -> float {
|
|
return exp(p*ln(x))
|
|
}
|
|
|
|
# log(x, b)
|
|
# x: number; any number greater than 0
|
|
# b: number; any number as the base
|
|
# Calculate the approximate value of the logarithm
|
|
# of a with b as base.
|
|
LOG_ACC := 0.0000001
|
|
fn log(a: float, b: float) -> float {
|
|
ln_b := ln(b)
|
|
|
|
pg := 0.0
|
|
g := 1.0
|
|
|
|
while absf(g - pg) > LOG_ACC {
|
|
pg = g
|
|
g = pg - 1.0/ln_b - a/(ln_b*pow(b, pg))
|
|
}
|
|
|
|
return g
|
|
}
|
|
|
|
# sin(x)
|
|
# x: number; an angle in radians
|
|
# Get the sine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine
|
|
# TODO: use hashmap with precomputed values and linear interpolation
|
|
fn sin(x: float) -> float {
|
|
f := 1.0
|
|
x = mod(x, 2.0*PI)
|
|
if x > PI {
|
|
x = PI - x
|
|
f = -1.0
|
|
}
|
|
|
|
# compute sine with a taylor series mock function of sine (valid between -pi and +pi)
|
|
tot := x
|
|
l := 1.0
|
|
i := 1.0
|
|
s := -1.0
|
|
|
|
while i <= 19.0 {
|
|
i = i + 2.0
|
|
l = s * l * x / i / (i-1.0)
|
|
|
|
tot = tot + l
|
|
|
|
s = -s
|
|
}
|
|
|
|
return tot*f
|
|
}
|
|
|
|
# cos(x)
|
|
# x: number; an angle in radians
|
|
# Get the cosine of an angle (in radians). https://en.wikipedia.org/wiki/Sine_and_cosine
|
|
fn cos(x: float) -> float {
|
|
# todo
|
|
0.0
|
|
}
|
|
|
|
# tan(x)
|
|
# x: number; an angle in radians
|
|
# Get the tangent of an angle. https://en.wikipedia.org/wiki/Tangent
|
|
fn tan(x: float) -> float {
|
|
# todo
|
|
0.0
|
|
}
|