Comment #3 on issue 3266 by impinball: Numeric issues in hyperbolic
functions
http://code.google.com/p/v8/issues/detail?id=3266
I have a few algorithm patch suggestions (I can't test it because my copy
currently doesn't compile):
Note: example implementations exclude type-checking, etc., and use ES6
syntax.
atanh(x) (division first reduces overflow:
log1p(x)/2 - log1p(-x)/2
Example implementation:
Math.atanh = x => log1p(x)/2 - log1p(-x)/2;
asinh(x) for large x:
|x|*sqrt(1 + (1/x)^2)
Example implementation:
Math.asinh = x => {
// sign without branching or extra method call, good for arbitrary size
let sign = (x > 0) - (x < 0);
if (x < 0) x = -x; // simplistic absolute value
// in last term of sqrt, take reciprocal in place
return sign * Math.log(x * (1 + Math.sqrt(1 + (x=1/x) * x));
}
This one merits an explanation, so here it is:
Let's first look at the current implementation (~= means approximately
equal to).
asinh x ~= | ln(x + sqrt(x^2 + 1)), x > 0
| -ln(-x + sqrt(x^2 + 1)), x < 0
(special cases excluded)
Now, let's toy around with the first one, with only positives:
log(x + sqrt(x^2 + 1))
/ |-------- \
| | 2 |
= log | x + \ | x + 1 | <-- above ASCII-ified
\ \| /
/ |------------- \
| | / 1 \ 2 |
= log | x + |x| \ | 1 + |---| |
\ \| \ x / /
/ |------------- \
| | / 1 \ 2 |
= log | x + x \ | 1 + |---| | <-- |x| = x if x > 0
\ \| \ x / /
Now, let's look at the second.
-log(-x + sqrt(x^2 + 1))
/ |-------- \
| | 2 |
= -log | -x + \ | x + 1 | <-- above ASCII-ified
\ \| /
/ |------------- \
| | / 1 \ 2 |
= -log | -x + |x| \ | 1 + |---| |
\ \| \ x / /
/ |------------- \
| | / 1 \ 2 |
= -log | -x - x \ | 1 + |---| | <-- |x| = -x if x < 0
\ \| \ x / /
If you notice, there are only two differences in the formula: the overall
sign and the sign of the x in the first term, both negative if x is
negative.
So, let l(x) be the following:
|-------------
| / 1 \ 2
1 + \ | 1 + |---|
\| \ x /
Now, we can redefine asinh x as:
asinh x ~= | log (x + |x| l(x)), x > 0
| -log (-x + |x| l(x)), x < 0
And, now, let sign(x) be the sign of x. This lets us further abstract it as
such, considering l is even and the first term is effectively |x|.
asinh x ~= sign(x) log |x| (1 + l(|x|)) <-- l(x) = l(-x), so l(x) = l(|
x|)
sign(x) = | 1 if x > 0
| -1 if x < 0
| 0 if x = 0
|-------------
| / 1 \ 2
l(x) = \ | 1 + |---| <-- close to 0 will underflow to 1
\| \ x /
The part "log |x| (1 + l(x))" cannot be further improved without potential
limit issues because these limits don't match up. to the proper limit of:
lim log |x| = -Infinity
x -> 0
lim log (1 + l(x)) = lim log (1 + 1) = log 2
x -> 0 x -> 0
lim asinh x = 0
x -> 0
This should explain my algorithm for asinh.
--
You received this message because this project is configured to send all
issue notifications to this address.
You may adjust your notification preferences at:
https://code.google.com/hosting/settings
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.