8377223: Port fdlibm atanh to Java

Reviewed-by: darcy, rgiulietti
This commit is contained in:
Anton Artemov 2026-02-20 08:31:18 +00:00
parent cb70654943
commit fa2f4d82f5
7 changed files with 651 additions and 6 deletions

View File

@ -3607,4 +3607,52 @@ final class FdLibm {
}
}
}
/**
* Return the Inverse Hyperbolic Tangent of x
* Method :
*
*
* atanh(x) is defined so that atanh(tanh(alpha)) = alpha, -∞ < alpha < ∞
* and tanh(atanh(x)) = x, -1 &lt x &lt 1;
* It can be written as atanh(x) = 0.5 * log1p(2 * x/(1-x)), -1 < x < 1;
* 1.
* atanh(x) := 0.5 * log1p(2 * x/(1 - x)), if |x| >= 0.5,
* := 0.5 * log1p(2x + 2x * x/(1 - x)), if |x| < 0.5.
*
*
*
* Special cases:
* only atanh(&plusmn;0)=&plusmn;0 is exact for finite x.
* atanh(NaN) is NaN
* atanh(&plusmn;1) is &plusmn;&infin;
*/
static final class Atanh {
static double compute(double x) {
double t;
int hx,ix;
int lx; // unsigned
hx = __HI(x); // high word
lx = __LO(x); // low word
ix = hx & 0x7fff_ffff;
if ((ix | ((lx | (-lx)) >>> 31)) > 0x3ff0_0000) { // |x| > 1
return (x - x) / (x - x);
}
if (ix == 0x3ff0_0000) {
return x / 0.0;
}
if (ix < 0x3e30_0000 && (HUGE + x) > 0.0) {
return x; // x<2**-28
}
x = __HI(x, ix); // x <- |x|
if (ix < 0x3fe0_0000) { // x < 0.5
t = x + x;
t = 0.5 * Log1p.compute(t + t * x / (1.0 - x));
} else {
t = 0.5 * Log1p.compute((x + x) / (1.0 - x));
}
return hx >= 0 ? t : -t;
}
}
}

View File

@ -109,7 +109,7 @@ import static java.lang.Double.*;
* acos acos}, {@link atan atan}, {@link exp exp}, {@link expm1
* expm1}, {@link log log}, {@link log10 log10}, {@link log1p log1p},
* {@link sinh sinh}, {@link cosh cosh}, {@link tanh tanh}, {@link asinh asinh},
* {@link acosh acosh}, {@link hypot hypot}, and {@link pow pow}.
* {@link acosh acosh}, {@link atanh atanh}, {@link hypot hypot}, and {@link pow pow}.
* (The {@link sqrt sqrt} operation is a required part of IEEE 754
* from a different section of the standard.) The special case behavior
* of the recommended operations generally follows the guidance of the IEEE 754
@ -2814,6 +2814,38 @@ public final class Math {
return StrictMath.acosh(x);
}
/**
* Returns the inverse hyperbolic tangent of a {@code double} value.
* The inverse hyperbolic tangent of <i>x</i> is defined to be the function such that
* atanh({@linkplain Math#tanh tanh(<i>x</i>)}) = <i>x</i> for any <i>x</i>.
* Note that the domain of the exact atanh is (-1; 1), the range is unrestricted.
*
* <p>Special cases:
* <ul>
*
* <li>If the argument is NaN, then the result is NaN.
*
* <li>If the argument is zero, then the result is a zero with the
* same sign as the argument.
*
* <li>If the argument is {@code +1.0}, then the result is
* positive infinity.
*
* <li>If the argument is {@code -1.0}, then the result is
* negative infinity.
*
* <li>If the argument is greater than {@code 1.0} in magnitude, then the result is NaN.
*
* </ul>
* <p> The computed result must be within 2.5 ulps of the exact result.
* @param x The number whose inverse hyperbolic tangent is to be returned.
* @return The inverse hyperbolic tangent of {@code x}.
* @since 27
*/
public static double atanh(double x) {
return StrictMath.atanh(x);
}
/**
* Returns sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
* without intermediate overflow or underflow.

View File

@ -76,8 +76,8 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
* {@code exp}, {@code log}, {@code log10},
* {@code cbrt}, {@code atan2}, {@code pow},
* {@code sinh}, {@code cosh}, {@code tanh},
* {@code asinh}, {@code acosh}, {@code hypot},
* {@code expm1}, and {@code log1p}.
* {@code asinh}, {@code acosh},{@code atanh},
* {@code hypot}, {@code expm1}, and {@code log1p}.
*
* <p>
* The platform uses signed two's complement integer arithmetic with
@ -2222,6 +2222,38 @@ public final class StrictMath {
return FdLibm.Acosh.compute(x);
}
/**
* Returns the inverse hyperbolic tangent of a {@code double} value.
* The inverse hyperbolic tangent of <i>x</i> is defined to be the function such that
* atanh({@linkplain Math#tanh tanh(<i>x</i>)}) = <i>x</i> for any <i>x</i>.
* Note that the domain of the exact atanh is (-1; 1), the range is unrestricted.
*
* <p>Special cases:
* <ul>
*
* <li>If the argument is NaN, then the result is NaN.
*
* <li>If the argument is zero, then the result is a zero with the
* same sign as the argument.
*
* <li>If the argument is {@code +1.0}, then the result is
* positive infinity.
*
* <li>If the argument is {@code -1.0}, then the result is
* negative infinity.
*
* <li>If the argument is greater than {@code 1.0} in magnitude, then the result is NaN.
*
* </ul>
*
* @param x The number whose inverse hyperbolic tangent is to be returned.
* @return The inverse hyperbolic tangent of {@code x}.
* @since 27
*/
public static double atanh(double x) {
return FdLibm.Atanh.compute(x);
}
/**
* Returns sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
* without intermediate overflow or underflow.

View File

@ -27,7 +27,7 @@
* @build Tests
* @build HyperbolicTests
* @run main HyperbolicTests
* @summary Tests for {Math, StrictMath}.{sinh, cosh, tanh, asinh, acosh}
* @summary Tests for {Math, StrictMath}.{sinh, cosh, tanh, asinh, acosh, atanh}
*/
import static java.lang.Double.longBitsToDouble;
@ -45,6 +45,7 @@ public class HyperbolicTests {
failures += testTanh();
failures += testAsinh();
failures += testAcosh();
failures += testAtanh();
if (failures > 0) {
System.err.println("Testing the hyperbolic functions incurred "
@ -2101,4 +2102,387 @@ public class HyperbolicTests {
failures += Tests.testUlpDiffWithAbsBound("StrictMath.acosh", input, StrictMath::acosh, expected, ulps, Double.POSITIVE_INFINITY);
return failures;
}
/**
* Test accuracy of {Math, StrictMath}.atanh. The specified
* accuracy is 2.5 ulps.
*
* The defintion of atanh(x) is
*
* atanh(tanh(x)) = x
*
* Can be also written as
*
* 0.5 * log1p(2 * x / (1-x0))
*
* Taylor expansion:
*
* x + x^3 / 3 + x^5 / 5 + ...
*
* Therefore,
*
* 1. For small values of x, tanh(x) ~= x.
*
* Additionally, atanh is an odd function; atanh(-x) = -atanh(x).
*
*/
static int testAtanh() {
int failures = 0;
/*
* Array elements below generated using a quad atanh
* implementation. Rounded to a double, the quad result
* *should* be correctly rounded, unless we are quite unlucky.
* Assuming the quad value is a correctly rounded double, the
* allowed error is 3.0 ulps instead of 2.5 since the quad
* value rounded to double can have its own 1/2 ulp error.
*/
double [][] testCases = {
// x atanh(x)
{+0.00000000000000000000000000000000000e+00 , +0.00000000000000000000000000000000000e+00 },
{+2.00000000000000004163336342344337027e-02 , +2.00026673068495811335374182828113576e-02 },
{+4.00000000000000008326672684688674053e-02 , +4.00213538367682137458906520059156020e-02 },
{+5.99999999999999977795539507496869192e-02 , +6.00721559210316214332906986486015264e-02 },
{+8.00000000000000016653345369377348106e-02 , +8.01713250375896933655527689248809233e-02 },
{+1.00000000000000005551115123125782702e-01 , +1.00335347731075586242913545116385118e-01 },
{+1.20000000000000009436895709313830594e-01 , +1.20581028408444044805093075807633198e-01 },
{+1.40000000000000013322676295501878485e-01 , +1.40925576070493877554736186975308236e-01 },
{+1.60000000000000003330669073875469621e-01 , +1.61386696131525518759511362898215609e-01 },
{+1.79999999999999993338661852249060757e-01 , +1.81982688600705816490251036770517457e-01 },
{+1.99999999999999983346654630622651894e-01 , +2.02732554054082173641771797964103718e-01 },
{+2.19999999999999973354647408996243030e-01 , +2.23656109021832382650747515743625830e-01 },
{+2.39999999999999963362640187369834166e-01 , +2.44774112659352854083413297101694196e-01 },
{+2.59999999999999953370632965743425302e-01 , +2.66108406873654071753827618842061943e-01 },
{+2.79999999999999971134201359745929949e-01 , +2.87682072451780896117822911968144088e-01 },
{+2.99999999999999988897769753748434596e-01 , +3.09519604203111703273814331202206426e-01 },
{+3.20000000000000006661338147750939243e-01 , +3.31647108705132085025104001081840030e-01 },
{+3.40000000000000024424906541753443889e-01 , +3.54092528962242939723929765493171945e-01 },
{+3.60000000000000042188474935755948536e-01 , +3.76885901188190124469133896689497444e-01 },
{+3.80000000000000059952043329758453183e-01 , +4.00059650056056638206593741845596981e-01 },
{+4.00000000000000077715611723760957830e-01 , +4.23648930193601899373639138690042112e-01 },
{+4.20000000000000095479180117763462476e-01 , +4.47692023527420813002158901561072580e-01 },
{+4.40000000000000113242748511765967123e-01 , +4.72230804420425833981180600242988051e-01 },
{+4.60000000000000131006316905768471770e-01 , +4.97311287572031193620508878977899997e-01 },
{+4.80000000000000148769885299770976417e-01 , +5.22984277591344047465367134186014130e-01 },
{+5.00000000000000111022302462515654042e-01 , +5.49306144334054993727359235148812474e-01 },
{+5.20000000000000128785870856518158689e-01 , +5.76339754969192906113997153691857594e-01 },
{+5.40000000000000146549439250520663336e-01 , +6.04155602962267286054127265014583953e-01 },
{+5.60000000000000164313007644523167983e-01 , +6.32833186665638181077146946128475799e-01 },
{+5.80000000000000182076576038525672629e-01 , +6.62462707371799523213172030295196960e-01 },
{+6.00000000000000199840144432528177276e-01 , +6.93147180559945621667457797283512021e-01 },
{+6.20000000000000217603712826530681923e-01 , +7.25005087752999506268291290927001216e-01 },
{+6.40000000000000235367281220533186570e-01 , +7.58173744684044609195455590065769225e-01 },
{+6.60000000000000253130849614535691217e-01 , +7.92813631870191370108450047457113058e-01 },
{+6.80000000000000270894418008538195863e-01 , +8.29114038301766692728933700083100051e-01 },
{+7.00000000000000288657986402540700510e-01 , +8.67300527694053760423196460163172710e-01 },
{+7.20000000000000306421554796543205157e-01 , +9.07644983319125195441126107009775370e-01 },
{+7.40000000000000324185123190545709804e-01 , +9.50479380596524207852088721432242171e-01 },
{+7.60000000000000341948691584548214450e-01 , +9.96215082345103890579587353760865510e-01 },
{+7.80000000000000359712259978550719097e-01 , +1.04537054846688556569856922586455819e+00 },
{+8.00000000000000377475828372553223744e-01 , +1.09861228866811073993921293846013796e+00 },
{+8.20000000000000395239396766555728391e-01 , +1.15681746459031653565363995495937725e+00 },
{+8.40000000000000413002965160558233038e-01 , +1.22117351768460359355809310163905228e+00 },
{+8.60000000000000430766533554560737684e-01 , +1.29334467204897297035888921761818841e+00 },
{+8.80000000000000448530101948563242331e-01 , +1.37576765652097643587819823310934128e+00 },
{+9.00000000000000466293670342565746978e-01 , +1.47221948958322268418172604524275263e+00 },
{+9.20000000000000484057238736568251625e-01 , +1.58902691517397596123778549185721945e+00 },
{+9.40000000000000501820807130570756271e-01 , +1.73804934491764087653605718356588900e+00 },
{+9.60000000000000519584375524573260918e-01 , +1.94591014905531993245708137324632564e+00 },
{+9.80000000000000537347943918575765565e-01 , +2.29755992506730853281874022244325249e+00 },
};
for(double [] testCase : testCases) {
failures += testAtanhCaseWithUlpDiff(testCase[0],
testCase[1],
3.0);
}
for(double nan : Tests.NaNs) {
failures += testAtanhCaseWithUlpDiff(nan, NaNd, 0);
}
double [][] specialTestCases = {
{0.0, 0.0},
{-0.0, -0.0},
{1.0, Double.POSITIVE_INFINITY},
{-1.0, Double.NEGATIVE_INFINITY},
{2.0, NaNd},
{-2.0, NaNd},
};
for(double [] specialTestCase : specialTestCases) {
failures += testAtanhCaseWithUlpDiff(specialTestCase[0],
specialTestCase[1],
0.0);
}
// For powers of 2 less than 2^(-27), the second and
// subsequent terms of the Taylor series expansion will get
// rounded away since |n-n^3| > 53, the binary precision of a
// double significand.
for(int i = DoubleConsts.MIN_SUB_EXPONENT; i < -27; i++) {
double d = Math.scalb(2.0, i);
// Result and expected are the same.
failures += testAtanhCaseWithUlpDiff(d, d, 2.5);
}
failures += testAtanhAdditionalTests();
return failures;
}
/**
* Test accuracy of {Math, StrictMath}.tanh using quad precision
* tanh implementation as the reference. There are additional tests.
* The specified accuracy is 2.5 ulps.
*
*/
static int testAtanhAdditionalTests() {
int failures = 0;
/*
* Array elements below are generated using a quad precision tanh
* implementation (libquadmath). Rounded to a double, the quad result
* *should* be correctly rounded, unless we are quite unlucky.
* Assuming the quad value is a correctly rounded double, the
* allowed error is 3.0 ulps instead of 2.5 since the quad
* value rounded to double can have its own 1/2 ulp error.
*/
double[][] testCases = {
// x atanh(x)
{+9.39017107929201566562937841808889061e-01 , +1.72967155564501022599234830162276798e+00 },
{+4.56590977869321346105380143853835762e-01 , +4.92995868916526654745557405930485720e-01 },
{-6.57855028101722583144805867050308734e-01 , -7.89022676186288902931611202476188124e-01 },
{+4.62405425240985490376033339998684824e-01 , +5.00366606474614321339885208418466006e-01 },
{-9.83365261789753697385663144814316183e-01 , -2.39052856803141716223262787771779768e+00 },
{-6.27582201138608741786129030515439808e-01 , -7.37417270574716377975381198846020522e-01 },
{-9.83196938676588638728048863413278013e-01 , -2.38545217282555498582477166161511345e+00 },
{+7.36681396907350904967870519612915814e-01 , +9.43183305171108845024940622694003154e-01 },
{-7.68733978209885648880117514636367559e-01 , -1.01722532284268312448347897782273734e+00 },
{-8.99650279001481090190850409271661192e-01 , -1.47038189478731874369381319202006168e+00 },
{+6.23383381659472490810003364458680153e-02 , +6.24192773197774301522605242534216118e-02 },
{-8.14139384718910008587045012973248959e-01 , -1.13918472673420532816505691112579313e+00 },
{-4.89518635342238050967011986358556896e-01 , -5.35427075187260852558782518094419668e-01 },
{-6.08295892536873550326959048106800765e-01 , -7.06211859359034873213744847874549993e-01 },
{+9.36079053287340978606323460553539917e-01 , +1.70538649403259128938060088254525967e+00 },
{+8.31593360663532843446432707423809916e-01 , +1.19328001443669418326658153597705593e+00 },
{+6.56422583223821076714443734090309590e-01 , +7.86501511439435312578862353672697253e-01 },
{-3.45789522181036979020518629113212228e-01 , -3.60653496973375779632391162421477716e-01 },
{+5.32079052777165939502879155043046921e-01 , +5.93040792269778100045583612458499490e-01 },
{-3.36182931512335247958844774984754622e-01 , -3.49782828626977949006925091676664461e-01 },
{+6.13630231412017335124176042882027104e-01 , +7.14723430606319696079463920489037224e-01 },
{+7.39217182016670415478643008100334555e-01 , +9.48751224833067617682882507817093541e-01 },
{-7.64409441646018983362864673836156726e-03 , -7.64424330871250337925427639013540391e-03 },
{-9.74816033382744917545892349153291434e-01 , -2.18101148933100542106171185218910695e+00 },
{+5.52687515297161868765840608830330893e-01 , +6.22242584006598996817110126253907160e-01 },
{+9.93416759200363430615254856093088165e-01 , +2.85653913150680081054657418761203993e+00 },
{+9.07659865436335255850508474395610392e-01 , +1.51407684709244159021847264731507603e+00 },
{+6.60272764758356833780794659105595201e-01 , +7.93297068812459385386864151954890303e-01 },
{+9.63130814953695568725322573300218210e-01 , +1.98745986190671136058731587311090272e+00 },
{-5.70877067883640121337407435930799693e-01 , -6.48822975697686437517619163352737241e-01 },
{-8.11543971448019485492864077968988568e-01 , -1.13153503707350652581786706338031953e+00 },
{+6.25363929368137561048968109389534220e-01 , +7.33765974893577300297563917687072047e-01 },
{-2.98846490310910706256208868580870330e-01 , -3.08252492314447063039336121789383998e-01 },
{-5.97049745291272859759601487894542515e-01 , -6.88550090030688204308547683807415861e-01 },
{+8.32383827085564576009346637874841690e-01 , +1.19584817769769645815260824209818595e+00 },
{-6.63715390745103883674005373904947191e-01 , -7.99425357382537999237287552090479860e-01 },
{-3.94238412786191538828006741823628545e-01 , -4.16808558150307726736043589182851417e-01 },
{-9.76759747274416945117536670295521617e-01 , -2.22166424268955747060822814557733573e+00 },
{+8.57442746954987455865193624049425125e-01 , +1.28360612935435243492898897724236702e+00 },
{-4.24565955117479187919116156990639865e-01 , -4.53248918353154620159372526887584647e-01 },
{+3.42862260746481295470289296645205468e-01 , +3.57332492545316699435359810051341636e-01 },
{+9.34459049867542246303742103918921202e-01 , +1.69245393271799745831802454769856267e+00 },
{+7.64520478549035598092586951679550111e-01 , +1.00700514849153029184678063244721996e+00 },
{-9.63864704576277597780631367641035467e-01 , -1.99769974929677935746994673118167405e+00 },
{-1.63366842704400605512660149543080479e-01 , -1.64843919557971079920329622870569601e-01 },
{+9.94878693411232140064726081618573517e-01 , +2.98246446127683966842287869896800818e+00 },
{+7.97196021651951247655176757689332590e-01 , +1.09087153746565597453258159715989760e+00 },
{+8.42371664350162419054868223611265421e-01 , +1.22928450632196951329839160548759750e+00 },
{+6.96520087724423975217291626904625446e-01 , +8.60509501716176099565750762116593117e-01 },
{+2.01836732473232416396058397367596626e-01 , +2.04646551779576522368238234135183581e-01 },
{+5.05939365449320055390103334502782673e-01 , +5.57256946951148119219566387597645954e-01 },
{-6.01430574320412913991162895399611443e-01 , -6.95385458565007214254554832195678104e-01 },
{-4.47649318961238940062230540206655860e-01 , -4.81756612137591759595253632500957881e-01 },
{+3.37215361458020113083478008775273338e-01 , +3.50947266793232870614512911957588554e-01 },
{+5.14125575037364890285118690371746197e-01 , +5.68321583728012649428480801619053327e-01 },
{-2.15214858343344861424384362180717289e-01 , -2.18633101430445893274568498462426012e-01 },
{-9.20630621904034773805847180483397096e-01 , -1.59314811621779716899638118653946385e+00 },
{+9.19047868224296293782060729427030310e-01 , +1.58286321290197920098639225270320808e+00 },
{-2.90913484009795997309311132994480431e-01 , -2.99563914714840125917110413508169726e-01 },
{+3.17993101000002553746526245959103107e-03 , +3.17994172851141737533171613593260162e-03 },
{-7.16021961571153608971940229821484536e-01 , -8.99433586194582637259073931486986768e-01 },
{+9.92926371376932737078391255636233836e-01 , +2.82049289268529672262432232518141968e+00 },
{-7.42199723778889541847547661745920777e-01 , -9.55359320438959545982214260560204172e-01 },
{+4.01228574786033020949105321051320061e-01 , +4.25112376436892578257996500834612471e-01 },
{-4.41626489426403034954660142830107361e-01 , -4.74249574732580717257665801841627296e-01 },
{-7.21334187852223251979921769816428423e-01 , -9.10420850885118135075313207007968241e-01 },
{+2.82138790772897052328005429444601759e-01 , +2.90004322151609047453793285881602424e-01 },
{+9.42986643599090679224161704041762277e-01 , +1.76434800601646585550841462860153977e+00 },
{-5.29497382099672897481923428131267428e-01 , -5.89446464446382266025999977702386855e-01 },
{+8.90579204675862490248050562513526529e-01 , +1.42471878072594370872155352848645131e+00 },
{+7.91047774827229877026013582508312538e-01 , +1.07422521925289214702426279427778303e+00 },
{+4.75836513423619322793456376530230045e-01 , +5.17588301409701923326927500834908347e-01 },
{+9.32576831661000027473562568047782406e-01 , +1.67781041728427657120484424620161805e+00 },
{+4.49528137196881449888508086587535217e-01 , +4.84108758524071045231641283604748208e-01 },
{-6.26946229789648867836149292998015881e-01 , -7.36368746336877301544734566556181860e-01 },
{+9.58777722962137812778848910966189578e-01 , +1.93054856596755898497650787204101231e+00 },
{-9.52075725696122754371231167169753462e-01 , -1.85351320681716370080636444991087747e+00 },
{+9.66628065084665144546249848644947633e-01 , +2.03818021917486263862909093415522483e+00 },
{-9.90577960901121823411585864960215986e-01 , -2.67656438907628996596144534201915287e+00 },
{-4.29129153811968588883019037893973291e-01 , -4.58828779570547333956754968138122237e-01 },
{+9.21075240738198020018501210870454088e-01 , +1.59607267263080478465215862819487820e+00 },
{-3.36155477527195101217216688382904977e-01 , -3.49751876782073295503516199927519371e-01 },
{-4.48919523178084922676589485490694642e-01 , -4.83346273396370947315596684554195125e-01 },
{-7.74714213440744980943009068141691387e-01 , -1.03201246185914269057125935805127686e+00 },
{-9.33695607057150489538344118045642972e-01 , -1.68646605985566878841417421790327581e+00 },
{-9.70495709947644780157816057908348739e-01 , -2.10075237060881671900628221642575807e+00 },
{-9.36541591900329706277261720970273018e-01 , -1.70913713792726775520494333833202263e+00 },
{+7.37812568478896091406227242259774357e-02 , +7.39155762025176670781318988781666040e-02 },
{-5.04698425671640915624038825626485050e-01 , -5.55590478683141718256493322563558866e-01 },
{+8.86920594265426132096763467416167259e-01 , +1.40730559326330763357753153399607213e+00 },
{-5.34965721339583311078058613929897547e-01 , -5.97076103988724933820435448973192479e-01 },
{-5.04547440425485049786402669269591570e-01 , -5.55387910636784813509136387661093775e-01 },
{+6.29048733546408000982808061962714419e-01 , +7.39840413838973059800583747029269377e-01 },
{-9.78682200705922600292296920088119805e-01 , -2.26532198777189725437096465346095003e+00 },
{+2.38919916302204882185833412222564220e-03 , +2.38920370910435739436106539813089152e-03 },
{+9.39119411473845255855508185049984604e-01 , +1.73053742845170764254605902984133442e+00 },
{-6.12092729070447649775132958893664181e-01 , -7.12261063519474464072359286081706738e-01 },
{-4.28286500855559193468025114270858467e-01 , -4.57796381674494452786278030205231882e-01 },
{-3.27343597141078301859806742868386209e-01 , -3.39850137417994572135528032299471827e-01 },
{+8.67784128381645536443045330088352785e-01 , +1.32403603565363914121499259355873480e+00 },
{+7.52660015475228982850808279181364924e-01 , +9.79063037984556159433073554464697266e-01 },
{+7.94013223397652012636172003112733364e-01 , +1.08219921900739052536746217766952318e+00 },
{+7.09905313419819106179886603058548644e-01 , +8.86992950278189161084285873777251874e-01 },
{-1.98448575704946783559989853529259562e-01 , -2.01117007840272246446085014680650093e-01 },
{-5.42433878231522781376838793221395463e-01 , -6.07597742754044712584754611484481699e-01 },
{-7.54416871023775081894768845813814551e-01 , -9.83128156322049799142775913826928208e-01 },
{+3.79392548957375952412007791281212121e-01 , +3.99349870596906125894068556877626311e-01 },
{-7.19279634651493138264299886941444129e-01 , -9.06150816136239309657351447814954486e-01 },
{-7.23976590297829680764607473975047469e-01 , -9.15951596268038628402616624621418121e-01 },
{+9.31431733675747830503155455517116934e-01 , +1.66909350005993386837360519102696526e+00 },
{+5.37270796945802042721140878711594269e-01 , +6.00310952521635654514167563653463826e-01 },
{+5.05516649275373541883027428411878645e-01 , +5.56688962620397076749424137775916558e-01 },
{+6.47849417517198489235852321144193411e-01 , +7.71583729081504579676124881689567952e-01 },
{-5.41124640015404612114480187301523983e-01 , -6.05744544146300297202878069447139070e-01 },
{+8.08308086737189235293499223189428449e-01 , +1.12212873178291911884370700806026369e+00 },
{-3.98280706273062445887944704736582935e-01 , -4.21603823445725768059979840445297322e-01 },
{+8.21296094676341903451088910514954478e-01 , +1.16078669527372101102128788451037300e+00 },
{+8.31294185704192667429879293194971979e-01 , +1.19231087346512905437819601187290515e+00 },
{+7.75279686135698531401772015669848770e-01 , +1.03342833983253459558199442655538342e+00 },
{+8.63016425798844855066249692754354328e-01 , +1.30504558255929258800082186193362940e+00 },
{-4.01121200686206158536606380948796868e-01 , -4.24984406726507784951210586374028211e-01 },
{-7.26296876814658931564849808637518436e-01 , -9.20844916340064967501644052845522852e-01 },
{-6.51251452570346556214531119621824473e-01 , -7.77468783732375082858572957021836038e-01 },
{-3.38884333978433982537126212264411151e-01 , -3.52831574304372263524860719607206882e-01 },
{+1.72392299987310537723317338532069698e-01 , +1.74131195612490806064041759672764899e-01 },
{-5.51462898378643817665079041034914553e-01 , -6.20481084171861782978180187043219425e-01 },
{-9.64904165725041895740332620334811509e-01 , -2.01255815534358709601688745544440155e+00 },
{+4.86038064330916674826710277557140216e-01 , +5.30859816325958819695652448239234798e-01 },
{-1.71510111227157313606994648580439389e-01 , -1.73222128192418256096782313598032358e-01 },
{-6.40878189659797481425584919634275138e-01 , -7.59662611746376207791374637040653373e-01 },
{-9.21153045478257270772814990777987987e-01 , -1.59658607015886876829589111732687615e+00 },
{+9.25949497320595948934851548983715475e-01 , +1.62921352070439068555146795332724838e+00 },
{+6.67107753751613463677472282142844051e-02 , +6.68100020655284551850585715148980622e-02 },
{-7.11704678755497255338013928849250078e-01 , -8.90629832677982628857274943637335499e-01 },
{+2.35257760530820814182106914813630283e-01 , +2.39748052543229836539708777609029562e-01 },
{-5.99809116170998191108765240642242134e-01 , -6.92848977932719794607448570102282265e-01 },
{+2.36856137326988402946881251409649849e-02 , +2.36900444994942435090279187572837691e-02 },
{+4.79753735068501274696473046788014472e-01 , +5.22664335906700767137176554743504717e-01 },
{-6.67813223642592657114391840877942741e-02 , -6.68808647504004031806529934863158282e-02 },
{+4.94668485437996574560770568496081978e-01 , +5.42222516993971658066335656775147071e-01 },
{+9.22379519394591618208778527332469821e-01 , +1.60474385650308389567794994129179836e+00 },
{+8.66971245297548764874306925776181743e-01 , +1.32075371812223257408713093011711133e+00 },
{-4.12983669850965462444492004578933120e-01 , -4.39203093212737172928023065922190938e-01 },
{-5.47462091173417153555647018947638571e-01 , -6.14749985698478964136871989998405650e-01 },
{+1.94666780724803700763914093840867281e-02 , +1.94691376077079831895420594672983760e-02 },
{+7.50017550413333511372115935955662280e-01 , +9.72995190965114870405588062706564568e-01 },
{+4.63499306097077345967250039393547922e-01 , +5.01758888267043269595832923648429311e-01 },
{-8.37886773978241183868931329925544560e-01 , -1.21403834050977292529923613488719174e+00 },
{-8.44836969187467534680990866036154330e-01 , -1.23783490656982630833439816713451784e+00 },
{-6.25239150214307315422956889960914850e-02 , -6.26055803188625957299760516982282628e-02 },
{+9.22830248275150921699605532921850681e-01 , +1.60777295202485947753242989620181993e+00 },
{-4.00102773592881266750964641687460244e-01 , -4.23771285697601852943736383483221011e-01 },
{-2.14797176230649089490043479599989951e-01 , -2.18195175029126913051736730604906575e-01 },
{+8.02345358196084879054410521348472685e-01 , +1.10516139904369984294917445650114715e+00 },
{-4.71866662797370439719202295236755162e-01 , -5.12468964220618253719339326228366982e-01 },
{-5.92911187960187158196845302882138640e-01 , -6.82143591940237868513886526048905163e-01 },
{-8.76501962797874289989863427763339132e-01 , -1.36046970086086594286889855837180352e+00 },
{-7.98090332703508265055347692396026105e-01 , -1.09333002432404366596746493295830794e+00 },
{-9.95891457501823618159164652752224356e-01 , -3.09288886654198972890077598351970075e+00 },
{+8.90238675794242206862350030860397965e-01 , +1.42307507755399321220435398978827125e+00 },
{+2.65017376806080395823528306209482253e-01 , +2.71497140326271882216423312414093371e-01 },
{-8.86140475954999118357591214589774609e-01 , -1.40366125031104099709908824399414822e+00 },
{-2.77209688130732434530045793508179486e-01 , -2.84656945620440202957754725962273832e-01 },
{-5.61942305274404585446745841181837022e-01 , -6.35667384226952551579962809234573845e-01 },
{+5.85899688875965107826004896196536720e-01 , +6.71399455223037749672225055315941521e-01 },
{+2.89700970360319720597885861934628338e-01 , +2.98239807343473574150289333944139019e-01 },
{+6.75650398573335864149669305334100500e-01 , +8.21067357862862215855289466859201333e-01 },
{+8.44595640831392491243434506031917408e-01 , +1.23699243938765398083225288313951255e+00 },
{+7.51976945151026199276600436860462651e-01 , +9.77489203652249672733902415356008597e-01 },
{+5.84881385823573185511747851705877110e-01 , +6.69850275691608515819691751205471169e-01 },
{+1.23322570031297651382828917121514678e-01 , +1.23953519549355101274007946363965461e-01 },
{-2.47363663564394764549092542438302189e-01 , -2.52602687864803306420298300961589174e-01 },
{-8.72948142869468535209875881264451891e-01 , -1.34533684420626699711543794108336721e+00 },
{+8.66853617575293000641067919787019491e-01 , +1.32028029629708106765994282266545478e+00 },
{+9.65229404828656933901243064610753208e-02 , +9.68243850830075059690451893341587506e-02 },
{-5.83777226707343555034412929671816528e-01 , -6.68173646565246900863367519530400319e-01 },
{+9.94603681374665704595372517360374331e-01 , +2.95624183430168683072844226874046298e+00 },
{+7.54573357889273710341626610897947103e-01 , +9.83491456493016558037612443042858735e-01 },
{-8.72065566686865079049084670259617269e-01 , -1.34163989421242748094845640631675400e+00 },
{-1.57050652646726351946426802896894515e-01 , -1.58361317756145752747805962366582739e-01 },
{+9.07524513496185902816648649604758248e-01 , +1.51330900778040915728163457702896072e+00 },
{+8.88013640284071148478517443436430767e-01 , +1.41245174788920614220523066982061669e+00 },
{+5.25920210223992712350593592418590561e-01 , +5.84488641604906625861481645606402185e-01 },
{-8.55361269493308373768059027497656643e-01 , -1.27579779541753266418749325433063584e+00 },
{+7.52458416629113502338555008464027196e-01 , +9.78598154541206783526807546834975210e-01 },
{+2.11594554867804984787937883083941415e-01 , +2.14840051580673426585151516223475322e-01 },
{-8.77614995063785929829691667691804469e-01 , -1.36529288845779405074788706705067271e+00 },
{-8.13140811836136734314095519948750734e-01 , -1.13623027343457311746522665305747518e+00 },
{-9.09625945665704094267312029842287302e-03 , -9.09651034981903612229998860206266111e-03 },
{+7.11723260837115345722736492461990565e-01 , +8.90667489144918362129731310184000150e-01 },
{-8.83729688568336113618784111167769879e-01 , -1.39254560811946769303745792066561506e+00 },
{+2.81119771587539202251093684026272967e-01 , +2.88897516488748428420498810336047168e-01 },
{+8.67969571335847511761585337808355689e-01 , +1.32478745650884654793737485679177607e+00 },
{+3.71711284421433640901000217127148062e-01 , +3.90407276521447439801268385319531263e-01 },
{-5.53264526894389874200896883849054575e-01 , -6.23073752400105167233817313285610373e-01 },
{-7.50972436681106358946635737083852291e-01 , -9.75181502145488477599896301261990367e-01 },
{+6.22632428081477007353328190220054239e-01 , +7.29292680370939598849165484001382202e-01 },
{-5.93039523143406244187758602492976934e-01 , -6.82341523923040079633725976448706286e-01 },
{-6.21804927349977942796499519317876548e-01 , -7.27942416494347815893737620840227454e-01 },
{-5.91667199221579398482617762056179345e-01 , -6.80227384371192279205589233595913495e-01 },
};
for (double[] testCase : testCases) {
failures += testAtanhCaseWithUlpDiff(testCase[0],
testCase[1],
3.0);
}
return failures;
}
public static int testAtanhCaseWithTolerance(double input,
double expected,
double tolerance) {
int failures = 0;
failures += Tests.testTolerance("Math.atanh", input, Math::atanh, expected, tolerance);
failures += Tests.testTolerance("Math.atanh", -input, Math::atanh, -expected, tolerance);
failures += Tests.testTolerance("StrictMath.atanh", input, StrictMath::atanh, expected, tolerance);
failures += Tests.testTolerance("StrictMath.atanh", -input, StrictMath::atanh, -expected, tolerance);
return failures;
}
public static int testAtanhCaseWithUlpDiff(double input,
double expected,
double ulps) {
int failures = 0;
failures += Tests.testUlpDiffWithAbsBound("Math.atanh", input, Math::atanh, expected, ulps, Double.POSITIVE_INFINITY);
failures += Tests.testUlpDiffWithAbsBound("Math.atanh", -input, Math::atanh, -expected, ulps, Double.POSITIVE_INFINITY);
failures += Tests.testUlpDiffWithAbsBound("StrictMath.atanh", input, StrictMath::atanh, expected, ulps, Double.POSITIVE_INFINITY);
failures += Tests.testUlpDiffWithAbsBound("StrictMath.atanh", -input, StrictMath::atanh, -expected, ulps, Double.POSITIVE_INFINITY);
return failures;
}
}

View File

@ -94,6 +94,7 @@ public class ExhaustingTests {
new UnaryTestCase("asinh", FdlibmTranslit::asinh, StrictMath::asinh, DEFAULT_SHIFT),
new UnaryTestCase("acosh", FdlibmTranslit::acosh, StrictMath::acosh, DEFAULT_SHIFT),
new UnaryTestCase("atanh", FdlibmTranslit::atanh, StrictMath::atanh, DEFAULT_SHIFT),
};
for (var testCase : testCases) {

View File

@ -148,6 +148,10 @@ public class FdlibmTranslit {
return Acosh.compute(x);
}
public static double atanh(double x) {
return Atanh.compute(x);
}
public static double IEEEremainder(double f1, double f2) {
return IEEEremainder.compute(f1, f2);
}
@ -2841,4 +2845,50 @@ public class FdlibmTranslit {
}
}
}
/*
* Return the Inverse Hyperbolic Tangent of x
*
* Method :
* 1.Reduced x to positive by atanh(-x) = -atanh(x)
* 2.For x>=0.5
* 1 2x x
* atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
* 2 1 - x 1 - x
*
* For x<0.5
* atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
*
* Special cases:
* atanh(x) is NaN if |x| > 1 with signal;
* atanh(NaN) is that NaN with no signal;
* atanh(+-1) is +-INF with signal.
*
*/
private static final class Atanh {
private static final double zero = 0.0;
private static final double one = 1.0;
private static final double huge = 1.0e300;
static double compute(double x) {
double t;
int hx,ix;
/*unsigned*/ int lx;
hx = __HI(x); /* high word */
lx = __LO(x); /* low word */
ix = hx&0x7fffffff;
if ((ix|((lx|(-lx))>>>31))>0x3ff00000) /* |x|>1 */
return (x-x)/(x-x);
if(ix==0x3ff00000)
return x/zero;
if(ix<0x3e300000&&(huge+x)>zero) return x; /* x<2**-28 */
x = __HI(x, ix); /* x <- |x| */
if(ix<0x3fe00000) { /* x < 0.5 */
t = x+x;
t = 0.5*log1p(t+t*x/(one-x));
} else
t = 0.5*log1p((x+x)/(one-x));
if(hx>=0) return t; else return -t;
}
}
}

View File

@ -34,7 +34,7 @@ import java.util.function.DoubleUnaryOperator;
* @build FdlibmTranslit
* @build HyperbolicTests
* @run main HyperbolicTests
* @summary Tests for StrictMath.{sinh, cosh, tanh, asinh, acosh}
* @summary Tests for StrictMath.{sinh, cosh, tanh, asinh, acosh, atanh}
*/
/**
@ -60,12 +60,14 @@ public class HyperbolicTests {
failures += testAgainstTranslitSinh();
failures += testAgainstTranslitCosh();
failures += testAgainstTranslitTanh();
failures += testAgainstTranslitAtanh();
failures += testSinh();
failures += testCosh();
failures += testTanh();
failures += testAsinh();
failures += testAcosh();
failures += testAtanh();
if (failures > 0) {
System.err.println("Testing the hyperbolics incurred "
@ -82,7 +84,8 @@ public class HyperbolicTests {
COSH(HyperbolicTests::testCoshCase, FdlibmTranslit::cosh),
TANH(HyperbolicTests::testTanhCase, FdlibmTranslit::tanh),
ASINH(HyperbolicTests::testAsinhCase, FdlibmTranslit::asinh),
ACOSH(HyperbolicTests::testAcoshCase, FdlibmTranslit::acosh);
ACOSH(HyperbolicTests::testAcoshCase, FdlibmTranslit::acosh),
ATANH(HyperbolicTests::testAtanhCase, FdlibmTranslit::atanh);
private DoubleDoubleToInt testCase;
private DoubleUnaryOperator transliteration;
@ -216,6 +219,31 @@ public class HyperbolicTests {
return failures;
}
/**
* Test StrictMath.tanh against transliteration port of tanh
*/
private static int testAgainstTranslitAtanh() {
int failures = 0;
double x;
// Probe near decision points in the FDLIBM algorithm.
double[] decisionPoints = {
0.0,
0x1.0p-28,
-0x1.0p-28,
1.0,
-1.0,
};
for (double testPoint : decisionPoints) {
failures += testRangeMidpoint(testPoint, Math.ulp(testPoint), 1000, HyperbolicTest.ATANH);
}
return failures;
}
private interface DoubleDoubleToInt {
int apply(double x, double y);
}
@ -267,6 +295,11 @@ public class HyperbolicTests {
StrictMath::acosh, expected);
}
private static int testAtanhCase(double input, double expected) {
return Tests.test("StrictMath.atanh(double)", input,
StrictMath::atanh, expected);
}
private static int testSinh() {
int failures = 0;
double [][] testCases = {
@ -618,4 +651,69 @@ public class HyperbolicTests {
return failures;
}
private static int testAtanh() {
int failures = 0;
double [][] testCases = {
{0x1.5798ee2308c36p-27, 0x1.5798ee2308c37p-27},
{0x1.ffffffffffffep-26, 0x1p-25},
{0x1.ffffffffffffep-25, 0x1.0000000000004p-24},
{0x1.ad7f29abcaf47p-24, 0x1.ad7f29abcaf6p-24},
{0x1.ad7f29abcaf48p-24, 0x1.ad7f29abcaf61p-24},
{0x1.ffffffffffffep-24, 0x1.0000000000014p-23},
{0x1.ffffffffffffep-23, 0x1.0000000000054p-22},
{0x1.ffffffffffffep-22, 0x1.0000000000154p-21},
{0x1.ffffffffffffep-21, 0x1.0000000000554p-20},
{0x1.0c6f7a0b5ed8dp-20, 0x1.0c6f7a0b5f3b3p-20},
{0x1.ffffffffffffep-20, 0x1.0000000001554p-19},
{0x1.ffffffffffffep-19, 0x1.0000000005554p-18},
{0x1.fffffffffffffp-18, 0x1.0000000015555p-17},
{0x1p-17, 0x1.0000000015555p-17},
{0x1.4f8b588e368edp-17, 0x1.4f8b588e6698bp-17},
{0x1.fffffffffffffp-17, 0x1.0000000055555p-16},
{0x1.fffffffffffffp-16, 0x1.0000000155555p-15},
{0x1p-15, 0x1.0000000155555p-15},
{0x1.fffffffffe5ddp-15, 0x1.0000000554844p-14},
{0x1.fffffffffffffp-15, 0x1.0000000555555p-14},
{0x1.a36e2eb1c432dp-14, 0x1.a36e2ec938ff8p-14},
{0x1.ffffffffffffep-14, 0x1.0000001555555p-13},
{0x1p-13, 0x1.0000001555556p-13},
{0x1.ffffffffffd51p-13, 0x1.0000005555401p-12},
{0x1.fffffffffffffp-13, 0x1.0000005555559p-12},
{0x1.ffffffffffffep-12, 0x1.0000015555587p-11},
{0x1p-11, 0x1.0000015555588p-11},
{0x1.fffffffffff1p-11, 0x1.0000055555811p-10},
{0x1p-10, 0x1.0000055555889p-10},
{0x1.0624dd2f1a9c6p-10, 0x1.0624e2e91ece1p-10},
{0x1.0624dd2f1a9f8p-10, 0x1.0624e2e91ed13p-10},
{0x1.fffffffffffddp-10, 0x1.0000155558877p-9},
{0x1.fffffffffffffp-10, 0x1.0000155558888p-9},
{0x1.ffffffffffffcp-9, 0x1.0000555588889p-8},
{0x1.ffffffffffffep-9, 0x1.000055558888ap-8},
{0x1.ffffffffffff8p-8, 0x1.0001555888917p-7},
{0x1.ffffffffffffep-8, 0x1.000155588891ap-7},
{0x1.47ae147ae1458p-7, 0x1.47b0e059d0574p-7},
{0x1.47ae147ae1464p-7, 0x1.47b0e059d058p-7},
{0x1.ffffffffffffep-7, 0x1.000555888ad1bp-6},
{0x1.fffffffffffffp-7, 0x1.000555888ad1cp-6},
{0x1.ffffffffffff9p-6, 0x1.001558891aedep-5},
{0x1.ffffffffffffep-6, 0x1.001558891aee1p-5},
{0x1.ffffffffffff9p-5, 0x1.005588ad375a9p-4},
{0x1.fffffffffffffp-5, 0x1.005588ad375acp-4},
{0x1.9999999999996p-4, 0x1.9af93cd23440ep-4},
{0x1.9999999999997p-4, 0x1.9af93cd23440fp-4},
{0x1.fffffffffffffp-4, 0x1.015891c9eaef7p-3},
{0x1p-3, 0x1.015891c9eaef7p-3},
{0x1.fffffffffffffp-3, 0x1.058aefa811451p-2},
{0x1.ffffffffffffcp-2, 0x1.193ea7aad0308p-1},
{0x1.ffffffffffffep-2, 0x1.193ea7aad0309p-1},
{0x1.ffffffffffffbp-1, 0x1.1e9067763b478p+4},
{0x1.ffffffffffffep-1, 0x1.25e4f7b2737fap+4},
};
for (double[] testCase: testCases)
failures += testAtanhCase(testCase[0], testCase[1]);
return failures;
}
}