darcy | 32db449 | 2009-01-26 19:49:26 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 21 | * have any questions. |
| 22 | */ |
| 23 | |
| 24 | /* |
| 25 | * @test |
| 26 | * @bug 4851625 4900189 4939441 |
| 27 | * @summary Tests for {Math, StrictMath}.{sinh, cosh, tanh} |
| 28 | * @author Joseph D. Darcy |
| 29 | */ |
| 30 | |
| 31 | import sun.misc.DoubleConsts; |
| 32 | import sun.misc.FpUtils; |
| 33 | |
| 34 | public class HyperbolicTests { |
| 35 | private HyperbolicTests(){} |
| 36 | |
| 37 | static final double NaNd = Double.NaN; |
| 38 | |
| 39 | /** |
| 40 | * Test accuracy of {Math, StrictMath}.sinh. The specified |
| 41 | * accuracy is 2.5 ulps. |
| 42 | * |
| 43 | * The defintion of sinh(x) is |
| 44 | * |
| 45 | * (e^x - e^(-x))/2 |
| 46 | * |
| 47 | * The series expansion of sinh(x) = |
| 48 | * |
| 49 | * x + x^3/3! + x^5/5! + x^7/7! +... |
| 50 | * |
| 51 | * Therefore, |
| 52 | * |
| 53 | * 1. For large values of x sinh(x) ~= signum(x)*exp(|x|)/2 |
| 54 | * |
| 55 | * 2. For small values of x, sinh(x) ~= x. |
| 56 | * |
| 57 | * Additionally, sinh is an odd function; sinh(-x) = -sinh(x). |
| 58 | * |
| 59 | */ |
| 60 | static int testSinh() { |
| 61 | int failures = 0; |
| 62 | /* |
| 63 | * Array elements below generated using a quad sinh |
| 64 | * implementation. Rounded to a double, the quad result |
| 65 | * *should* be correctly rounded, unless we are quite unlucky. |
| 66 | * Assuming the quad value is a correctly rounded double, the |
| 67 | * allowed error is 3.0 ulps instead of 2.5 since the quad |
| 68 | * value rounded to double can have its own 1/2 ulp error. |
| 69 | */ |
| 70 | double [][] testCases = { |
| 71 | // x sinh(x) |
| 72 | {0.0625, 0.06254069805219182172183988501029229}, |
| 73 | {0.1250, 0.12532577524111545698205754229137154}, |
| 74 | {0.1875, 0.18860056562029018382047025055167585}, |
| 75 | {0.2500, 0.25261231680816830791412515054205787}, |
| 76 | {0.3125, 0.31761115611357728583959867611490292}, |
| 77 | {0.3750, 0.38385106791361456875429567642050245}, |
| 78 | {0.4375, 0.45159088610312053032509815226723017}, |
| 79 | {0.5000, 0.52109530549374736162242562641149155}, |
| 80 | {0.5625, 0.59263591611468777373870867338492247}, |
| 81 | {0.6250, 0.66649226445661608227260655608302908}, |
| 82 | {0.6875, 0.74295294580567543571442036910465007}, |
| 83 | {0.7500, 0.82231673193582998070366163444691386}, |
| 84 | {0.8125, 0.90489373856606433650504536421491368}, |
| 85 | {0.8750, 0.99100663714429475605317427568995231}, |
| 86 | {0.9375, 1.08099191569306394011007867453992548}, |
| 87 | {1.0000, 1.17520119364380145688238185059560082}, |
| 88 | {1.0625, 1.27400259579739321279181130344911907}, |
| 89 | {1.1250, 1.37778219077984075760379987065228373}, |
| 90 | {1.1875, 1.48694549961380717221109202361777593}, |
| 91 | {1.2500, 1.60191908030082563790283030151221415}, |
| 92 | {1.3125, 1.72315219460596010219069206464391528}, |
| 93 | {1.3750, 1.85111856355791532419998548438506416}, |
| 94 | {1.4375, 1.98631821852425112898943304217629457}, |
| 95 | {1.5000, 2.12927945509481749683438749467763195}, |
| 96 | {1.5625, 2.28056089740825247058075476705718764}, |
| 97 | {1.6250, 2.44075368098794353221372986997161132}, |
| 98 | {1.6875, 2.61048376261693140366028569794027603}, |
| 99 | {1.7500, 2.79041436627764265509289122308816092}, |
| 100 | {1.8125, 2.98124857471401377943765253243875520}, |
| 101 | {1.8750, 3.18373207674259205101326780071803724}, |
| 102 | {1.9375, 3.39865608104779099764440244167531810}, |
| 103 | {2.0000, 3.62686040784701876766821398280126192}, |
| 104 | {2.0625, 3.86923677050642806693938384073620450}, |
| 105 | {2.1250, 4.12673225993027252260441410537905269}, |
| 106 | {2.1875, 4.40035304533919660406976249684469164}, |
| 107 | {2.2500, 4.69116830589833069188357567763552003}, |
| 108 | {2.3125, 5.00031440855811351554075363240262157}, |
| 109 | {2.3750, 5.32899934843284576394645856548481489}, |
| 110 | {2.4375, 5.67850746906785056212578751630266858}, |
| 111 | {2.5000, 6.05020448103978732145032363835040319}, |
| 112 | {2.5625, 6.44554279850040875063706020260185553}, |
| 113 | {2.6250, 6.86606721451642172826145238779845813}, |
| 114 | {2.6875, 7.31342093738196587585692115636603571}, |
| 115 | {2.7500, 7.78935201149073201875513401029935330}, |
| 116 | {2.8125, 8.29572014785741787167717932988491961}, |
| 117 | {2.8750, 8.83450399097893197351853322827892144}, |
| 118 | {2.9375, 9.40780885043076394429977972921690859}, |
| 119 | {3.0000, 10.01787492740990189897459361946582867}, |
| 120 | {3.0625, 10.66708606836969224165124519209968368}, |
| 121 | {3.1250, 11.35797907995166028304704128775698426}, |
| 122 | {3.1875, 12.09325364161259019614431093344260209}, |
| 123 | {3.2500, 12.87578285468067003959660391705481220}, |
| 124 | {3.3125, 13.70862446906136798063935858393686525}, |
| 125 | {3.3750, 14.59503283146163690015482636921657975}, |
| 126 | {3.4375, 15.53847160182039311025096666980558478}, |
| 127 | {3.5000, 16.54262728763499762495673152901249743}, |
| 128 | {3.5625, 17.61142364906941482858466494889121694}, |
| 129 | {3.6250, 18.74903703113232171399165788088277979}, |
| 130 | {3.6875, 19.95991268283598684128844120984214675}, |
| 131 | {3.7500, 21.24878212710338697364101071825171163}, |
| 132 | {3.8125, 22.62068164929685091969259499078125023}, |
| 133 | {3.8750, 24.08097197661255803883403419733891573}, |
| 134 | {3.9375, 25.63535922523855307175060244757748997}, |
| 135 | {4.0000, 27.28991719712775244890827159079382096}, |
| 136 | {4.0625, 29.05111111351106713777825462100160185}, |
| 137 | {4.1250, 30.92582287788986031725487699744107092}, |
| 138 | {4.1875, 32.92137796722343190618721270937061472}, |
| 139 | {4.2500, 35.04557405638942942322929652461901154}, |
| 140 | {4.3125, 37.30671148776788628118833357170042385}, |
| 141 | {4.3750, 39.71362570500944929025069048612806024}, |
| 142 | {4.4375, 42.27572177772344954814418332587050658}, |
| 143 | {4.5000, 45.00301115199178562180965680564371424}, |
| 144 | {4.5625, 47.90615077031205065685078058248081891}, |
| 145 | {4.6250, 50.99648471383193131253995134526177467}, |
| 146 | {4.6875, 54.28608852959281437757368957713936555}, |
| 147 | {4.7500, 57.78781641599226874961859781628591635}, |
| 148 | {4.8125, 61.51535145084362283008545918273109379}, |
| 149 | {4.8750, 65.48325905829987165560146562921543361}, |
| 150 | {4.9375, 69.70704392356508084094318094283346381}, |
| 151 | {5.0000, 74.20321057778875897700947199606456364}, |
| 152 | {5.0625, 78.98932788987998983462810080907521151}, |
| 153 | {5.1250, 84.08409771724448958901392613147384951}, |
| 154 | {5.1875, 89.50742798369883598816307922895346849}, |
| 155 | {5.2500, 95.28051047011540739630959111303975956}, |
| 156 | {5.3125, 101.42590362176666730633859252034238987}, |
| 157 | {5.3750, 107.96762069594029162704530843962700133}, |
| 158 | {5.4375, 114.93122359426386042048760580590182604}, |
| 159 | {5.5000, 122.34392274639096192409774240457730721}, |
| 160 | {5.5625, 130.23468343534638291488502321709913206}, |
| 161 | {5.6250, 138.63433897999898233879574111119546728}, |
| 162 | {5.6875, 147.57571121692522056519568264304815790}, |
| 163 | {5.7500, 157.09373875244884423880085377625986165}, |
| 164 | {5.8125, 167.22561348600435888568183143777868662}, |
| 165 | {5.8750, 178.01092593829229887752609866133883987}, |
| 166 | {5.9375, 189.49181995209921964640216682906501778}, |
| 167 | {6.0000, 201.71315737027922812498206768797872263}, |
| 168 | {6.0625, 214.72269333437984291483666459592578915}, |
| 169 | {6.1250, 228.57126288889537420461281285729970085}, |
| 170 | {6.1875, 243.31297962030799867970551767086092471}, |
| 171 | {6.2500, 259.00544710710289911522315435345489966}, |
| 172 | {6.3125, 275.70998400700299790136562219920451185}, |
| 173 | {6.3750, 293.49186366095654566861661249898332253}, |
| 174 | {6.4375, 312.42056915013535342987623229485223434}, |
| 175 | {6.5000, 332.57006480258443156075705566965111346}, |
| 176 | {6.5625, 354.01908521044116928437570109827956007}, |
| 177 | {6.6250, 376.85144288706511933454985188849781703}, |
| 178 | {6.6875, 401.15635576625530823119100750634165252}, |
| 179 | {6.7500, 427.02879582326538080306830640235938517}, |
| 180 | {6.8125, 454.56986017986077163530945733572724452}, |
| 181 | {6.8750, 483.88716614351897894746751705315210621}, |
| 182 | {6.9375, 515.09527172439720070161654727225752288}, |
| 183 | {7.0000, 548.31612327324652237375611757601851598}, |
| 184 | {7.0625, 583.67953198942753384680988096024373270}, |
| 185 | {7.1250, 621.32368116099280160364794462812762880}, |
| 186 | {7.1875, 661.39566611888784148449430491465857519}, |
| 187 | {7.2500, 704.05206901515336623551137120663358760}, |
| 188 | {7.3125, 749.45957067108712382864538206200700256}, |
| 189 | {7.3750, 797.79560188617531521347351754559776282}, |
| 190 | {7.4375, 849.24903675279739482863565789325699416}, |
| 191 | {7.5000, 904.02093068584652953510919038935849651}, |
| 192 | {7.5625, 962.32530605113249628368993221570636328}, |
| 193 | {7.6250, 1024.38998846242707559349318193113614698}, |
| 194 | {7.6875, 1090.45749701500081956792547346904792325}, |
| 195 | {7.7500, 1160.78599193425808533255719118417856088}, |
| 196 | {7.8125, 1235.65028334242796895820912936318532502}, |
| 197 | {7.8750, 1315.34290508508890654067255740428824014}, |
| 198 | {7.9375, 1400.17525781352742299995139486063802583}, |
| 199 | {8.0000, 1490.47882578955018611587663903188144796}, |
| 200 | {8.0625, 1586.60647216744061169450001100145859236}, |
| 201 | {8.1250, 1688.93381781440241350635231605477507900}, |
| 202 | {8.1875, 1797.86070905726094477721128358866360644}, |
| 203 | {8.2500, 1913.81278009067446281883262689250118009}, |
| 204 | {8.3125, 2037.24311615199935553277163192983440062}, |
| 205 | {8.3750, 2168.63402396170125867037749369723761636}, |
| 206 | {8.4375, 2308.49891634734644432370720900969004306}, |
| 207 | {8.5000, 2457.38431841538268239359965370719928775}, |
| 208 | {8.5625, 2615.87200310986940554256648824234335262}, |
| 209 | {8.6250, 2784.58126450289932429469130598902487336}, |
| 210 | {8.6875, 2964.17133769964321637973459949999057146}, |
| 211 | {8.7500, 3155.34397481384944060352507473513108710}, |
| 212 | {8.8125, 3358.84618707947841898217318996045550438}, |
| 213 | {8.8750, 3575.47316381333288862617411467285480067}, |
| 214 | {8.9375, 3806.07137963459383403903729660349293583}, |
| 215 | {9.0000, 4051.54190208278996051522359589803425598}, |
| 216 | {9.0625, 4312.84391255878980330955246931164633615}, |
| 217 | {9.1250, 4590.99845434696991399363282718106006883}, |
| 218 | {9.1875, 4887.09242236403719571363798584676797558}, |
| 219 | {9.2500, 5202.28281022453561319352901552085348309}, |
| 220 | {9.3125, 5537.80123121853803935727335892054791265}, |
| 221 | {9.3750, 5894.95873086734181634245918412592155656}, |
| 222 | {9.4375, 6275.15090986233399457103055108344546942}, |
| 223 | {9.5000, 6679.86337740502119410058225086262108741}, |
| 224 | {9.5625, 7110.67755625726876329967852256934334025}, |
| 225 | {9.6250, 7569.27686218510919585241049433331592115}, |
| 226 | {9.6875, 8057.45328194243077504648484392156371121}, |
| 227 | {9.7500, 8577.11437549816065709098061006273039092}, |
| 228 | {9.8125, 9130.29072986829727910801024120918114778}, |
| 229 | {9.8750, 9719.14389367880274015504995181862860062}, |
| 230 | {9.9375, 10345.97482346383208590278839409938269134}, |
| 231 | {10.0000, 11013.23287470339337723652455484636420303}, |
| 232 | }; |
| 233 | |
| 234 | for(int i = 0; i < testCases.length; i++) { |
| 235 | double [] testCase = testCases[i]; |
| 236 | failures += testSinhCaseWithUlpDiff(testCase[0], |
| 237 | testCase[1], |
| 238 | 3.0); |
| 239 | } |
| 240 | |
| 241 | double [][] specialTestCases = { |
| 242 | {0.0, 0.0}, |
| 243 | {NaNd, NaNd}, |
| 244 | {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, |
| 245 | {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, |
| 246 | {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, |
| 247 | {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, |
| 248 | {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, |
| 249 | {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, |
| 250 | {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, |
| 251 | {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, |
| 252 | {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, |
| 253 | {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, |
| 254 | {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY} |
| 255 | }; |
| 256 | |
| 257 | for(int i = 0; i < specialTestCases.length; i++) { |
| 258 | failures += testSinhCaseWithUlpDiff(specialTestCases[i][0], |
| 259 | specialTestCases[i][1], |
| 260 | 0.0); |
| 261 | } |
| 262 | |
| 263 | // For powers of 2 less than 2^(-27), the second and |
| 264 | // subsequent terms of the Taylor series expansion will get |
| 265 | // rounded away since |n-n^3| > 53, the binary precision of a |
| 266 | // double significand. |
| 267 | |
| 268 | for(int i = DoubleConsts.MIN_SUB_EXPONENT; i < -27; i++) { |
| 269 | double d = FpUtils.scalb(2.0, i); |
| 270 | |
| 271 | // Result and expected are the same. |
| 272 | failures += testSinhCaseWithUlpDiff(d, d, 2.5); |
| 273 | } |
| 274 | |
| 275 | // For values of x larger than 22, the e^(-x) term is |
| 276 | // insignificant to the floating-point result. Util exp(x) |
| 277 | // overflows around 709.8, sinh(x) ~= exp(x)/2; will will test |
| 278 | // 10000 values in this range. |
| 279 | |
| 280 | long trans22 = Double.doubleToLongBits(22.0); |
| 281 | // (approximately) largest value such that exp shouldn't |
| 282 | // overflow |
| 283 | long transExpOvfl = Double.doubleToLongBits(FpUtils.nextDown(709.7827128933841)); |
| 284 | |
| 285 | for(long i = trans22; |
| 286 | i < transExpOvfl; |
| 287 | i +=(transExpOvfl-trans22)/10000) { |
| 288 | |
| 289 | double d = Double.longBitsToDouble(i); |
| 290 | |
| 291 | // Allow 3.5 ulps of error to deal with error in exp. |
| 292 | failures += testSinhCaseWithUlpDiff(d, StrictMath.exp(d)*0.5, 3.5); |
| 293 | } |
| 294 | |
| 295 | // (approximately) largest value such that sinh shouldn't |
| 296 | // overflow. |
| 297 | long transSinhOvfl = Double.doubleToLongBits(710.4758600739439); |
| 298 | |
| 299 | // Make sure sinh(x) doesn't overflow as soon as exp(x) |
| 300 | // overflows. |
| 301 | |
| 302 | /* |
| 303 | * For large values of x, sinh(x) ~= 0.5*(e^x). Therefore, |
| 304 | * |
| 305 | * sinh(x) ~= e^(ln 0.5) * e^x = e^(x + ln 0.5) |
| 306 | * |
| 307 | * So, we can calculate the approximate expected result as |
| 308 | * exp(x + -0.693147186). However, this sum suffers from |
| 309 | * roundoff, limiting the accuracy of the approximation. The |
| 310 | * accuracy can be improved by recovering the rounded-off |
| 311 | * information. Since x is larger than ln(0.5), the trailing |
| 312 | * bits of ln(0.5) get rounded away when the two values are |
| 313 | * added. However, high-order bits of ln(0.5) that |
| 314 | * contribute to the sum can be found: |
| 315 | * |
| 316 | * offset = log(0.5); |
| 317 | * effective_offset = (x + offset) - x; // exact subtraction |
| 318 | * rounded_away_offset = offset - effective_offset; // exact subtraction |
| 319 | * |
| 320 | * Therefore, the product |
| 321 | * |
| 322 | * exp(x + offset)*exp(rounded_away_offset) |
| 323 | * |
| 324 | * will be a better approximation to the exact value of |
| 325 | * |
| 326 | * e^(x + offset) |
| 327 | * |
| 328 | * than exp(x+offset) alone. (The expected result cannot be |
| 329 | * computed as exp(x)*exp(offset) since exp(x) by itself would |
| 330 | * overflow to infinity.) |
| 331 | */ |
| 332 | double offset = StrictMath.log(0.5); |
| 333 | for(long i = transExpOvfl+1; i < transSinhOvfl; |
| 334 | i += (transSinhOvfl-transExpOvfl)/1000 ) { |
| 335 | double input = Double.longBitsToDouble(i); |
| 336 | |
| 337 | double expected = |
| 338 | StrictMath.exp(input + offset) * |
| 339 | StrictMath.exp( offset - ((input + offset) - input) ); |
| 340 | |
| 341 | failures += testSinhCaseWithUlpDiff(input, expected, 4.0); |
| 342 | } |
| 343 | |
| 344 | // sinh(x) overflows for values greater than 710; in |
| 345 | // particular, it overflows for all 2^i, i > 10. |
| 346 | for(int i = 10; i <= DoubleConsts.MAX_EXPONENT; i++) { |
| 347 | double d = FpUtils.scalb(2.0, i); |
| 348 | |
| 349 | // Result and expected are the same. |
| 350 | failures += testSinhCaseWithUlpDiff(d, |
| 351 | Double.POSITIVE_INFINITY, 0.0); |
| 352 | } |
| 353 | |
| 354 | return failures; |
| 355 | } |
| 356 | |
| 357 | public static int testSinhCaseWithTolerance(double input, |
| 358 | double expected, |
| 359 | double tolerance) { |
| 360 | int failures = 0; |
| 361 | failures += Tests.testTolerance("Math.sinh(double)", |
| 362 | input, Math.sinh(input), |
| 363 | expected, tolerance); |
| 364 | failures += Tests.testTolerance("Math.sinh(double)", |
| 365 | -input, Math.sinh(-input), |
| 366 | -expected, tolerance); |
| 367 | |
| 368 | failures += Tests.testTolerance("StrictMath.sinh(double)", |
| 369 | input, StrictMath.sinh(input), |
| 370 | expected, tolerance); |
| 371 | failures += Tests.testTolerance("StrictMath.sinh(double)", |
| 372 | -input, StrictMath.sinh(-input), |
| 373 | -expected, tolerance); |
| 374 | return failures; |
| 375 | } |
| 376 | |
| 377 | public static int testSinhCaseWithUlpDiff(double input, |
| 378 | double expected, |
| 379 | double ulps) { |
| 380 | int failures = 0; |
| 381 | failures += Tests.testUlpDiff("Math.sinh(double)", |
| 382 | input, Math.sinh(input), |
| 383 | expected, ulps); |
| 384 | failures += Tests.testUlpDiff("Math.sinh(double)", |
| 385 | -input, Math.sinh(-input), |
| 386 | -expected, ulps); |
| 387 | |
| 388 | failures += Tests.testUlpDiff("StrictMath.sinh(double)", |
| 389 | input, StrictMath.sinh(input), |
| 390 | expected, ulps); |
| 391 | failures += Tests.testUlpDiff("StrictMath.sinh(double)", |
| 392 | -input, StrictMath.sinh(-input), |
| 393 | -expected, ulps); |
| 394 | return failures; |
| 395 | } |
| 396 | |
| 397 | |
| 398 | /** |
| 399 | * Test accuracy of {Math, StrictMath}.cosh. The specified |
| 400 | * accuracy is 2.5 ulps. |
| 401 | * |
| 402 | * The defintion of cosh(x) is |
| 403 | * |
| 404 | * (e^x + e^(-x))/2 |
| 405 | * |
| 406 | * The series expansion of cosh(x) = |
| 407 | * |
| 408 | * 1 + x^2/2! + x^4/4! + x^6/6! +... |
| 409 | * |
| 410 | * Therefore, |
| 411 | * |
| 412 | * 1. For large values of x cosh(x) ~= exp(|x|)/2 |
| 413 | * |
| 414 | * 2. For small values of x, cosh(x) ~= 1. |
| 415 | * |
| 416 | * Additionally, cosh is an even function; cosh(-x) = cosh(x). |
| 417 | * |
| 418 | */ |
| 419 | static int testCosh() { |
| 420 | int failures = 0; |
| 421 | /* |
| 422 | * Array elements below generated using a quad cosh |
| 423 | * implementation. Rounded to a double, the quad result |
| 424 | * *should* be correctly rounded, unless we are quite unlucky. |
| 425 | * Assuming the quad value is a correctly rounded double, the |
| 426 | * allowed error is 3.0 ulps instead of 2.5 since the quad |
| 427 | * value rounded to double can have its own 1/2 ulp error. |
| 428 | */ |
| 429 | double [][] testCases = { |
| 430 | // x cosh(x) |
| 431 | {0.0625, 1.001953760865667607841550709632597376}, |
| 432 | {0.1250, 1.007822677825710859846949685520422223}, |
| 433 | {0.1875, 1.017629683800690526835115759894757615}, |
| 434 | {0.2500, 1.031413099879573176159295417520378622}, |
| 435 | {0.3125, 1.049226785060219076999158096606305793}, |
| 436 | {0.3750, 1.071140346704586767299498015567016002}, |
| 437 | {0.4375, 1.097239412531012567673453832328262160}, |
| 438 | {0.5000, 1.127625965206380785226225161402672030}, |
| 439 | {0.5625, 1.162418740845610783505338363214045218}, |
| 440 | {0.6250, 1.201753692975606324229229064105075301}, |
| 441 | {0.6875, 1.245784523776616395403056980542275175}, |
| 442 | {0.7500, 1.294683284676844687841708185390181730}, |
| 443 | {0.8125, 1.348641048647144208352285714214372703}, |
| 444 | {0.8750, 1.407868656822803158638471458026344506}, |
| 445 | {0.9375, 1.472597542369862933336886403008640891}, |
| 446 | {1.0000, 1.543080634815243778477905620757061497}, |
| 447 | {1.0625, 1.619593348374367728682469968448090763}, |
| 448 | {1.1250, 1.702434658138190487400868008124755757}, |
| 449 | {1.1875, 1.791928268324866464246665745956119612}, |
| 450 | {1.2500, 1.888423877161015738227715728160051696}, |
| 451 | {1.3125, 1.992298543335143985091891077551921106}, |
| 452 | {1.3750, 2.103958159362661802010972984204389619}, |
| 453 | {1.4375, 2.223839037619709260803023946704272699}, |
| 454 | {1.5000, 2.352409615243247325767667965441644201}, |
| 455 | {1.5625, 2.490172284559350293104864895029231913}, |
| 456 | {1.6250, 2.637665356192137582275019088061812951}, |
| 457 | {1.6875, 2.795465162524235691253423614360562624}, |
| 458 | {1.7500, 2.964188309728087781773608481754531801}, |
| 459 | {1.8125, 3.144494087167972176411236052303565201}, |
| 460 | {1.8750, 3.337087043587520514308832278928116525}, |
| 461 | {1.9375, 3.542719740149244276729383650503145346}, |
| 462 | {2.0000, 3.762195691083631459562213477773746099}, |
| 463 | {2.0625, 3.996372503438463642260225717607554880}, |
| 464 | {2.1250, 4.246165228196992140600291052990934410}, |
| 465 | {2.1875, 4.512549935859540340856119781585096760}, |
| 466 | {2.2500, 4.796567530460195028666793366876218854}, |
| 467 | {2.3125, 5.099327816921939817643745917141739051}, |
| 468 | {2.3750, 5.422013837643509250646323138888569746}, |
| 469 | {2.4375, 5.765886495263270945949271410819116399}, |
| 470 | {2.5000, 6.132289479663686116619852312817562517}, |
| 471 | {2.5625, 6.522654518468725462969589397439224177}, |
| 472 | {2.6250, 6.938506971550673190999796241172117288}, |
| 473 | {2.6875, 7.381471791406976069645686221095397137}, |
| 474 | {2.7500, 7.853279872697439591457564035857305647}, |
| 475 | {2.8125, 8.355774815752725814638234943192709129}, |
| 476 | {2.8750, 8.890920130482709321824793617157134961}, |
| 477 | {2.9375, 9.460806908834119747071078865866737196}, |
| 478 | {3.0000, 10.067661995777765841953936035115890343}, |
| 479 | {3.0625, 10.713856690753651225304006562698007312}, |
| 480 | {3.1250, 11.401916013575067700373788969458446177}, |
| 481 | {3.1875, 12.134528570998387744547733730974713055}, |
| 482 | {3.2500, 12.914557062512392049483503752322408761}, |
| 483 | {3.3125, 13.745049466398732213877084541992751273}, |
| 484 | {3.3750, 14.629250949773302934853381428660210721}, |
| 485 | {3.4375, 15.570616549147269180921654324879141947}, |
| 486 | {3.5000, 16.572824671057316125696517821376119469}, |
| 487 | {3.5625, 17.639791465519127930722105721028711044}, |
| 488 | {3.6250, 18.775686128468677200079039891415789429}, |
| 489 | {3.6875, 19.984947192985946987799359614758598457}, |
| 490 | {3.7500, 21.272299872959396081877161903352144126}, |
| 491 | {3.8125, 22.642774526961913363958587775566619798}, |
| 492 | {3.8750, 24.101726314486257781049388094955970560}, |
| 493 | {3.9375, 25.654856121347151067170940701379544221}, |
| 494 | {4.0000, 27.308232836016486629201989612067059978}, |
| 495 | {4.0625, 29.068317063936918520135334110824828950}, |
| 496 | {4.1250, 30.941986372478026192360480044849306606}, |
| 497 | {4.1875, 32.936562165180269851350626768308756303}, |
| 498 | {4.2500, 35.059838290298428678502583470475012235}, |
| 499 | {4.3125, 37.320111495433027109832850313172338419}, |
| 500 | {4.3750, 39.726213847251883288518263854094284091}, |
| 501 | {4.4375, 42.287547242982546165696077854963452084}, |
| 502 | {4.5000, 45.014120148530027928305799939930642658}, |
| 503 | {4.5625, 47.916586706774825161786212701923307169}, |
| 504 | {4.6250, 51.006288368867753140854830589583165950}, |
| 505 | {4.6875, 54.295298211196782516984520211780624960}, |
| 506 | {4.7500, 57.796468111195389383795669320243166117}, |
| 507 | {4.8125, 61.523478966332915041549750463563672435}, |
| 508 | {4.8750, 65.490894152518731617237739112888213645}, |
| 509 | {4.9375, 69.714216430810089539924900313140922323}, |
| 510 | {5.0000, 74.209948524787844444106108044487704798}, |
| 511 | {5.0625, 78.995657605307475581204965926043112946}, |
| 512 | {5.1250, 84.090043934600961683400343038519519678}, |
| 513 | {5.1875, 89.513013937957834087706670952561002466}, |
| 514 | {5.2500, 95.285757988514588780586084642381131013}, |
| 515 | {5.3125, 101.430833209098212357990123684449846912}, |
| 516 | {5.3750, 107.972251614673824873137995865940755392}, |
| 517 | {5.4375, 114.935573939814969189535554289886848550}, |
| 518 | {5.5000, 122.348009517829425991091207107262038316}, |
| 519 | {5.5625, 130.238522601820409078244923165746295574}, |
| 520 | {5.6250, 138.637945543134998069351279801575968875}, |
| 521 | {5.6875, 147.579099269447055276899288971207106581}, |
| 522 | {5.7500, 157.096921533245353905868840194264636395}, |
| 523 | {5.8125, 167.228603431860671946045256541679445836}, |
| 524 | {5.8750, 178.013734732486824390148614309727161925}, |
| 525 | {5.9375, 189.494458570056311567917444025807275896}, |
| 526 | {6.0000, 201.715636122455894483405112855409538488}, |
| 527 | {6.0625, 214.725021906554080628430756558271312513}, |
| 528 | {6.1250, 228.573450380013557089736092321068279231}, |
| 529 | {6.1875, 243.315034578039208138752165587134488645}, |
| 530 | {6.2500, 259.007377561239126824465367865430519592}, |
| 531 | {6.3125, 275.711797500835732516530131577254654076}, |
| 532 | {6.3750, 293.493567280752348242602902925987643443}, |
| 533 | {6.4375, 312.422169552825597994104814531010579387}, |
| 534 | {6.5000, 332.571568241777409133204438572983297292}, |
| 535 | {6.5625, 354.020497560858198165985214519757890505}, |
| 536 | {6.6250, 376.852769667496146326030849450983914197}, |
| 537 | {6.6875, 401.157602161123700280816957271992998156}, |
| 538 | {6.7500, 427.029966702886171977469256622451185850}, |
| 539 | {6.8125, 454.570960119471524953536004647195906721}, |
| 540 | {6.8750, 483.888199441157626584508920036981010995}, |
| 541 | {6.9375, 515.096242417696720610477570797503766179}, |
| 542 | {7.0000, 548.317035155212076889964120712102928484}, |
| 543 | {7.0625, 583.680388623257719787307547662358502345}, |
| 544 | {7.1250, 621.324485894002926216918634755431456031}, |
| 545 | {7.1875, 661.396422095589629755266517362992812037}, |
| 546 | {7.2500, 704.052779189542208784574955807004218856}, |
| 547 | {7.3125, 749.460237818184878095966335081928645934}, |
| 548 | {7.3750, 797.796228612873763671070863694973560629}, |
| 549 | {7.4375, 849.249625508044731271830060572510241864}, |
| 550 | {7.5000, 904.021483770216677368692292389446994987}, |
| 551 | {7.5625, 962.325825625814651122171697031114091993}, |
| 552 | {7.6250, 1024.390476557670599008492465853663578558}, |
| 553 | {7.6875, 1090.457955538048482588540574008226583335}, |
| 554 | {7.7500, 1160.786422676798661020094043586456606003}, |
| 555 | {7.8125, 1235.650687987597295222707689125107720568}, |
| 556 | {7.8750, 1315.343285214046776004329388551335841550}, |
| 557 | {7.9375, 1400.175614911635999247504386054087931958}, |
| 558 | {8.0000, 1490.479161252178088627715460421007179728}, |
| 559 | {8.0625, 1586.606787305415349050508956232945539108}, |
| 560 | {8.1250, 1688.934113859132470361718199038326340668}, |
| 561 | {8.1875, 1797.860987165547537276364148450577336075}, |
| 562 | {8.2500, 1913.813041349231764486365114317586148767}, |
| 563 | {8.3125, 2037.243361581700856522236313401822532385}, |
| 564 | {8.3750, 2168.634254521568851112005905503069409349}, |
| 565 | {8.4375, 2308.499132938297821208734949028296170563}, |
| 566 | {8.5000, 2457.384521883751693037774022640629666294}, |
| 567 | {8.5625, 2615.872194250713123494312356053193077854}, |
| 568 | {8.6250, 2784.581444063104750127653362960649823247}, |
| 569 | {8.6875, 2964.171506380845754878370650565756538203}, |
| 570 | {8.7500, 3155.344133275174556354775488913749659006}, |
| 571 | {8.8125, 3358.846335940117183452010789979584950102}, |
| 572 | {8.8750, 3575.473303654961482727206202358956274888}, |
| 573 | {8.9375, 3806.071511003646460448021740303914939059}, |
| 574 | {9.0000, 4051.542025492594047194773093534725371440}, |
| 575 | {9.0625, 4312.844028491571841588188869958240355518}, |
| 576 | {9.1250, 4590.998563255739769060078863130940205710}, |
| 577 | {9.1875, 4887.092524674358252509551443117048351290}, |
| 578 | {9.2500, 5202.282906336187674588222835339193136030}, |
| 579 | {9.3125, 5537.801321507079474415176386655744387251}, |
| 580 | {9.3750, 5894.958815685577062811620236195525504885}, |
| 581 | {9.4375, 6275.150989541692149890530417987358096221}, |
| 582 | {9.5000, 6679.863452256851081801173722051940058824}, |
| 583 | {9.5625, 7110.677626574055535297758456126491707647}, |
| 584 | {9.6250, 7569.276928241617224537226019600213961572}, |
| 585 | {9.6875, 8057.453343996777301036241026375049070162}, |
| 586 | {9.7500, 8577.114433792824387959788368429252257664}, |
| 587 | {9.8125, 9130.290784631065880205118262838330689429}, |
| 588 | {9.8750, 9719.143945123662919857326995631317996715}, |
| 589 | {9.9375, 10345.974871791805753327922796701684092861}, |
| 590 | {10.0000, 11013.232920103323139721376090437880844591}, |
| 591 | }; |
| 592 | |
| 593 | for(int i = 0; i < testCases.length; i++) { |
| 594 | double [] testCase = testCases[i]; |
| 595 | failures += testCoshCaseWithUlpDiff(testCase[0], |
| 596 | testCase[1], |
| 597 | 3.0); |
| 598 | } |
| 599 | |
| 600 | |
| 601 | double [][] specialTestCases = { |
| 602 | {0.0, 1.0}, |
| 603 | {NaNd, NaNd}, |
| 604 | {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, |
| 605 | {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, |
| 606 | {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, |
| 607 | {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, |
| 608 | {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, |
| 609 | {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, |
| 610 | {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, |
| 611 | {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, |
| 612 | {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, |
| 613 | {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, |
| 614 | {Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY} |
| 615 | }; |
| 616 | |
| 617 | for(int i = 0; i < specialTestCases.length; i++ ) { |
| 618 | failures += testCoshCaseWithUlpDiff(specialTestCases[i][0], |
| 619 | specialTestCases[i][1], |
| 620 | 0.0); |
| 621 | } |
| 622 | |
| 623 | // For powers of 2 less than 2^(-27), the second and |
| 624 | // subsequent terms of the Taylor series expansion will get |
| 625 | // rounded. |
| 626 | |
| 627 | for(int i = DoubleConsts.MIN_SUB_EXPONENT; i < -27; i++) { |
| 628 | double d = FpUtils.scalb(2.0, i); |
| 629 | |
| 630 | // Result and expected are the same. |
| 631 | failures += testCoshCaseWithUlpDiff(d, 1.0, 2.5); |
| 632 | } |
| 633 | |
| 634 | // For values of x larger than 22, the e^(-x) term is |
| 635 | // insignificant to the floating-point result. Util exp(x) |
| 636 | // overflows around 709.8, cosh(x) ~= exp(x)/2; will will test |
| 637 | // 10000 values in this range. |
| 638 | |
| 639 | long trans22 = Double.doubleToLongBits(22.0); |
| 640 | // (approximately) largest value such that exp shouldn't |
| 641 | // overflow |
| 642 | long transExpOvfl = Double.doubleToLongBits(FpUtils.nextDown(709.7827128933841)); |
| 643 | |
| 644 | for(long i = trans22; |
| 645 | i < transExpOvfl; |
| 646 | i +=(transExpOvfl-trans22)/10000) { |
| 647 | |
| 648 | double d = Double.longBitsToDouble(i); |
| 649 | |
| 650 | // Allow 3.5 ulps of error to deal with error in exp. |
| 651 | failures += testCoshCaseWithUlpDiff(d, StrictMath.exp(d)*0.5, 3.5); |
| 652 | } |
| 653 | |
| 654 | // (approximately) largest value such that cosh shouldn't |
| 655 | // overflow. |
| 656 | long transCoshOvfl = Double.doubleToLongBits(710.4758600739439); |
| 657 | |
| 658 | // Make sure sinh(x) doesn't overflow as soon as exp(x) |
| 659 | // overflows. |
| 660 | |
| 661 | /* |
| 662 | * For large values of x, cosh(x) ~= 0.5*(e^x). Therefore, |
| 663 | * |
| 664 | * cosh(x) ~= e^(ln 0.5) * e^x = e^(x + ln 0.5) |
| 665 | * |
| 666 | * So, we can calculate the approximate expected result as |
| 667 | * exp(x + -0.693147186). However, this sum suffers from |
| 668 | * roundoff, limiting the accuracy of the approximation. The |
| 669 | * accuracy can be improved by recovering the rounded-off |
| 670 | * information. Since x is larger than ln(0.5), the trailing |
| 671 | * bits of ln(0.5) get rounded away when the two values are |
| 672 | * added. However, high-order bits of ln(0.5) that |
| 673 | * contribute to the sum can be found: |
| 674 | * |
| 675 | * offset = log(0.5); |
| 676 | * effective_offset = (x + offset) - x; // exact subtraction |
| 677 | * rounded_away_offset = offset - effective_offset; // exact subtraction |
| 678 | * |
| 679 | * Therefore, the product |
| 680 | * |
| 681 | * exp(x + offset)*exp(rounded_away_offset) |
| 682 | * |
| 683 | * will be a better approximation to the exact value of |
| 684 | * |
| 685 | * e^(x + offset) |
| 686 | * |
| 687 | * than exp(x+offset) alone. (The expected result cannot be |
| 688 | * computed as exp(x)*exp(offset) since exp(x) by itself would |
| 689 | * overflow to infinity.) |
| 690 | */ |
| 691 | double offset = StrictMath.log(0.5); |
| 692 | for(long i = transExpOvfl+1; i < transCoshOvfl; |
| 693 | i += (transCoshOvfl-transExpOvfl)/1000 ) { |
| 694 | double input = Double.longBitsToDouble(i); |
| 695 | |
| 696 | double expected = |
| 697 | StrictMath.exp(input + offset) * |
| 698 | StrictMath.exp( offset - ((input + offset) - input) ); |
| 699 | |
| 700 | failures += testCoshCaseWithUlpDiff(input, expected, 4.0); |
| 701 | } |
| 702 | |
| 703 | // cosh(x) overflows for values greater than 710; in |
| 704 | // particular, it overflows for all 2^i, i > 10. |
| 705 | for(int i = 10; i <= DoubleConsts.MAX_EXPONENT; i++) { |
| 706 | double d = FpUtils.scalb(2.0, i); |
| 707 | |
| 708 | // Result and expected are the same. |
| 709 | failures += testCoshCaseWithUlpDiff(d, |
| 710 | Double.POSITIVE_INFINITY, 0.0); |
| 711 | } |
| 712 | return failures; |
| 713 | } |
| 714 | |
| 715 | public static int testCoshCaseWithTolerance(double input, |
| 716 | double expected, |
| 717 | double tolerance) { |
| 718 | int failures = 0; |
| 719 | failures += Tests.testTolerance("Math.cosh(double)", |
| 720 | input, Math.cosh(input), |
| 721 | expected, tolerance); |
| 722 | failures += Tests.testTolerance("Math.cosh(double)", |
| 723 | -input, Math.cosh(-input), |
| 724 | expected, tolerance); |
| 725 | |
| 726 | failures += Tests.testTolerance("StrictMath.cosh(double)", |
| 727 | input, StrictMath.cosh(input), |
| 728 | expected, tolerance); |
| 729 | failures += Tests.testTolerance("StrictMath.cosh(double)", |
| 730 | -input, StrictMath.cosh(-input), |
| 731 | expected, tolerance); |
| 732 | return failures; |
| 733 | } |
| 734 | |
| 735 | public static int testCoshCaseWithUlpDiff(double input, |
| 736 | double expected, |
| 737 | double ulps) { |
| 738 | int failures = 0; |
| 739 | failures += Tests.testUlpDiff("Math.cosh(double)", |
| 740 | input, Math.cosh(input), |
| 741 | expected, ulps); |
| 742 | failures += Tests.testUlpDiff("Math.cosh(double)", |
| 743 | -input, Math.cosh(-input), |
| 744 | expected, ulps); |
| 745 | |
| 746 | failures += Tests.testUlpDiff("StrictMath.cosh(double)", |
| 747 | input, StrictMath.cosh(input), |
| 748 | expected, ulps); |
| 749 | failures += Tests.testUlpDiff("StrictMath.cosh(double)", |
| 750 | -input, StrictMath.cosh(-input), |
| 751 | expected, ulps); |
| 752 | return failures; |
| 753 | } |
| 754 | |
| 755 | |
| 756 | /** |
| 757 | * Test accuracy of {Math, StrictMath}.tanh. The specified |
| 758 | * accuracy is 2.5 ulps. |
| 759 | * |
| 760 | * The defintion of tanh(x) is |
| 761 | * |
| 762 | * (e^x - e^(-x))/(e^x + e^(-x)) |
| 763 | * |
| 764 | * The series expansion of tanh(x) = |
| 765 | * |
| 766 | * x - x^3/3 + 2x^5/15 - 17x^7/315 + ... |
| 767 | * |
| 768 | * Therefore, |
| 769 | * |
| 770 | * 1. For large values of x tanh(x) ~= signum(x) |
| 771 | * |
| 772 | * 2. For small values of x, tanh(x) ~= x. |
| 773 | * |
| 774 | * Additionally, tanh is an odd function; tanh(-x) = -tanh(x). |
| 775 | * |
| 776 | */ |
| 777 | static int testTanh() { |
| 778 | int failures = 0; |
| 779 | /* |
| 780 | * Array elements below generated using a quad sinh |
| 781 | * implementation. Rounded to a double, the quad result |
| 782 | * *should* be correctly rounded, unless we are quite unlucky. |
| 783 | * Assuming the quad value is a correctly rounded double, the |
| 784 | * allowed error is 3.0 ulps instead of 2.5 since the quad |
| 785 | * value rounded to double can have its own 1/2 ulp error. |
| 786 | */ |
| 787 | double [][] testCases = { |
| 788 | // x tanh(x) |
| 789 | {0.0625, 0.06241874674751251449014289119421133}, |
| 790 | {0.1250, 0.12435300177159620805464727580589271}, |
| 791 | {0.1875, 0.18533319990813951753211997502482787}, |
| 792 | {0.2500, 0.24491866240370912927780113149101697}, |
| 793 | {0.3125, 0.30270972933210848724239738970991712}, |
| 794 | {0.3750, 0.35835739835078594631936023155315807}, |
| 795 | {0.4375, 0.41157005567402245143207555859415687}, |
| 796 | {0.5000, 0.46211715726000975850231848364367256}, |
| 797 | {0.5625, 0.50982997373525658248931213507053130}, |
| 798 | {0.6250, 0.55459972234938229399903909532308371}, |
| 799 | {0.6875, 0.59637355547924233984437303950726939}, |
| 800 | {0.7500, 0.63514895238728731921443435731249638}, |
| 801 | {0.8125, 0.67096707420687367394810954721913358}, |
| 802 | {0.8750, 0.70390560393662106058763026963135371}, |
| 803 | {0.9375, 0.73407151960434149263991588052503660}, |
| 804 | {1.0000, 0.76159415595576488811945828260479366}, |
| 805 | {1.0625, 0.78661881210869761781941794647736081}, |
| 806 | {1.1250, 0.80930107020178101206077047354332696}, |
| 807 | {1.1875, 0.82980190998595952708572559629034476}, |
| 808 | {1.2500, 0.84828363995751289761338764670750445}, |
| 809 | {1.3125, 0.86490661772074179125443141102709751}, |
| 810 | {1.3750, 0.87982669965198475596055310881018259}, |
| 811 | {1.4375, 0.89319334040035153149249598745889365}, |
| 812 | {1.5000, 0.90514825364486643824230369645649557}, |
| 813 | {1.5625, 0.91582454416876231820084311814416443}, |
| 814 | {1.6250, 0.92534622531174107960457166792300374}, |
| 815 | {1.6875, 0.93382804322259173763570528576138652}, |
| 816 | {1.7500, 0.94137553849728736226942088377163687}, |
| 817 | {1.8125, 0.94808528560440629971240651310180052}, |
| 818 | {1.8750, 0.95404526017994877009219222661968285}, |
| 819 | {1.9375, 0.95933529331468249183399461756952555}, |
| 820 | {2.0000, 0.96402758007581688394641372410092317}, |
| 821 | {2.0625, 0.96818721657637057702714316097855370}, |
| 822 | {2.1250, 0.97187274591350905151254495374870401}, |
| 823 | {2.1875, 0.97513669829362836159665586901156483}, |
| 824 | {2.2500, 0.97802611473881363992272924300618321}, |
| 825 | {2.3125, 0.98058304703705186541999427134482061}, |
| 826 | {2.3750, 0.98284502917257603002353801620158861}, |
| 827 | {2.4375, 0.98484551746427837912703608465407824}, |
| 828 | {2.5000, 0.98661429815143028888127603923734964}, |
| 829 | {2.5625, 0.98817786228751240824802592958012269}, |
| 830 | {2.6250, 0.98955974861288320579361709496051109}, |
| 831 | {2.6875, 0.99078085564125158320311117560719312}, |
| 832 | {2.7500, 0.99185972456820774534967078914285035}, |
| 833 | {2.8125, 0.99281279483715982021711715899682324}, |
| 834 | {2.8750, 0.99365463431502962099607366282699651}, |
| 835 | {2.9375, 0.99439814606575805343721743822723671}, |
| 836 | {3.0000, 0.99505475368673045133188018525548849}, |
| 837 | {3.0625, 0.99563456710930963835715538507891736}, |
| 838 | {3.1250, 0.99614653067334504917102591131792951}, |
| 839 | {3.1875, 0.99659855517712942451966113109487039}, |
| 840 | {3.2500, 0.99699763548652601693227592643957226}, |
| 841 | {3.3125, 0.99734995516557367804571991063376923}, |
| 842 | {3.3750, 0.99766097946988897037219469409451602}, |
| 843 | {3.4375, 0.99793553792649036103161966894686844}, |
| 844 | {3.5000, 0.99817789761119870928427335245061171}, |
| 845 | {3.5625, 0.99839182812874152902001617480606320}, |
| 846 | {3.6250, 0.99858065920179882368897879066418294}, |
| 847 | {3.6875, 0.99874733168378115962760304582965538}, |
| 848 | {3.7500, 0.99889444272615280096784208280487888}, |
| 849 | {3.8125, 0.99902428575443546808677966295308778}, |
| 850 | {3.8750, 0.99913888583735077016137617231569011}, |
| 851 | {3.9375, 0.99924003097049627100651907919688313}, |
| 852 | {4.0000, 0.99932929973906704379224334434172499}, |
| 853 | {4.0625, 0.99940808577297384603818654530731215}, |
| 854 | {4.1250, 0.99947761936180856115470576756499454}, |
| 855 | {4.1875, 0.99953898655601372055527046497863955}, |
| 856 | {4.2500, 0.99959314604388958696521068958989891}, |
| 857 | {4.3125, 0.99964094406130644525586201091350343}, |
| 858 | {4.3750, 0.99968312756179494813069349082306235}, |
| 859 | {4.4375, 0.99972035584870534179601447812936151}, |
| 860 | {4.5000, 0.99975321084802753654050617379050162}, |
| 861 | {4.5625, 0.99978220617994689112771768489030236}, |
| 862 | {4.6250, 0.99980779516900105210240981251048167}, |
| 863 | {4.6875, 0.99983037791655283849546303868853396}, |
| 864 | {4.7500, 0.99985030754497877753787358852000255}, |
| 865 | {4.8125, 0.99986789571029070417475400133989992}, |
| 866 | {4.8750, 0.99988341746867772271011794614780441}, |
| 867 | {4.9375, 0.99989711557251558205051185882773206}, |
| 868 | {5.0000, 0.99990920426259513121099044753447306}, |
| 869 | {5.0625, 0.99991987261554158551063867262784721}, |
| 870 | {5.1250, 0.99992928749851651137225712249720606}, |
| 871 | {5.1875, 0.99993759617721206697530526661105307}, |
| 872 | {5.2500, 0.99994492861777083305830639416802036}, |
| 873 | {5.3125, 0.99995139951851344080105352145538345}, |
| 874 | {5.3750, 0.99995711010315817210152906092289064}, |
| 875 | {5.4375, 0.99996214970350792531554669737676253}, |
| 876 | {5.5000, 0.99996659715630380963848952941756868}, |
| 877 | {5.5625, 0.99997052203605101013786592945475432}, |
| 878 | {5.6250, 0.99997398574306704793434088941484766}, |
| 879 | {5.6875, 0.99997704246374583929961850444364696}, |
| 880 | {5.7500, 0.99997974001803825215761760428815437}, |
| 881 | {5.8125, 0.99998212060739040166557477723121777}, |
| 882 | {5.8750, 0.99998422147482750993344503195672517}, |
| 883 | {5.9375, 0.99998607548749972326220227464612338}, |
| 884 | {6.0000, 0.99998771165079557056434885235523206}, |
| 885 | {6.0625, 0.99998915556205996764518917496149338}, |
| 886 | {6.1250, 0.99999042981101021976277974520745310}, |
| 887 | {6.1875, 0.99999155433311068015449574811497719}, |
| 888 | {6.2500, 0.99999254672143162687722782398104276}, |
| 889 | {6.3125, 0.99999342250186907900400800240980139}, |
| 890 | {6.3750, 0.99999419537602957780612639767025158}, |
| 891 | {6.4375, 0.99999487743557848265406225515388994}, |
| 892 | {6.5000, 0.99999547935140419285107893831698753}, |
| 893 | {6.5625, 0.99999601054055694588617385671796346}, |
| 894 | {6.6250, 0.99999647931357331502887600387959900}, |
| 895 | {6.6875, 0.99999689300449080997594368612277442}, |
| 896 | {6.7500, 0.99999725808558628431084200832778748}, |
| 897 | {6.8125, 0.99999758026863294516387464046135924}, |
| 898 | {6.8750, 0.99999786459425991170635407313276785}, |
| 899 | {6.9375, 0.99999811551081218572759991597586905}, |
| 900 | {7.0000, 0.99999833694394467173571641595066708}, |
| 901 | {7.0625, 0.99999853235803894918375164252059190}, |
| 902 | {7.1250, 0.99999870481040359014665019356422927}, |
| 903 | {7.1875, 0.99999885699910593255108365463415411}, |
| 904 | {7.2500, 0.99999899130518359709674536482047025}, |
| 905 | {7.3125, 0.99999910982989611769943303422227663}, |
| 906 | {7.3750, 0.99999921442759946591163427422888252}, |
| 907 | {7.4375, 0.99999930673475777603853435094943258}, |
| 908 | {7.5000, 0.99999938819554614875054970643513124}, |
| 909 | {7.5625, 0.99999946008444508183970109263856958}, |
| 910 | {7.6250, 0.99999952352618001331402589096040117}, |
| 911 | {7.6875, 0.99999957951331792817413683491979752}, |
| 912 | {7.7500, 0.99999962892179632633374697389145081}, |
| 913 | {7.8125, 0.99999967252462750190604116210421169}, |
| 914 | {7.8750, 0.99999971100399253750324718031574484}, |
| 915 | {7.9375, 0.99999974496191422474977283863588658}, |
| 916 | {8.0000, 0.99999977492967588981001883295636840}, |
| 917 | {8.0625, 0.99999980137613348259726597081723424}, |
| 918 | {8.1250, 0.99999982471505097353529823063673263}, |
| 919 | {8.1875, 0.99999984531157382142423402736529911}, |
| 920 | {8.2500, 0.99999986348794179107425910499030547}, |
| 921 | {8.3125, 0.99999987952853049895833839645847571}, |
| 922 | {8.3750, 0.99999989368430056302584289932834041}, |
| 923 | {8.4375, 0.99999990617672396471542088609051728}, |
| 924 | {8.5000, 0.99999991720124905211338798152800748}, |
| 925 | {8.5625, 0.99999992693035839516545287745322387}, |
| 926 | {8.6250, 0.99999993551626733394129009365703767}, |
| 927 | {8.6875, 0.99999994309330543951799157347876934}, |
| 928 | {8.7500, 0.99999994978001814614368429416607424}, |
| 929 | {8.8125, 0.99999995568102143535399207289008504}, |
| 930 | {8.8750, 0.99999996088863858914831986187674522}, |
| 931 | {8.9375, 0.99999996548434461974481685677429908}, |
| 932 | {9.0000, 0.99999996954004097447930211118358244}, |
| 933 | {9.0625, 0.99999997311918045901919121395899372}, |
| 934 | {9.1250, 0.99999997627775997868467948564005257}, |
| 935 | {9.1875, 0.99999997906519662964368381583648379}, |
| 936 | {9.2500, 0.99999998152510084671976114264303159}, |
| 937 | {9.3125, 0.99999998369595870397054673668361266}, |
| 938 | {9.3750, 0.99999998561173404286033236040150950}, |
| 939 | {9.4375, 0.99999998730239984852716512979473289}, |
| 940 | {9.5000, 0.99999998879440718770812040917618843}, |
| 941 | {9.5625, 0.99999999011109904501789298212541698}, |
| 942 | {9.6250, 0.99999999127307553219220251303121960}, |
| 943 | {9.6875, 0.99999999229851618412119275358396363}, |
| 944 | {9.7500, 0.99999999320346438410630581726217930}, |
| 945 | {9.8125, 0.99999999400207836827291739324060736}, |
| 946 | {9.8750, 0.99999999470685273619047001387577653}, |
| 947 | {9.9375, 0.99999999532881393331131526966058758}, |
| 948 | {10.0000, 0.99999999587769276361959283713827574}, |
| 949 | }; |
| 950 | |
| 951 | for(int i = 0; i < testCases.length; i++) { |
| 952 | double [] testCase = testCases[i]; |
| 953 | failures += testTanhCaseWithUlpDiff(testCase[0], |
| 954 | testCase[1], |
| 955 | 3.0); |
| 956 | } |
| 957 | |
| 958 | |
| 959 | double [][] specialTestCases = { |
| 960 | {0.0, 0.0}, |
| 961 | {NaNd, NaNd}, |
| 962 | {Double.longBitsToDouble(0x7FF0000000000001L), NaNd}, |
| 963 | {Double.longBitsToDouble(0xFFF0000000000001L), NaNd}, |
| 964 | {Double.longBitsToDouble(0x7FF8555555555555L), NaNd}, |
| 965 | {Double.longBitsToDouble(0xFFF8555555555555L), NaNd}, |
| 966 | {Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL), NaNd}, |
| 967 | {Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL), NaNd}, |
| 968 | {Double.longBitsToDouble(0x7FFDeadBeef00000L), NaNd}, |
| 969 | {Double.longBitsToDouble(0xFFFDeadBeef00000L), NaNd}, |
| 970 | {Double.longBitsToDouble(0x7FFCafeBabe00000L), NaNd}, |
| 971 | {Double.longBitsToDouble(0xFFFCafeBabe00000L), NaNd}, |
| 972 | {Double.POSITIVE_INFINITY, 1.0} |
| 973 | }; |
| 974 | |
| 975 | for(int i = 0; i < specialTestCases.length; i++) { |
| 976 | failures += testTanhCaseWithUlpDiff(specialTestCases[i][0], |
| 977 | specialTestCases[i][1], |
| 978 | 0.0); |
| 979 | } |
| 980 | |
| 981 | // For powers of 2 less than 2^(-27), the second and |
| 982 | // subsequent terms of the Taylor series expansion will get |
| 983 | // rounded away since |n-n^3| > 53, the binary precision of a |
| 984 | // double significand. |
| 985 | |
| 986 | for(int i = DoubleConsts.MIN_SUB_EXPONENT; i < -27; i++) { |
| 987 | double d = FpUtils.scalb(2.0, i); |
| 988 | |
| 989 | // Result and expected are the same. |
| 990 | failures += testTanhCaseWithUlpDiff(d, d, 2.5); |
| 991 | } |
| 992 | |
| 993 | // For values of x larger than 22, tanh(x) is 1.0 in double |
| 994 | // floating-point arithmetic. |
| 995 | |
| 996 | for(int i = 22; i < 32; i++) { |
| 997 | failures += testTanhCaseWithUlpDiff(i, 1.0, 2.5); |
| 998 | } |
| 999 | |
| 1000 | for(int i = 5; i <= DoubleConsts.MAX_EXPONENT; i++) { |
| 1001 | double d = FpUtils.scalb(2.0, i); |
| 1002 | |
| 1003 | failures += testTanhCaseWithUlpDiff(d, 1.0, 2.5); |
| 1004 | } |
| 1005 | |
| 1006 | return failures; |
| 1007 | } |
| 1008 | |
| 1009 | public static int testTanhCaseWithTolerance(double input, |
| 1010 | double expected, |
| 1011 | double tolerance) { |
| 1012 | int failures = 0; |
| 1013 | failures += Tests.testTolerance("Math.tanh(double", |
| 1014 | input, Math.tanh(input), |
| 1015 | expected, tolerance); |
| 1016 | failures += Tests.testTolerance("Math.tanh(double", |
| 1017 | -input, Math.tanh(-input), |
| 1018 | -expected, tolerance); |
| 1019 | |
| 1020 | failures += Tests.testTolerance("StrictMath.tanh(double", |
| 1021 | input, StrictMath.tanh(input), |
| 1022 | expected, tolerance); |
| 1023 | failures += Tests.testTolerance("StrictMath.tanh(double", |
| 1024 | -input, StrictMath.tanh(-input), |
| 1025 | -expected, tolerance); |
| 1026 | return failures; |
| 1027 | } |
| 1028 | |
| 1029 | public static int testTanhCaseWithUlpDiff(double input, |
| 1030 | double expected, |
| 1031 | double ulps) { |
| 1032 | int failures = 0; |
| 1033 | |
| 1034 | failures += Tests.testUlpDiffWithAbsBound("Math.tanh(double)", |
| 1035 | input, Math.tanh(input), |
| 1036 | expected, ulps, 1.0); |
| 1037 | failures += Tests.testUlpDiffWithAbsBound("Math.tanh(double)", |
| 1038 | -input, Math.tanh(-input), |
| 1039 | -expected, ulps, 1.0); |
| 1040 | |
| 1041 | failures += Tests.testUlpDiffWithAbsBound("StrictMath.tanh(double)", |
| 1042 | input, StrictMath.tanh(input), |
| 1043 | expected, ulps, 1.0); |
| 1044 | failures += Tests.testUlpDiffWithAbsBound("StrictMath.tanh(double)", |
| 1045 | -input, StrictMath.tanh(-input), |
| 1046 | -expected, ulps, 1.0); |
| 1047 | return failures; |
| 1048 | } |
| 1049 | |
| 1050 | |
| 1051 | public static void main(String argv[]) { |
| 1052 | int failures = 0; |
| 1053 | |
| 1054 | failures += testSinh(); |
| 1055 | failures += testCosh(); |
| 1056 | failures += testTanh(); |
| 1057 | |
| 1058 | if (failures > 0) { |
| 1059 | System.err.println("Testing the hyperbolic functions incurred " |
| 1060 | + failures + " failures."); |
| 1061 | throw new RuntimeException(); |
| 1062 | } |
| 1063 | } |
| 1064 | |
| 1065 | } |