|
| 1 | +// |
| 2 | +// FILE: FastTrig.cpp |
| 3 | +// AUTHOR: Rob Tillaart |
| 4 | +// VERSION: 0.1.10 |
| 5 | +// PURPOSE: Arduino library for a faster approximation of sin() and cos() |
| 6 | +// DATE: 2011-08-18 |
| 7 | +// URL: https://github.com/RobTillaart/FastTrig |
| 8 | +// https://forum.arduino.cc/index.php?topic=69723.0 |
| 9 | +// |
| 10 | +// HISTORY: |
| 11 | +// 0.1.00 2011-08-18 initial version |
| 12 | +// 0.1.01 2011-08-18 improved tables a bit + changed param to float |
| 13 | +// 0.1.02 2011-08-20 added interpolation |
| 14 | +// eons passed |
| 15 | +// 0.1.1 2020-08-30 refactor, create a library out of it. |
| 16 | +// itan() approximation is bad. |
| 17 | +// 0.1.2 2020-09-06 optimize 16 bit table with example sketch |
| 18 | +// 0.1.3 2020-09-07 initial release. |
| 19 | +// 0.1.4 2020-09-08 rewrite itan() + cleanup + examples |
| 20 | +// 0.1.5 2020-09-11 fixed optimize, new table, added iasin() and iacos() |
| 21 | +// 0.1.6 2020-12-23 Arduino-CI + unit tests |
| 22 | +// 0.1.7 2021-04-23 fix for PlatformIO |
| 23 | +// 0.1.8 2021-08-10 made % 180 conditional in itan() => performance gain |
| 24 | +// added icot() cotangent. |
| 25 | +// 0.1.9 2021-12-18 update Arduino-CI, badges, |
| 26 | +// update library.json, minor edits |
| 27 | +// 0.1.10 2022-04-15 fix #12 split .h in .h and .cpp |
| 28 | + |
| 29 | + |
| 30 | +#include "FastTrig.h" |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +// 91 x 2 bytes ==> 182 bytes |
| 35 | +// use 65535.0 as divider |
| 36 | +uint16_t isinTable16[] = { |
| 37 | + 0, |
| 38 | +1145, 2289, 3435, 4572, 5716, 6853, 7989, 9125, 10255, 11385, |
| 39 | +12508, 13631, 14745, 15859, 16963, 18067, 19165, 20253, 21342, 22417, |
| 40 | +23489, 24553, 25610, 26659, 27703, 28731, 29755, 30773, 31777, 32772, |
| 41 | +33756, 34734, 35697, 36649, 37594, 38523, 39445, 40350, 41247, 42131, |
| 42 | +42998, 43856, 44701, 45528, 46344, 47147, 47931, 48708, 49461, 50205, |
| 43 | +50933, 51646, 52342, 53022, 53686, 54334, 54969, 55579, 56180, 56760, |
| 44 | +57322, 57866, 58394, 58908, 59399, 59871, 60327, 60768, 61184, 61584, |
| 45 | +61969, 62330, 62677, 63000, 63304, 63593, 63858, 64108, 64334, 64545, |
| 46 | +64731, 64903, 65049, 65177, 65289, 65377, 65449, 65501, 65527, 65535, |
| 47 | +65535 |
| 48 | +}; |
| 49 | + |
| 50 | + |
| 51 | +/* 0.1.4 table |
| 52 | +uint16_t isinTable16[] = { |
| 53 | + 0, |
| 54 | + 1145, 2289, 3435, 4571, 5715, 6852, 7988, 9125, 10254, 11385, |
| 55 | + 12508, 13630, 14745, 15859, 16963, 18067, 19165, 20253, 21342, 22416, |
| 56 | + 23488, 24553, 25610, 26659, 27699, 28730, 29754, 30773, 31777, 32771, |
| 57 | + 33755, 34734, 35697, 36649, 37594, 38523, 39445, 40350, 41247, 42127, |
| 58 | + 42998, 43856, 44697, 45527, 46344, 47146, 47931, 48708, 49461, 50205, |
| 59 | + 50933, 51645, 52341, 53022, 53686, 54333, 54969, 55578, 56180, 56759, |
| 60 | + 57322, 57866, 58394, 58908, 59399, 59871, 60327, 60767, 61184, 61584, |
| 61 | + 61969, 62330, 62677, 63000, 63304, 63592, 63857, 64108, 64333, 64544, |
| 62 | + 64731, 64902, 65049, 65177, 65289, 65376, 65449, 65501, 65527, 65535, |
| 63 | + 65535 |
| 64 | +}; |
| 65 | +*/ |
| 66 | + |
| 67 | + |
| 68 | +// use 255.0 as divider |
| 69 | +uint8_t isinTable8[] = { |
| 70 | + 0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, |
| 71 | + 49, 53, 57, 62, 66, 70, 75, 79, 83, 87, |
| 72 | + 91, 96, 100, 104, 108, 112, 116, 120, 124, 128, |
| 73 | + 131, 135, 139, 143, 146, 150, 153, 157, 160, 164, |
| 74 | + 167, 171, 174, 177, 180, 183, 186, 190, 192, 195, |
| 75 | + 198, 201, 204, 206, 209, 211, 214, 216, 219, 221, |
| 76 | + 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, |
| 77 | + 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, |
| 78 | + 252, 253, 253, 254, 254, 254, 255, 255, 255, 255, |
| 79 | + 255 |
| 80 | +}; |
| 81 | + |
| 82 | + |
| 83 | +/////////////////////////////////////////////////////// |
| 84 | +// |
| 85 | +// GONIO LOOKUP |
| 86 | +// |
| 87 | +float isin(float f) |
| 88 | +{ |
| 89 | + boolean pos = true; // positive |
| 90 | + if (f < 0) |
| 91 | + { |
| 92 | + f = -f; |
| 93 | + pos = !pos; |
| 94 | + } |
| 95 | + |
| 96 | + long x = f; |
| 97 | + uint8_t r = (f - x) * 256; |
| 98 | + |
| 99 | + if (x >= 360) x %= 360; |
| 100 | + |
| 101 | + int y = x; // 16 bit math is faster than 32 bit |
| 102 | + |
| 103 | + if (y >= 180) |
| 104 | + { |
| 105 | + y -= 180; |
| 106 | + pos = !pos; |
| 107 | + } |
| 108 | + |
| 109 | + if (y >= 90) |
| 110 | + { |
| 111 | + y = 180 - y; |
| 112 | + if (r != 0) |
| 113 | + { |
| 114 | + r = 255 - r; |
| 115 | + y--; |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + // float v improves ~4% on avg error for ~60 bytes. |
| 120 | + uint16_t v = isinTable16[y]; |
| 121 | + |
| 122 | + // interpolate if needed |
| 123 | + if (r > 0) |
| 124 | + { |
| 125 | + v = v + ((isinTable16[y + 1] - v) / 8 * r) /32; // == * r / 256 |
| 126 | + } |
| 127 | + float g = v * 0.0000152590219; // = /65535.0 |
| 128 | + if (pos) return g; |
| 129 | + return -g; |
| 130 | +} |
| 131 | + |
| 132 | + |
| 133 | +float icos(float x) |
| 134 | +{ |
| 135 | + // prevent modulo math if x in 0..360 |
| 136 | + return isin(x - 270.0); // better than x + 90; |
| 137 | +} |
| 138 | + |
| 139 | + |
| 140 | +float itan(float f) |
| 141 | +{ |
| 142 | + // reference |
| 143 | + // return isin(f)/icos(f); |
| 144 | + |
| 145 | + // idea is to divide two (interpolated) values from the table |
| 146 | + // so no divide by 65535 |
| 147 | + |
| 148 | + // FOLDING |
| 149 | + bool mir = false; |
| 150 | + bool neg = (f < 0); |
| 151 | + if (neg) f = -f; |
| 152 | + |
| 153 | + long x = f; |
| 154 | + float rem = f - x; |
| 155 | + if (x >= 180) x %= 180; |
| 156 | + float v = rem + x; // normalised value 0..179.9999 |
| 157 | + if (v > 90) |
| 158 | + { |
| 159 | + v = 180 - v; |
| 160 | + neg = !neg; |
| 161 | + mir = true; |
| 162 | + } |
| 163 | + uint8_t d = v; |
| 164 | + if (d == 90) return 0; |
| 165 | + |
| 166 | + // COS FIRST |
| 167 | + uint8_t p = 90 - d; |
| 168 | + float co = isinTable16[p]; |
| 169 | + if (rem != 0) |
| 170 | + { |
| 171 | + float delta = (isinTable16[p] - isinTable16[p - 1]); |
| 172 | + if (mir) co = isinTable16[p - 1] + rem * delta; |
| 173 | + else co = isinTable16[p] - rem * delta; |
| 174 | + } |
| 175 | + else if (co == 0) return 0; |
| 176 | + |
| 177 | + float si = isinTable16[d]; |
| 178 | + if (rem != 0) si += rem * (isinTable16[d + 1] - isinTable16[d]); |
| 179 | + |
| 180 | + float ta = si/co; |
| 181 | + if (neg) return -ta; |
| 182 | + return ta; |
| 183 | +} |
| 184 | + |
| 185 | + |
| 186 | +// some problem at 0 but at least we have a icot(x) cotangent. |
| 187 | +float icot(float f) |
| 188 | +{ |
| 189 | + float t = itan(f); |
| 190 | + if (t == 0) return NAN; |
| 191 | + return 1.0 / t; |
| 192 | +} |
| 193 | + |
| 194 | + |
| 195 | +// missing function... |
| 196 | +// float cot(float f) |
| 197 | +// { |
| 198 | + // return 1.0/tan(f); |
| 199 | +// } |
| 200 | + |
| 201 | + |
| 202 | +/////////////////////////////////////////////////////// |
| 203 | +// |
| 204 | +// INVERSE GONIO LOOKUP |
| 205 | +// |
| 206 | +float iasin(float f) |
| 207 | +{ |
| 208 | + bool neg = (f < 0); |
| 209 | + if (neg) |
| 210 | + { |
| 211 | + f = -f; |
| 212 | + neg = true; |
| 213 | + } |
| 214 | + uint16_t val = round(f * 65535); |
| 215 | + uint8_t lo = 0; |
| 216 | + uint8_t hi = 90; |
| 217 | + |
| 218 | + while (hi - lo > 1) |
| 219 | + { |
| 220 | + uint8_t mi = (lo + hi) / 2; |
| 221 | + if (isinTable16[mi] == val) |
| 222 | + { |
| 223 | + if (neg) return -mi; |
| 224 | + return mi; |
| 225 | + } |
| 226 | + if (isinTable16[mi] < val) lo = mi; |
| 227 | + else hi = mi; |
| 228 | + } |
| 229 | + float delta = val - isinTable16[lo]; |
| 230 | + uint16_t range = isinTable16[hi] - isinTable16[lo]; |
| 231 | + delta /= range; |
| 232 | + if (neg) return -(lo + delta); |
| 233 | + return (lo + delta); |
| 234 | +} |
| 235 | + |
| 236 | + |
| 237 | +float iacos(float f) |
| 238 | +{ |
| 239 | + return 90 - iasin(f); |
| 240 | +} |
| 241 | + |
| 242 | + |
| 243 | +// PLACEHOLDER |
| 244 | +float iatan(float f) |
| 245 | +{ |
| 246 | + return 0 * f; |
| 247 | +} |
| 248 | + |
| 249 | + |
| 250 | +// -- END OF FILE -- |
0 commit comments