ACL seems to max out at about (exp 88), the same as CMUCL, but in contrast to CMUCL there is no floating-point exception being raised. Interestingly, CMUCL's implementation of TANH is smart enough to avoid the overflow.
Since EXP and friends are specified to return a "number", I guess a clever implementation _could_ detect the overflow and return an integer (big-num) rather than failing, although I'm not sure if that's desirable.
The problem is easily avoided though, as (TANH x) is indistinguishable from 1.0 for all x>10 or so.
Daniel Buenzli wrote: > USER(15): (tanh 92.0) > #.EXCL::*NAN-SINGLE*
What value do you expect tanh 92.0 to give you?
Uhhh, scratches head, gets a sharp shooting pain, iirc tahn = (exp(x) - exp(-x))/(exp(x)+exp(-x))) I would expect to tend to 1 (since exp(92) is a large number). So in theory I would expect tanh 92.0 to return 1.0000000(and maybe some fiddly bits). However, because exp(92) is so bloody big I would be not suprised if it didn't.
* Daniel Buenzli wrote: > Hello, > Is this an ACL bug ? > USER(15): (tanh 92.0) > #.EXCL::*NAN-SINGLE*
I think it probably is. I imagine what's happening is they're using some formula using e^x and running out of single-float range, even though tanh is nowhere near out of range at that point. I'd report it to b...@franz.com
Frode> Daniel Buenzli <Daniel.Buen...@studi.epfl.ch> writes: >> Is this an ACL bug ? >> >> USER(15): (tanh 92.0) >> #.EXCL::*NAN-SINGLE*
[snip]
Frode> ACL seems to max out at about (exp 88), the same as CMUCL, but in Frode> contrast to CMUCL there is no floating-point exception being Frode> raised. Interestingly, CMUCL's implementation of TANH is smart enough Frode> to avoid the overflow.
Well, in all ports of CMUCL tanh calls out to the tanh in your C math library. So if tanh in your C library is broken, tanh in CMUCL is broken.
> ACL seems to max out at about (exp 88), the same as CMUCL, but in > contrast to CMUCL there is no floating-point exception being > raised. Interestingly, CMUCL's implementation of TANH is smart enough > to avoid the overflow.
I think it's running out of single-float range. I don't think it should though, since tanh is perfectly well-defined there.
> Since EXP and friends are specified to return a "number", I guess a > clever implementation _could_ detect the overflow and return an > integer (big-num) rather than failing, although I'm not sure if that's > desirable.
No, it's not, in fact I think it's not allowed -- the numerical contagion rules mean that (tanh x) should be of the same type as X (I think). Certainly this, or something like it, would need to be the case to allow the compiler to generate reasonable floating point code.
* Daniel Buenzli wrote: > I forgot to tell you the funny thing : > USER(1): (tanh 709) > #.EXCL::*NAN-SINGLE* > USER(2): (tanh 710) > 1.0 > USER(3): (tanh 2343254) > 1.0 > In fact it doesn't work from 89 to 709.
So they've got a test in to stop it dying through overflow, but the test assumes doubles, and it overflows with singles much earlier. (I guess the test is something like `if it's greater than this just return 1 coerced to the approprate type').
* Tim Bradshaw <t...@cley.com> | So they've got a test in to stop it dying through overflow, but the | test assumes doubles, and it overflows with singles much earlier. | (I guess the test is something like `if it's greater than this just | return 1 coerced to the approprate type').
This is all bogus. (tanh x) is defined as (/ (sinh x) (cosh x)), and those are defined as (/ (+/- (exp x) (exp (- x))) 2), but (exp x) doesn't do a test, it bloats the value to double-float, computes the value, then abbreviates it to single-float, which fails for a whole truckload of double-floats, naturally. The NaN-single result is simply that of of (/ infinity infinity).
I don't have an equally good explanation for the 1.0 result, which I actually don't get on my Intel Pentium III running Linux. *sigh*
#:Erik -- If this is not what you expected, please alter your expectations.
* Erik Naggum wrote: > I don't have an equally good explanation for the 1.0 result, which I > actually don't get on my Intel Pentium III running Linux. *sigh*
That 1.0 result for numbers where (exp x) would overflow for doubles was all I was trying to explain though. (I don't get it either actually).
When (exp (* -2 x)) < (expt 2 (- n)) where n is the number of bits of precision of the floating point number, you can simply return the result 1.0 for tanh x, because you compute (tanh x) using (/ (- 1 (exp (- (* 2 x)))) (+ 1 (exp (- (* 2 x))))) instead of (/ (- (exp x) (exp (- x))) (+ (exp x) (exp (- x))))). The underflow of (exp (- (* 2 x))) is no problem, and the result is 1.0.