From dbfce1c9b95d4e1ec405043208f19caf42fc79f0 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Thu, 15 Jan 2026 16:59:03 +0100 Subject: [PATCH] 8375285: Port of fdlibm asinh function --- .../share/classes/java/lang/FdLibm.java | 53 +++ .../share/classes/java/lang/Math.java | 25 ++ .../share/classes/java/lang/StrictMath.java | 25 ++ test/jdk/java/lang/Math/HyperbolicTests.java | 347 +++++++++++++++++- .../java/lang/StrictMath/ExhaustingTests.java | 2 + .../java/lang/StrictMath/FdlibmTranslit.java | 44 +++ .../java/lang/StrictMath/HyperbolicTests.java | 83 ++++- 7 files changed, 576 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/FdLibm.java b/src/java.base/share/classes/java/lang/FdLibm.java index 73e1da46af4..ac3321983b3 100644 --- a/src/java.base/share/classes/java/lang/FdLibm.java +++ b/src/java.base/share/classes/java/lang/FdLibm.java @@ -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; + } + } } diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 55659bed57b..0ca5ac853af 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -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 x is defined to be a function such that + * asinh({@linkplain Math#sinh sinh(x)}) = x for any x. + * Note that range of the exact asinh is not limited. + *

Special cases: + *

+ * @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(x2 +y2) * without intermediate overflow or underflow. diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index 499fce73aee..6ea57061816 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -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 x is defined to be a function such that + * asinh({@linkplain Math#sinh sinh(x)}) = x for any x. + * Note that range of the exact asinh is not limited. + *

Special cases: + *

+ * @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(x2 +y2) * without intermediate overflow or underflow. diff --git a/test/jdk/java/lang/Math/HyperbolicTests.java b/test/jdk/java/lang/Math/HyperbolicTests.java index 4534396ee06..770feb8c47e 100644 --- a/test/jdk/java/lang/Math/HyperbolicTests.java +++ b/test/jdk/java/lang/Math/HyperbolicTests.java @@ -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; + } } diff --git a/test/jdk/java/lang/StrictMath/ExhaustingTests.java b/test/jdk/java/lang/StrictMath/ExhaustingTests.java index 0351caff70c..29b829bc2e3 100644 --- a/test/jdk/java/lang/StrictMath/ExhaustingTests.java +++ b/test/jdk/java/lang/StrictMath/ExhaustingTests.java @@ -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) { diff --git a/test/jdk/java/lang/StrictMath/FdlibmTranslit.java b/test/jdk/java/lang/StrictMath/FdlibmTranslit.java index f38ca68569b..fc6c7da49a3 100644 --- a/test/jdk/java/lang/StrictMath/FdlibmTranslit.java +++ b/test/jdk/java/lang/StrictMath/FdlibmTranslit.java @@ -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; + } + } } diff --git a/test/jdk/java/lang/StrictMath/HyperbolicTests.java b/test/jdk/java/lang/StrictMath/HyperbolicTests.java index 1f570ce9efd..d3a955f8183 100644 --- a/test/jdk/java/lang/StrictMath/HyperbolicTests.java +++ b/test/jdk/java/lang/StrictMath/HyperbolicTests.java @@ -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; + } }