8375285: Port of fdlibm asinh function

This commit is contained in:
Anton Artemov 2026-01-15 16:59:03 +01:00 committed by Anton Artemov
parent d0aae04d61
commit dbfce1c9b9
7 changed files with 576 additions and 3 deletions

View File

@ -3508,4 +3508,57 @@ final class FdLibm {
return iz;
}
}
/**
* Return the Inverse Hyperbolic Sine of x
*
* Method :
*
*
* asinh(x) is defined so that asinh(sinh(alpha)) = alpha -INF < alpha < < INF
* and sinh(asinh(x)) = x, -INF < x < INF.
* It can be written as asinh(x) = ln(x + sqrt(x^2 + 1)), -INF < x < INF.
* 1. Replace x by |x| as the function is odd.
* 2.
* asinh(x) := x, if 1+x^2 = 1,
* := sign(x)*(log(x)+ln2)) for large |x|, else
* := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
* := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
*
*
*
* Special cases:
* only asinh(0)=0 is exact for finite x.
* asinh(NaN) is NaN
* asinh(INF) is INF
*/
static final class Asinh {
private static final double ln2 = 6.93147180559945286227e-01;
private static final double huge = 1.0e300;
static double compute(double x) {
double t,w;
int hx,ix;
hx = __HI(x);
ix = hx&0x7fffffff;
if(ix >= 0x7ff00000) {
return x + x; /* x is inf or NaN */
}
if(ix < 0x3e300000) { /* |x| < 2**-28 */
if(huge + x > 1.0) {
return x; /* return x inexact except 0 */
}
}
if(ix > 0x41b00000) { /* |x| > 2**28 */
w = Log.compute(Math.abs(x)) + ln2;
} else if (ix > 0x40000000) { /* 2**28 > |x| > 2.0 */
t = Math.abs(x);
w = Log.compute(2.0 * t + 1.0 / (Sqrt.compute(x * x + 1.0) + t));
} else { /* 2.0 > |x| > 2**-28 */
t = x * x;
w = Log1p.compute(Math.abs(x) + t / (1.0 + Sqrt.compute(1.0 + t)));
}
return hx > 0 ? w : -w;
}
}
}

View File

@ -2758,6 +2758,31 @@ public final class Math {
return StrictMath.tanh(x);
}
/**
* Returns the inverse hyperbolic sine of a {@code double} value.
* The inverse hyperbolic sine of <i>x</i> is defined to be a function such that
* asinh({@linkplain Math#sinh sinh(<i>x</i>)}) = <i>x</i> for any <i>x</i>.
* Note that range of the exact asinh is not limited.
* <p>Special cases:
* <ul>
*
* <li>If the argument is zero, then the result is a zero with the
* same sign as the argument.
*
* <li>If the argument is positive infinity, then the result is
* positive infinity
*
* <li>If the argument is negative infinity, then the result is
* negative infinity
*
* </ul>
* @param x The number whose inverse hyperbolic sine is to be returned.
* @return The inverse hyperbolic sine of {@code x}.
*/
public static double asinh(double x) {
return StrictMath.asinh(x);
}
/**
* Returns sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
* without intermediate overflow or underflow.

View File

@ -2170,6 +2170,31 @@ public final class StrictMath {
return FdLibm.Tanh.compute(x);
}
/**
* Returns the inverse hyperbolic sine of a {@code double} value.
* The inverse hyperbolic sine of <i>x</i> is defined to be a function such that
* asinh({@linkplain Math#sinh sinh(<i>x</i>)}) = <i>x</i> for any <i>x</i>.
* Note that range of the exact asinh is not limited.
* <p>Special cases:
* <ul>
*
* <li>If the argument is zero, then the result is a zero with the
* same sign as the argument.
*
* <li>If the argument is positive infinity, then the result is
* positive infinity
*
* <li>If the argument is negative infinity, then the result is
* negative infinity
*
* </ul>
* @param x The number whose inverse hyperbolic sine is to be returned.
* @return The inverse hyperbolic sine of {@code x}.
*/
public static double asinh(double x) {
return FdLibm.Asinh.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}
* @summary Tests for {Math, StrictMath}.{sinh, cosh, tanh, asinh}
*/
import static java.lang.Double.longBitsToDouble;
@ -43,6 +43,7 @@ public class HyperbolicTests {
failures += testSinh();
failures += testCosh();
failures += testTanh();
failures += testAsinh();
if (failures > 0) {
System.err.println("Testing the hyperbolic functions incurred "
@ -1390,4 +1391,348 @@ public class HyperbolicTests {
failures += Tests.testUlpDiffWithAbsBound("StrictMath.tanh", -input, StrictMath::tanh, -expected, ulps, 1.0);
return failures;
}
/**
* Test accuracy of {Math, StrictMath}.asinh. The specified
* accuracy is 2.5 ulps.
*
* The defintion of asinh(x) is
*
* asinh(sinh(x)) = x
*
* Can be also written as
*
* asinh(x) = ln(x + sqrt(x*x + 1))
*
* The series expansion of asinh(x) =
*
* x - x^3/6 + 3x^5/40 - 15x^7/336 + ...
*
* Therefore,
*
* 1. For large values of x asinh(x) ~= signum(x)
*
* 2. For small values of x, asinh(x) ~= x.
*
* Additionally, asinh is an odd function; asinh(-x) = -asinh(x).
*
*/
static int testAsinh() {
int failures = 0;
/*
* Array elements below generated using a quad asinh
* 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 asinh(x)
{+8.08576586004706676646947016706690192e+00 , +2.78705446940175084037519072068240843e+00 },
{+5.71198448718283557923314219806343317e+00 , +2.44328951112537869179362382769224610e+00 },
{+5.13969133196956207143557548988610506e+00 , +2.33947242588811531576718987896918712e+00 },
{+2.95996078504353032911922127823345363e+00 , +1.80570832446450945675615676944433187e+00 },
{+4.16200980791957864113328469102270901e+00 , +2.13327472868053919998765640756092875e+00 },
{+3.69545071772785460595400763850193471e+00 , +2.01807302682646291458685219028816252e+00 },
{+1.37724078256330018099617973348358646e+00 , +1.12468193910119796648577714130477538e+00 },
{+8.42544369040329677034151245607063174e+00 , +2.82790657643842246518401899587920414e+00 },
{+3.91229039061375782893037467147223651e+00 , +2.07321736531667549827684130235156669e+00 },
{+5.73782778462038400846267904853448272e+00 , +2.44773637486997939825874893068408245e+00 },
{+4.99855755102017340618658636230975389e+00 , +2.31215541451092776291779112133540281e+00 },
{+8.10100320171622989562365546589717269e+00 , +2.78892295229049846951081695322303143e+00 },
{+6.40711498894297992734436775208450854e+00 , +2.55659134739804960225496541857063844e+00 },
{+4.25639664782793492037171745323576033e+00 , +2.15509221067754853744881157535735520e+00 },
{+2.65061122655180847473843641637358814e+00 , +1.70175906719364776650786532519668576e+00 },
{+3.14233404262031967846269253641366959e+00 , +1.86252059324271515969573278167449533e+00 },
{+9.13083295141416328988270834088325500e+00 , +2.90778930976529177537743330080053959e+00 },
{+9.34996922888940673601609887555241585e+00 , +2.93136773795688457445658002134152253e+00 },
{+9.35132773574746245515143527882173657e+00 , +2.93151219897178112284587212807769745e+00 },
{+1.47453686867873412502660812606336549e+00 , +1.18055530917929730380021873702412893e+00 },
{+2.93708318858647077220780374773312360e+00 , +1.79836038745797816082436481350298220e+00 },
{+4.09105467685985679793247982161119580e+00 , +2.11656320434131763040467250984368994e+00 },
{+4.65121160775030162426446622703224421e+00 , +2.24163561547669988062740649953739512e+00 },
{+8.83128600332669755346159945474937558e+00 , +2.87463799399744068863572725409458990e+00 },
{+1.66240543263013162977870251779677346e+00 , +1.28160121300334421559587040333022048e+00 },
{+4.58372145493984728403802364482544363e+00 , +2.22735027800562207352532152241704895e+00 },
{+8.50271775332108248335316602606326342e+00 , +2.83697322459569158510957272430255446e+00 },
{+8.82962635800362249938189052045345306e+00 , +2.87445124207064977822740131999732509e+00 },
{+8.84552264926561093716372852213680744e+00 , +2.87623855339831018046947582541398439e+00 },
{+3.12516324361785047258877057174686342e+00 , +1.85730059825198435603813107760370448e+00 },
{+8.26480987017928114823916985187679529e+00 , +2.80879391905067271939218423695889677e+00 },
{+9.68117403887023186825899756513535976e+00 , +2.96598712423961990106836581021055404e+00 },
{+3.05372997660021550103692788979969919e+00 , +1.83530180662998049991392377010746750e+00 },
{+4.40157829954937795946534606628119946e+00 , +2.18777148553475610871290743261274356e+00 },
{+6.88055177977352627749496605247259140e+00 , +2.62708540897893209827881652490154282e+00 },
{+5.98475681846005524988640900119207799e+00 , +2.48927078678959642161006322827411013e+00 },
{+8.92994029487849694248779996996745467e+00 , +2.88567728733406656162446662917506943e+00 },
{+3.12419716639021327608816136489622295e+00 , +1.85700613402604977963039277274730202e+00 },
{+7.51161063055123179310612613335251808e+00 , +2.71399864345854847918135863803957037e+00 },
{+1.17944590788822001314883891609497368e+00 , +1.00274792631001937429660854217557106e+00 },
{+1.36421200272156672994583459512796253e+00 , +1.11700316010328101318941761315262905e+00 },
{+6.88888479910741580169997178018093109e+00 , +2.62828320452398770553274423944254222e+00 },
{+3.64699814082431839068476620013825595e+00 , +2.00533888971591775569462526134655508e+00 },
{+1.41057156993997545590957543026888743e+00 , +1.14411132290221221244416446367286189e+00 },
{+6.14945472638136703125155690941028297e+00 , +2.51605697935151660544323868421618014e+00 },
{+6.02996213994895136067952989833429456e+00 , +2.49669366977555745163814756818745494e+00 },
{+9.65271660518461160904735152143985033e+00 , +2.96305895992701909105343212587439308e+00 },
{+3.48339981002946785793028539046645164e+00 , +1.96115002199047863383320140967526859e+00 },
{+6.07995920803143352628694628947414458e+00 , +2.50484056235894688250578712446408489e+00 },
{+6.00204567486939666309808671940118074e+00 , +2.49211610375224051369293822349155577e+00 },
{+1.38833519546032624347731143643613905e+00 , +1.13118326188543957732445742827584178e+00 },
{+4.52480967383013776839106867555528879e+00 , +2.21471559269073802833304398595496088e+00 },
{+6.11810275538071746126433936296962202e+00 , +2.51101220932060589427300910397289711e+00 },
{+7.50648056792778461954185331705957651e+00 , +2.71332143777867740825109248925661428e+00 },
{+4.89658239129396388733539424720220268e+00 , +2.29195213807282224382341089459270833e+00 },
{+2.79265817118974496446881516931171063e-02 , +2.79229530231546570990366385479747555e-02 },
{+9.69315108025863381158160336781293154e+00 , +2.96721697176250274577477693915618144e+00 },
{+7.83910637998812109827895255875773728e+00 , +2.75631566551255789285879320458504177e+00 },
{+2.76576984498692324265789466153364629e+00 , +1.74165321687466923031477628544545184e+00 },
{+4.99754435738235347486124737770296633e+00 , +2.31195663638515281361584735869808938e+00 },
{+4.88922334987356776991873630322515965e+00 , +2.29047857490944287858591282873426921e+00 },
{+2.78689754339832429508305722265504301e+00 , +1.74881289991707628903792141369254180e+00 },
{+7.20931795462930935514123120810836554e+00 , +2.67329726418547732793921189411944602e+00 },
{+8.33063517511005890980868571205064654e+00 , +2.81666990685356361031034871477442414e+00 },
{+3.61188437237348836106320959515869617e+00 , +1.99601167970722876532263572785839092e+00 },
{+5.32263649620131218398455530405044556e+00 , +2.37382580077770566473979021057511520e+00 },
{+8.00366962656528002639788610395044088e+00 , +2.77692733912554343763823757722995583e+00 },
{+4.59751681469834139193153532687574625e+00 , +2.23028654083102682106197643909523811e+00 },
{+8.20253764279967612083055428229272366e+00 , +2.80128593985583624900402694440723735e+00 },
{+8.81590969774593169461240904638543725e+00 , +2.87290644386803298326256037256286587e+00 },
{+9.00323408655057377814046049024909735e+00 , +2.89380106762776953348709842638973283e+00 },
{+7.21533058010746941590696224011480808e+00 , +2.67412302459536699184126235350224069e+00 },
{+8.23695914498319758934030687669292092e+00 , +2.80544295419888555964661400747277886e+00 },
{+9.66912482942344198022510681767016649e+00 , +2.96474834621717039972248353595994898e+00 },
{+3.17602315814959101913927952409721911e+00 , +1.87268737666193382172385150977422494e+00 },
{+6.90930101488594594627556944033131003e+00 , +2.63121186253032074408677485367709385e+00 },
{+6.52386312488162189993090578354895115e+00 , +2.57443674633460769002260368508028529e+00 },
{+8.33701897902340283152966549096163362e-01 , +7.58769250678348128717944053061372995e-01 },
{+1.84073794668312284983358040335588157e+00 , +1.37005541332928719568137972151743439e+00 },
{+3.74278586498477183752697783347684890e+00 , +2.03036413719335448282150464654423886e+00 },
{+1.24005876679504356552286026271758601e+00 , +1.04136768247874493368196676622778561e+00 },
{+5.46039591734140294931876269401982427e+00 , +2.39894972726732001224686289699275119e+00 },
{+2.05576175637293001585703677847050130e+00 , +1.46829835554351749799178251325101620e+00 },
{+8.14075272140118322283797169802710414e+00 , +2.79378100004325258561034629239868920e+00 },
{+1.83236824312878154863426516385516152e+00 , +1.36605297794115641494849841805273118e+00 },
{+3.75374287549383511830569659650791436e+00 , +2.03318857169224539730556063537088565e+00 },
{+6.43073501869452779367009043198777363e-01 , +6.05407648939611618428355730173212664e-01 },
{+3.48621711345758855671306264412123710e+00 , +1.96192711264291527976588288592889484e+00 },
{+3.91549582965699016767757711932063103e+00 , +2.07401086477835132988304884524188567e+00 },
{+8.71307615958979297943187702912837267e+00 , +2.86124897639861530832907097356321837e+00 },
{+9.25125528837059185605085076531395316e+00 , +2.92081476128803069384228991876733421e+00 },
{+1.39894257949993688905365729624463711e-01 , +1.39441932379308919610017101598940231e-01 },
{+2.13018467023163493578863381117116660e+00 , +1.50038473636497909802939352641033551e+00 },
{+9.11338663647286573166184098226949573e+00 , +2.90588816775704749530976417485641794e+00 },
{+2.13672753800762960096903952944558114e+00 , +1.50316162138023144213989303271149548e+00 },
{+1.84662954052762628975870029535144567e+00 , +1.37286438673796624203424974151164008e+00 },
{+2.27538767726088808629469895095098764e+00 , +1.56042056675324794384613128836997008e+00 },
{+2.25459809157452584216230206948239356e+00 , +1.55202382694053013875493092338973536e+00 },
{+6.43951067826539436111943359719589353e+00 , +2.56157478187883218395455558699771338e+00 },
{+2.38928979360439708301555583602748811e+00 , +1.60531075239512338397498990117642106e+00 }
};
for(int i = 0; i < testCases.length; i++) {
double [] testCase = testCases[i];
failures += testAsinhCaseWithUlpDiff(testCase[0],
testCase[1],
3.0);
}
for(double nan : Tests.NaNs) {
failures += testAsinhCaseWithUlpDiff(nan, NaNd, 0);
}
double [][] specialTestCases = {
{0.0, 0.0},
{-0.0, -0.0},
{Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY},
{Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY}
};
for(int i = 0; i < specialTestCases.length; i++) {
failures += testAsinhCaseWithUlpDiff(specialTestCases[i][0],
specialTestCases[i][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 += testAsinhCaseWithUlpDiff(d, d, 2.5);
}
failures += testAsinhAdditionalTests();
return failures;
}
/**
* Test accuracy of {Math, StrictMath}.asinh using quad precision
* asinh implementation as the reference. There are additional tests.
* The specified accuracy is 2.5 ulps.
*
*/
static int testAsinhAdditionalTests() {
int failures = 0;
/*
* Array elements below are generated using a quad precision asinh
* 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 asinh(x)
{+9.29888520047217510822168407003118773e-03 , +9.29875119439016991620829879950089510e-03 },
{+8.99606577522583765460506555200481671e-03 , +8.99594443891109052619951669093253709e-03 },
{+1.14699795207729403345719987328266143e-03 , +1.14699770057820289010729363443748979e-03 },
{-7.40424146583510897623447988280531717e-03 , -7.40417381397284073003520743847398090e-03 },
{+5.49488608694304568602628791040842771e-03 , +5.49485843542812296005405619611903743e-03 },
{-2.52116366329231764847884633695684897e-03 , -2.52116099243538701654807174519941378e-03 },
{+8.06768422999586641564118139058336965e-03 , +8.06759671495411237747532966838824601e-03 },
{+9.88178277836134454081840061689945287e-03 , +9.88162196002118907735979091611455166e-03 },
{-9.74812907680771244256501262270830921e-03 , -9.74797469575697378811862965186905034e-03 },
{+1.28957646989550853144912423431378556e-03 , +1.28957611246655855199674391222106077e-03 },
{-3.58837408582282288427300898092653370e-03 , -3.58836638496033900344918006245058062e-03 },
{+4.13062959563161372078532451723731356e-03 , +4.13061784951867272487598247250853139e-03 },
{-2.51244549635140212301420703511212196e-03 , -2.51244285310613342444371438470610248e-03 },
{+9.68636675928437156091188597883956390e-03 , +9.68621529398750501339156647788267837e-03 },
{-5.46432162869262862125996349504930549e-03 , -5.46429443603366704988023092426655825e-03 },
{-1.83386276898741575058782160567716346e-03 , -1.83386174109279550088776833959567103e-03 },
{+4.29194713096967862819841599275605404e-03 , +4.29193395422167505495925421977757693e-03 },
{-9.98345193989031744197237827620483586e-03 , -9.98328610669592860197569944928865818e-03 },
{-2.77682511858849418590056146172173612e-03 , -2.77682155002991423153566829770018797e-03 },
{-9.27080565792574341765774903478813940e-03 , -9.27067286211199059124030266083673465e-03 },
{+2.13343832085455265001883162767626345e-03 , +2.13343670244611127381061946915639278e-03 },
{+1.86531796573603282640707590189776965e-03 , +1.86531688403638317794548160776476123e-03 },
{+7.59089952706850680519412577496041195e-03 , +7.59082662879913430594165031269929038e-03 },
{-7.23221864571126256404642873576449347e-03 , -7.23215560034534649276205014022842148e-03 },
{-4.85379569260787659124023463164121495e-03 , -4.85377663411205855718020189862812411e-03 },
{+2.06427745583616026325834980070794700e-03 , +2.06427598977487382238201754110142048e-03 },
{-9.05864273164906988466960058303811820e-03 , -9.05851884568408865775918913306811448e-03 },
{+8.14126659074132334736884075709895114e-03 , +8.14117665926450847350600785486541236e-03 },
{-1.18703607276676031956341716977476608e-03 , -1.18703579400048976745061906381442506e-03 },
{-3.72556727069004237073990282169688726e-03 , -3.72555865235713390047416035972567655e-03 },
{+3.20078632768614965153908258344017668e-03 , +3.20078086235102579132641956617880741e-03 },
{-3.64652695868728470018904630478573381e-03 , -3.64651887732759812624780495337361570e-03 },
{-4.37271109890237635181575726051050879e-03 , -4.37269716421058504020032749615645348e-03 },
{-4.53954699201700607319454050525564526e-03 , -4.53953140071906668014572342681250395e-03 },
{-7.71410922638161335174178390161614516e-03 , -7.71403272056205844933819193169521112e-03 },
{-4.14748385016995048391041933655287721e-03 , -4.14747195968688563991362285984749351e-03 },
{+2.16239643776180469336711809091866598e-03 , +2.16239475255273602474341490749538226e-03 },
{+1.70867505939914857138184345330955693e-04 , +1.70867505108481996929933792720554316e-04 },
{+4.45468038573873341412490134416657384e-03 , +4.45466565262570403928813346774794963e-03 },
{+5.02848450175214997659445259614585666e-04 , +5.02848428983795534702560585886961806e-04 },
{+3.27121347478520618778929929248988628e-03 , +3.27120764069260936386068328808026876e-03 },
{-3.02035237923277844612757192521712568e-03 , -3.02034778704318937598236175985252813e-03 },
{+1.83493544153568409471599665039320826e-03 , +1.83493441183628601773262459027151432e-03 },
{-3.57742891707456961425393160425301176e-03 , -3.57742128646403200576149317708586166e-03 },
{+4.07461518018882584701856330866576172e-04 , +4.07461506744091232910512108590665082e-04 },
{+8.93213245095503781401102827430804609e-03 , +8.93201368317984717551252673740071605e-03 },
{+4.83633433470810093768310622408534982e-03 , +4.83631548115857258701091393657125083e-03 },
{+4.41941080408745669283465673515820527e-03 , +4.41939641815384450220145838057678415e-03 },
{-7.40905574125878471636319488879962591e-03 , -7.40898795735011644277922058251845971e-03 },
{+5.86417821400006013254913028731607483e-03 , +5.86414460438723375893640532030031887e-03 },
{+6.40143962390532852979596611930901418e-04 , +6.40143918670384118303282950462728667e-04 },
{-6.62414482978957927516994175221043406e-03 , -6.62409638694556116425732364897473820e-03 },
{+2.32034013904017406837443360245742952e-03 , +2.32033805693503550464566970496041304e-03 },
{-1.70037238711657177903102677873903303e-03 , -1.70037156774608724006177273975196346e-03 },
{-2.41007559448008345376335270771051000e-03 , -2.41007326134647811152942503146226815e-03 },
{-4.88371906557288470301925187300184916e-03 , -4.88369965241849364892773140816442366e-03 },
{+5.45353417327115556900718473798406194e-03 , +5.45350714134116714399404074418610335e-03 },
{+1.82127472834406854695910027430727496e-03 , +1.82127372147155402291508536733347481e-03 },
{+3.08464771244317328968698177504847990e-03 , +3.08464282070047297125571891308421168e-03 },
{+8.64099586698139320029010690404902562e-03 , +8.64088833799551442516038310825829002e-03 },
{+5.55586600363066999974659410099775414e-03 , +5.55583742127587993316327594170344732e-03 },
{+8.72688321697448303460031837630594964e-03 , +8.72677244972821936872995155020997092e-03 },
{+8.67310115846320860144569309113649069e-03 , +8.67299242648623772707657889109267822e-03 },
{-6.14210531791088872044515056813906995e-03 , -6.14206669961072319996743834488437463e-03 },
{+8.88625749891074935560286718327915878e-03 , +8.88614055166480866111859091126682642e-03 },
{-1.43504119833010382323301712403917918e-03 , -1.43504070579016156191011766070535043e-03 },
{+8.88630021979499445938799340183322784e-04 , +8.88629905026452701546356648558325925e-04 },
{+3.93780142608554303840229238176107174e-03 , +3.93779124938125782164719425287579139e-03 },
{+5.97434710953371854447180311353804427e-03 , +5.97431156988517485964304752157241804e-03 },
{-7.98875566707221360096546902695990866e-03 , -7.98867069549231529699110336543851522e-03 },
{-7.35260998042218307663153709086145682e-03 , -7.35254373394740372183361138755444401e-03 },
{-1.21452151194481779150624589647122775e-03 , -1.21452121336249242914680975845323467e-03 },
{+4.98481949753720385287714123023761204e-04 , +4.98481929109570105039386663388380124e-04 },
{+4.91985816350236880578616904813316069e-03 , +4.91983831618717601288972307767102048e-03 },
{+7.68796449908712258014542584305672790e-03 , +7.68788876850302034489862036714171394e-03 },
{-1.49188964399755812084702455422302592e-03 , -1.49188909057301843050666760106824645e-03 },
{-6.73163270527497858974896871586679481e-03 , -6.73158186579155909561057079482268382e-03 },
{+8.73326787816911150053034162965559517e-03 , +8.73315686763575988088834491175495305e-03 },
{+7.81885100909627574206073319373899722e-03 , +7.81877134445315065535398733750043537e-03 },
{+5.17883696377165365920536288513176260e-03 , +5.17881381434573686588090532152532759e-03 },
{+5.94443020139156542980263253639350296e-03 , +5.94439519296920978949883610708856872e-03 },
{+6.20408692607689153664107806207539397e-03 , +6.20404712683039987243003869674263039e-03 },
{-4.13924636982772493898341537033047643e-03 , -4.13923455005213957426577773895357676e-03 },
{-3.71140287747976152510354097557865316e-03 , -3.71139435707241790669973810798603847e-03 },
{-8.37941685260259506995428324671593145e-03 , -8.37931879609631048090526043629803007e-03 },
{+8.48517293301665094518160259440264781e-03 , +8.48507111684271940482025173385456325e-03 },
{+8.52827781082153742187035305732933921e-03 , +8.52817443510010657036791986083451790e-03 },
{-4.07416024108964158756407414330169559e-03 , -4.07414897015777394146227881635448891e-03 },
{+4.33240979016216026797891913702187594e-03 , +4.33239623721743479728849041379241354e-03 },
{-4.89052581083683143847729013486969052e-04 , -4.89052561589036445343259711601066150e-04 },
{-9.62974650385375885441874288517283276e-05 , -9.62974648897066185792218187524452666e-05 },
{-9.26529020589744040092838872624270152e-04 , -9.26528888025725086174151901318195528e-04 },
{+1.39965317129459553002757132844635635e-03 , +1.39965271430147299997462291249440004e-03 },
{-7.12079193844885119379917171045235591e-03 , -7.12073176239158986696262840488189056e-03 },
{-3.62621830991397085114380516301935131e-03 , -3.62621036282602413990843595245483708e-03 },
{-7.11170226471406416446363607519742800e-03 , -7.11164231880305326913177834599584014e-03 },
{-1.07788116725225993630665755063091638e-04 , -1.07788116516507275261580974984359313e-04 },
{-2.51343271020868386927960003163207148e-03 , -2.51343006384636979438035563375611134e-03 },
{-9.70989675056706420808172453007500735e-03 , -9.70974417880563379443605277365308469e-03 },
{+7.17488567146307328059595675995296915e-03 , +7.17482411358449384368065167506580475e-03 }
};
for (int i = 0; i < testCases.length; i++) {
double[] testCase = testCases[i];
failures += testAsinhCaseWithUlpDiff(testCase[0],
testCase[1],
3.0);
}
return failures;
}
public static int testAsinhCaseWithTolerance(double input,
double expected,
double tolerance) {
int failures = 0;
failures += Tests.testTolerance("Math.asinh", input, Math::asinh, expected, tolerance);
failures += Tests.testTolerance("Math.asinh", -input, Math::asinh, -expected, tolerance);
failures += Tests.testTolerance("StrictMath.asinh", input, StrictMath::asinh, expected, tolerance);
failures += Tests.testTolerance("StrictMath.asinh", -input, StrictMath::asinh, -expected, tolerance);
return failures;
}
public static int testAsinhCaseWithUlpDiff(double input,
double expected,
double ulps) {
int failures = 0;
failures += Tests.testUlpDiffWithAbsBound("Math.asinh", input, Math::asinh, expected, ulps, Double.POSITIVE_INFINITY);
failures += Tests.testUlpDiffWithAbsBound("Math.asinh", -input, Math::asinh, -expected, ulps, Double.NEGATIVE_INFINITY);
failures += Tests.testUlpDiffWithAbsBound("StrictMath.asinh", input, StrictMath::asinh, expected, ulps, Double.POSITIVE_INFINITY);
failures += Tests.testUlpDiffWithAbsBound("StrictMath.asinh", -input, StrictMath::asinh, -expected, ulps, Double.NEGATIVE_INFINITY);
return failures;
}
}

View File

@ -91,6 +91,8 @@ public class ExhaustingTests {
new UnaryTestCase("asin", FdlibmTranslit::asin, StrictMath::asin, DEFAULT_SHIFT),
new UnaryTestCase("acos", FdlibmTranslit::acos, StrictMath::acos, DEFAULT_SHIFT),
new UnaryTestCase("atan", FdlibmTranslit::atan, StrictMath::atan, DEFAULT_SHIFT),
new UnaryTestCase("asinh", FdlibmTranslit::asinh, StrictMath::asinh, DEFAULT_SHIFT),
};
for (var testCase : testCases) {

View File

@ -140,6 +140,10 @@ public class FdlibmTranslit {
return Tanh.compute(x);
}
public static double asinh(double x) {
return Asinh.compute(x);
}
public static double IEEEremainder(double f1, double f2) {
return IEEEremainder.compute(f1, f2);
}
@ -2752,4 +2756,44 @@ public class FdlibmTranslit {
return x; /* exact output */
}
}
/**
* Return the Inverse Hyperbolic Sine of x
*
* Method :
*
* Based on
* asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
* we have
* asinh(x) := x if 1+x*x=1,
* := sign(x)*(log(x)+ln2)) for large |x|, else
* := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
* := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
*/
private static final class Asinh {
private static final double one = 1.0;
private static final double ln2 = 6.93147180559945286227e-01;
private static final double huge = 1.0e300;
static double compute(double x) {
double t,w;
int hx,ix;
hx = __HI(x);
ix = hx&0x7fffffff;
if(ix>=0x7ff00000) return x+x; /* x is inf or NaN */
if(ix< 0x3e300000) { /* |x|<2**-28 */
if(huge+x>one) return x; /* return x inexact except 0 */
}
if(ix>0x41b00000) { /* |x| > 2**28 */
w = log(Math.abs(x))+ln2;
} else if (ix>0x40000000) { /* 2**28 > |x| > 2.0 */
t = Math.abs(x);
w = log(2.0*t+one/(sqrt(x*x+one)+t));
} else { /* 2.0 > |x| > 2**-28 */
t = x*x;
w =log1p(Math.abs(x)+t/(one+sqrt(one+t)));
}
if(hx>0) return w; else return -w;
}
}
}

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}
* @summary Tests for StrictMath.{sinh, cosh, tanh, asinh}
*/
/**
@ -64,6 +64,7 @@ public class HyperbolicTests {
failures += testSinh();
failures += testCosh();
failures += testTanh();
failures += testAsinh();
if (failures > 0) {
System.err.println("Testing the hyperbolics incurred "
@ -78,7 +79,8 @@ public class HyperbolicTests {
private static enum HyperbolicTest {
SINH(HyperbolicTests::testSinhCase, FdlibmTranslit::sinh),
COSH(HyperbolicTests::testCoshCase, FdlibmTranslit::cosh),
TANH(HyperbolicTests::testTanhCase, FdlibmTranslit::tanh);
TANH(HyperbolicTests::testTanhCase, FdlibmTranslit::tanh),
ASINH(HyperbolicTests::testAsinhCase, FdlibmTranslit::asinh);
private DoubleDoubleToInt testCase;
private DoubleUnaryOperator transliteration;
@ -253,6 +255,11 @@ public class HyperbolicTests {
StrictMath::tanh, expected);
}
private static int testAsinhCase(double input, double expected) {
return Tests.test("StrictMath.asinh(double)", input,
StrictMath::asinh, expected);
}
private static int testSinh() {
int failures = 0;
double [][] testCases = {
@ -484,4 +491,76 @@ public class HyperbolicTests {
return failures;
}
private static int testAsinh() {
int failures = 0;
double [][] testCases = {
{0x1.5798ee2308c36p-27, 0x1.5798ee2308c35p-27},
{0x1.ffffffffffffep-26, 0x1.ffffffffffffdp-26},
{0x1.ffffffffffffep-25, 0x1.ffffffffffff9p-25},
{0x1.ad7f29abcaf47p-24, 0x1.ad7f29abcaf3bp-24},
{0x1.ad7f29abcaf48p-24, 0x1.ad7f29abcaf3cp-24},
{0x1.ffffffffffffep-24, 0x1.fffffffffffe9p-24},
{0x1.ffffffffffffep-23, 0x1.fffffffffffa9p-23},
{0x1.ffffffffffffep-22, 0x1.ffffffffffea9p-22},
{0x1.ffffffffffffep-21, 0x1.ffffffffffaa9p-21},
{0x1.0c6f7a0b5ed8dp-20, 0x1.0c6f7a0b5ea7ap-20},
{0x1.ffffffffffffep-20, 0x1.fffffffffeaa9p-20},
{0x1.ffffffffffffep-19, 0x1.fffffffffaaa9p-19},
{0x1.fffffffffffffp-18, 0x1.ffffffffeaaa9p-18},
{0x1p-17, 0x1.ffffffffeaaabp-18},
{0x1.4f8b588e368edp-17, 0x1.4f8b588e1e89ep-17},
{0x1.fffffffffffffp-17, 0x1.ffffffffaaaa9p-17},
{0x1.fffffffffffffp-16, 0x1.fffffffeaaaa9p-16},
{0x1p-15, 0x1.fffffffeaaaabp-16},
{0x1.fffffffffe5ddp-15, 0x1.fffffffaa9087p-15},
{0x1.fffffffffffffp-15, 0x1.fffffffaaaaa9p-15},
{0x1.a36e2eb1c432dp-14, 0x1.a36e2ea609cc8p-14},
{0x1.ffffffffffffep-14, 0x1.ffffffeaaaaa9p-14},
{0x1p-13, 0x1.ffffffeaaaaabp-14},
{0x1.ffffffffffd51p-13, 0x1.ffffffaaaa7fdp-13},
{0x1.fffffffffffffp-13, 0x1.ffffffaaaaaadp-13},
{0x1.ffffffffffffep-12, 0x1.fffffeaaaaacfp-12},
{0x1p-11, 0x1.fffffeaaaaad1p-12},
{0x1.fffffffffff1p-11, 0x1.fffffaaaaac21p-11},
{0x1p-10, 0x1.fffffaaaaad11p-11},
{0x1.0624dd2f1a9c6p-10, 0x1.0624da5218b5fp-10},
{0x1.0624dd2f1a9f8p-10, 0x1.0624da5218b91p-10},
{0x1.fffffffffffddp-10, 0x1.ffffeaaaad0edp-10},
{0x1.fffffffffffffp-10, 0x1.ffffeaaaad10fp-10},
{0x1.ffffffffffffcp-9, 0x1.ffffaaaad110cp-9},
{0x1.ffffffffffffep-9, 0x1.ffffaaaad110ep-9},
{0x1.ffffffffffff8p-8, 0x1.fffeaaad110aep-8},
{0x1.ffffffffffffep-8, 0x1.fffeaaad110b4p-8},
{0x1.47ae147ae1458p-7, 0x1.47acae9508ae4p-7},
{0x1.47ae147ae1464p-7, 0x1.47acae9508afp-7},
{0x1.ffffffffffffep-7, 0x1.fffaaad10fa35p-7},
{0x1.fffffffffffffp-7, 0x1.fffaaad10fa35p-7},
{0x1.ffffffffffff9p-6, 0x1.ffeaad10b5b28p-6},
{0x1.ffffffffffffep-6, 0x1.ffeaad10b5b2bp-6},
{0x1.ffffffffffff9p-5, 0x1.ffaad0fa4525bp-5},
{0x1.fffffffffffffp-5, 0x1.ffaad0fa45261p-5},
{0x1.9999999999996p-4, 0x1.98eb9e7e5fc3ap-4},
{0x1.9999999999997p-4, 0x1.98eb9e7e5fc3bp-4},
{0x1.fffffffffffffp-4, 0x1.fead0b6996972p-4},
{0x1p-3, 0x1.fead0b6996972p-4},
{0x1.fffffffffffffp-3, 0x1.facfb2399e636p-3},
{0x1.ffffffffffffcp-2, 0x1.ecc2caec51605p-2},
{0x1.ffffffffffffep-2, 0x1.ecc2caec51608p-2},
{0x1.ffffffffffffbp-1, 0x1.c34366179d423p-1},
{0x1.ffffffffffffep-1, 0x1.c34366179d426p-1},
{0x1.fffffffffffd3p+0, 0x1.719218313d073p+0},
{0x1.fffffffffffe1p+0, 0x1.719218313d079p+0},
{0x1.ffffffffffed8p+1, 0x1.0c1f8a6e80ea4p+1},
{0x1.fffffffffff92p+1, 0x1.0c1f8a6e80edp+1},
{0x1.0108b83c4bbc8p-1, 0x1.ee9c256f3947ep-2},
{-0x1.c41e527b70f43p-3, -0x1.c0863c7dece22p-3},
};
for (double[] testCase: testCases) {
failures += testAsinhCase(testCase[0], testCase[1]);
}
return failures;
}
}