On 15/08/17 23:46, Matt Davey wrote to pd-list@lists.iem.at:
I've always used:
tanh(x) ~= x*(27+x*x) / (27+9*x*x)
works well and is pretty CPU cheap
Nice.
That seems accurate to about 5 or 6 bits in my tests (over the range -4 to 4). A slightly more accurate (about 7 or 8 bits) variant is:
x * (27.2837670294674 + 1.22070209109864 * x * x)
/ (27.2837670294674 + 9.86205301460732 * x * x)
A higher degree version is accurate to about 16 or 17 bits:
x * (44220389.1067293 + 4672204.74255456 * x * x
+ 34604.8550273853 * x * x * x * x)
/ (44220389.1067293 + 19409074.7654446 * x * x
+ 612890.122925575 * x * x * x * x)
(Though I realize now, later, that there is some redundancy and they could be normalized to have a leading "1 +" instead of these large values...)
I found these using gnuplot's fit functionality:
F(x) = x * (a + b * x * x) / (a + c * x * x)
fit F(x) 'tanh.dat' via a,b,c
and similarly for the higher degree version. 'tanh.dat' contains 1024 equally spaced samples of x,tanh(x) in [-4,4], calculated in double precision with a small C program, similar to the input generation in the help patches.
I evaluated the accuracy visually in gnuplot:
bits(x,y) = log(abs(y - tanh(x))+2**(-53)) / log(2.0)
plot [-4:4] bits(x,F(x))
I don't know if single-precision rounding will affect the results much. I put the full precision coefficients into the patches using a text editor, so double precision Pd can benefit just in case.
It's probably also best to use [clip~ -4 4] before these functions, to avoid possible Inf or NaN explosions, or maybe [clip~ -1 1] afterwards would be enough to be safe?
I haven't benchmarked yet.
Consider the patches placed into the Public Domain. Message-rate versions are left as an exercise.