-
Notifications
You must be signed in to change notification settings - Fork 2
/
math.sh
145 lines (124 loc) · 3.02 KB
/
math.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
scale="100000000"
frac_digits=${#scale}
add() ((ret = $1 + $2))
sub() ((ret = $1 - $2))
mul() {
((ret = $1 * $2 / scale))
if ((ret < 0 && $1 > 0 && $2 > 0)); then
log "OVERFLOW DETECTED: $1 x $2 = $ret"
fi
}
div() ((ret = $1 * scale / $2))
div_by_2() ((ret = $1 >> 1))
mul_by_2() ((ret = $1 << 1))
truncate() ((ret = $1 / scale))
abs() ((ret = $1 < 0 ? -$1 : $1))
sqrt() {
local x=$1
if ((x < 0)); then
fatal "arg passed to sqrt x was negative: ${x}"
# TODO mul can exceed the precision needed so certain dot products get
# weird
# abs "$x"; x=$ret
# echo 0
# return
fi
div_by_2 "$x"
local guess=$ret
for i in {0..5}; do
if ((guess==0)); then
break
fi
div "$x" "$guess"
add "$ret" "$guess"
div_by_2 "$ret"
guess=$ret
done
ret=$guess
}
# Convert a number to fixed point representation
to_fp() {
local x=$1
# Remove everything after the .
local int_part=${x%.*}
# Remove everything before the .
local frac_part=${x#*.}
if [[ $x == *.* ]]
then
frac_part=${frac_part:0:6}
else
frac_part=0
fi
local frac_length=${#frac_part}
local pad_length=$(( frac_digits - frac_length - 1 ))
local padding=""
for ((i=0;i<pad_length;i++)); do
padding="${padding}0"
done
local frac_padded="${frac_part}${padding}"
frac_padded=${frac_padded#0*}
local sign=${x:0:1}
local res=0
if [ "$sign" == "-" ]
then
res=$(( int_part * scale - frac_padded ))
else
res=$(( int_part * scale + frac_padded ))
fi
ret=$res
}
# Converts from fixed point to normal representation
# Doesn't really need to be fast as we only use it for debugging
from_fp() {
local x=$1
local int_part=$(( x / scale ))
if [ $int_part -eq 0 ]
then
if [ $x -gt 0 ] || [ $x -eq 0 ]
then
x=$((x + scale))
else
int_part="-0"
x=$((x - scale))
fi
fi
# Can't just do x % scale, because this does not preserve leading zeroes
local x_length=${#x}
local decimal_point_pos=$((x_length - frac_digits + 1))
local fract_part=${x:$decimal_point_pos:$frac_digits}
ret=${int_part}.${fract_part}
}
vec3_print() {
local -a v=("${!1}")
from_fp "${v[0]}"; v[0]=$ret
from_fp "${v[1]}"; v[1]=$ret
from_fp "${v[2]}"; v[2]=$ret
echo "{ ${v[0]}, ${v[1]}, ${v[2]} }"
}
print() {
local ret
from_fp "$1"
echo "$1"
}
to_fp 1.5; three_halves=$ret
inv_sqrt() {
sqrt "$1"
div "$scale" "$ret"
# if ((x<0)); then
# fatal "arg passed to inv sqrt x was negative ${x}"
# fi
# div_by_2 "$x"; local x2=$ret
# div $scale $x; local guess=$ret
# for i in {0..4}; do
# mul $guess $guess
# mul $ret $x2
# sub $three_halves $ret
# mul $ret $guess
# guess=$ret
# done
# ret=$guess
}
clamp_0_1() {
((ret = $1 > scale ? scale : $1 < 0 ? 0 : $1))
}
source ./vec_math.sh