More improvements to linalg functions

This commit is contained in:
gingerBill
2026-05-11 15:44:12 +01:00
parent 86a6f69793
commit 724ce14677
2 changed files with 46 additions and 47 deletions

View File

@@ -7,7 +7,7 @@ import "core:math"
@(require_results)
to_radians :: proc "contextless" (degrees: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = degrees[i] * RAD_PER_DEG
}
} else {
@@ -19,7 +19,7 @@ to_radians :: proc "contextless" (degrees: $T) -> (out: T) where IS_NUMERIC(ELEM
@(require_results)
to_degrees :: proc "contextless" (radians: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = radians[i] * DEG_PER_RAD
}
} else {
@@ -31,7 +31,7 @@ to_degrees :: proc "contextless" (radians: $T) -> (out: T) where IS_NUMERIC(ELEM
@(require_results)
min_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = builtin.min(a[i], b[i])
}
} else {
@@ -51,7 +51,7 @@ min_single :: proc "contextless" (a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC
out = builtin.min(a[0], a[1])
} else {
out = builtin.min(a[0], a[1])
for i in 2..<N {
#no_bounds_check for i in 2..<N {
out = builtin.min(out, a[i])
}
}
@@ -71,7 +71,7 @@ min :: proc{min_single, min_double, min_triple}
@(require_results)
max_double :: proc "contextless" (a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = builtin.max(a[i], b[i])
}
} else {
@@ -93,7 +93,7 @@ max_single :: proc "contextless" (a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC
out = builtin.max(a[0], a[1], a[2])
}else {
out = builtin.max(a[0], a[1])
for i in 2..<N {
#no_bounds_check for i in 2..<N {
out = builtin.max(out, a[i])
}
}
@@ -113,7 +113,7 @@ max :: proc{max_single, max_double, max_triple}
@(require_results)
abs :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = auto_cast builtin.abs(a[i])
}
} else {
@@ -125,7 +125,7 @@ abs :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
@(require_results)
sign :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = #force_inline math.sign(a[i])
}
} else {
@@ -137,7 +137,7 @@ sign :: proc "contextless" (a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
@(require_results)
clamp :: proc "contextless" (x, a, b: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = builtin.clamp(x[i], a[i], b[i])
}
} else {
@@ -155,7 +155,7 @@ saturate :: proc "contextless" (x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
lerp :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = a[i]*(1-t[i]) + b[i]*t[i]
}
} else {
@@ -166,7 +166,7 @@ lerp :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)
@(require_results)
mix :: proc "contextless" (a, b, t: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = a[i]*(1-t[i]) + b[i]*t[i]
}
} else {
@@ -183,7 +183,7 @@ unlerp :: proc "contextless" (a, b, x: $T) -> T where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
step :: proc "contextless" (e, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = x[i] < e[i] ? 0.0 : 1.0
}
} else {
@@ -208,7 +208,7 @@ smootherstep :: proc "contextless" (e0, e1, x: $T) -> T where IS_FLOAT(ELEM_TYPE
@(require_results)
sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.sqrt(x[i])
}
} else {
@@ -220,7 +220,7 @@ sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
inverse_sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = 1.0/math.sqrt(x[i])
}
} else {
@@ -232,7 +232,7 @@ inverse_sqrt :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(
@(require_results)
cos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.cos(x[i])
}
} else {
@@ -244,7 +244,7 @@ cos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
sin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.sin(x[i])
}
} else {
@@ -256,7 +256,7 @@ sin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
tan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.tan(x[i])
}
} else {
@@ -268,7 +268,7 @@ tan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
acos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.acos(x[i])
}
} else {
@@ -280,7 +280,7 @@ acos :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
asin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.asin(x[i])
}
} else {
@@ -292,7 +292,7 @@ asin :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
atan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.atan(x[i])
}
} else {
@@ -303,7 +303,7 @@ atan :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
atan2 :: proc "contextless" (y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.atan2(y[i], x[i])
}
} else {
@@ -316,7 +316,7 @@ atan2 :: proc "contextless" (y, x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T))
@(require_results)
ln :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.ln(x[i])
}
} else {
@@ -329,7 +329,7 @@ ln :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
log2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
INVLN2 :: 1.4426950408889634073599246810018921374266459541529859341354494069
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = INVLN2 * math.ln(x[i])
}
} else {
@@ -342,7 +342,7 @@ log2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
log10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
INVLN10 :: 0.4342944819032518276511289189166050822943970058036665661144537831
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = INVLN10 * math.ln(x[i])
}
} else {
@@ -354,7 +354,7 @@ log10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
log :: proc "contextless" (x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.ln(x[i]) / math.ln(cast(ELEM_TYPE(T))b[i])
}
} else {
@@ -366,7 +366,7 @@ log :: proc "contextless" (x, b: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
exp :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.exp(x[i])
}
} else {
@@ -378,7 +378,7 @@ exp :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
exp2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.exp(LN2 * x[i])
}
} else {
@@ -390,7 +390,7 @@ exp2 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
exp10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.exp(LN10 * x[i])
}
} else {
@@ -402,7 +402,7 @@ exp10 :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
pow :: proc "contextless" (x, e: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = math.pow(x[i], e[i])
}
} else {
@@ -425,7 +425,7 @@ floor :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
@(require_results)
round :: proc "contextless" (x: $T) -> (out: T) where IS_FLOAT(ELEM_TYPE(T)) {
when IS_ARRAY(T) {
for i in 0..<len(T) {
#no_bounds_check for i in 0..<len(T) {
out[i] = #force_inline math.round(x[i])
}
} else {
@@ -486,7 +486,7 @@ is_nan_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) {
@(require_results)
is_nan_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = #force_inline is_nan(x[i])
}
return
@@ -499,7 +499,7 @@ is_inf_single :: proc "contextless" (x: $T) -> bool where IS_FLOAT(T) {
@(require_results)
is_inf_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]bool) where IS_FLOAT(T) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = #force_inline is_inf(x[i])
}
return
@@ -512,7 +512,7 @@ classify_single :: proc "contextless" (x: $T) -> math.Float_Class where IS_FLOAT
@(require_results)
classify_array :: proc "contextless" (x: $A/[$N]$T) -> (out: [N]math.Float_Class) where IS_FLOAT(T) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = #force_inline classify_single(x[i])
}
return
@@ -532,42 +532,42 @@ classify :: proc{classify_single, classify_array}
@(require_results)
less_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = x[i] < y[i]
}
return
}
@(require_results)
less_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = x[i] <= y[i]
}
return
}
@(require_results)
greater_than_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = x[i] > y[i]
}
return
}
@(require_results)
greater_than_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = x[i] >= y[i]
}
return
}
@(require_results)
equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = x[i] == y[i]
}
return
}
@(require_results)
not_equal_array :: proc "contextless" (x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) {
for i in 0..<N {
#no_bounds_check for i in 0..<N {
out[i] = x[i] != y[i]
}
return
@@ -601,7 +601,7 @@ all :: proc "contextless" (x: $A/[$N]bool) -> (out: bool) {
@(require_results)
not :: proc "contextless" (x: $A/[$N]bool) -> (out: A) {
for e, i in x {
out[i] = !e
#no_bounds_check out[i] = !e
}
return
}

View File

@@ -46,18 +46,17 @@ scalar_dot :: proc "contextless" (a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T)
@(require_results)
vector_dot :: proc "contextless" (a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E) #no_bounds_check {
ab := a * b
when N == 1 {
return ab.x
return a.x*b.x
} else when N == 2 {
return ab.x + ab.y
return a.x*b.x + a.y*b.y
} else when N == 3 {
return ab.x + ab.y + ab.z
return a.x*b.x + a.y*b.y + a.z*b.z
} else when N == 4 {
return ab.x + ab.y + ab.z + ab.w
return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w
} else {
for elem in ab {
c += elem
#unroll for _, i in a {
c += a[i]*b[i]
}
return c
}