1 32 package org.jruby; 33 34 import org.jruby.runtime.CallbackFactory; 35 import org.jruby.runtime.builtin.IRubyObject; 36 37 public class RubyMath { 38 41 public static RubyModule createMathModule(Ruby runtime) { 42 RubyModule result = runtime.defineModule("Math"); 43 CallbackFactory callbackFactory = runtime.callbackFactory(RubyMath.class); 44 45 result.defineConstant("E", RubyFloat.newFloat(runtime, Math.E)); 46 result.defineConstant("PI", RubyFloat.newFloat(runtime, Math.PI)); 47 48 result.defineFastModuleFunction("atan2", callbackFactory.getFastSingletonMethod("atan2", RubyKernel.IRUBY_OBJECT, RubyKernel.IRUBY_OBJECT)); 49 result.defineFastModuleFunction("cos", callbackFactory.getFastSingletonMethod("cos", RubyKernel.IRUBY_OBJECT)); 50 result.defineFastModuleFunction("sin", callbackFactory.getFastSingletonMethod("sin", RubyKernel.IRUBY_OBJECT)); 51 result.defineFastModuleFunction("tan", callbackFactory.getFastSingletonMethod("tan", RubyKernel.IRUBY_OBJECT)); 52 53 result.defineFastModuleFunction("acos", callbackFactory.getFastSingletonMethod("acos", RubyKernel.IRUBY_OBJECT)); 54 result.defineFastModuleFunction("asin", callbackFactory.getFastSingletonMethod("asin", RubyKernel.IRUBY_OBJECT)); 55 result.defineFastModuleFunction("atan", callbackFactory.getFastSingletonMethod("atan", RubyKernel.IRUBY_OBJECT)); 56 57 result.defineFastModuleFunction("cosh", callbackFactory.getFastSingletonMethod("cosh", RubyKernel.IRUBY_OBJECT)); 58 result.defineFastModuleFunction("sinh", callbackFactory.getFastSingletonMethod("sinh", RubyKernel.IRUBY_OBJECT)); 59 result.defineFastModuleFunction("tanh", callbackFactory.getFastSingletonMethod("tanh", RubyKernel.IRUBY_OBJECT)); 60 61 result.defineFastModuleFunction("acosh", callbackFactory.getFastSingletonMethod("acosh", RubyKernel.IRUBY_OBJECT)); 62 result.defineFastModuleFunction("asinh", callbackFactory.getFastSingletonMethod("asinh", RubyKernel.IRUBY_OBJECT)); 63 result.defineFastModuleFunction("atanh", callbackFactory.getFastSingletonMethod("atanh", RubyKernel.IRUBY_OBJECT)); 64 65 result.defineFastModuleFunction("exp", callbackFactory.getFastSingletonMethod("exp", RubyKernel.IRUBY_OBJECT)); 66 result.defineFastModuleFunction("log", callbackFactory.getFastSingletonMethod("log", RubyKernel.IRUBY_OBJECT)); 67 result.defineFastModuleFunction("log10", callbackFactory.getFastSingletonMethod("log10", RubyKernel.IRUBY_OBJECT)); 68 result.defineFastModuleFunction("sqrt", callbackFactory.getFastSingletonMethod("sqrt", RubyKernel.IRUBY_OBJECT)); 69 70 result.defineFastModuleFunction("frexp", callbackFactory.getFastSingletonMethod("frexp", RubyKernel.IRUBY_OBJECT)); 71 result.defineFastModuleFunction("ldexp", callbackFactory.getFastSingletonMethod("ldexp", RubyKernel.IRUBY_OBJECT, RubyKernel.IRUBY_OBJECT)); 72 73 result.defineFastModuleFunction("hypot", callbackFactory.getFastSingletonMethod("hypot", RubyKernel.IRUBY_OBJECT, RubyKernel.IRUBY_OBJECT)); 74 result.defineFastModuleFunction("erf", callbackFactory.getFastSingletonMethod("erf", RubyKernel.IRUBY_OBJECT)); 75 result.defineFastModuleFunction("erfc", callbackFactory.getFastSingletonMethod("erfc", RubyKernel.IRUBY_OBJECT)); 76 77 return result; 78 } 79 80 81 private static void domainCheck(IRubyObject recv, double value, String msg) { 82 if (Double.isNaN(value)) { 83 throw recv.getRuntime().newErrnoEDOMError(msg); 84 } 85 } 86 87 private static double chebylevSerie(double x, double coef[]) { 88 double b0, b1, b2, twox; 89 int i; 90 b1 = 0.0; 91 b0 = 0.0; 92 b2 = 0.0; 93 twox = 2.0 * x; 94 for (i = coef.length-1; i >= 0; i--) { 95 b2 = b1; 96 b1 = b0; 97 b0 = twox * b1 - b2 + coef[i]; 98 } 99 return 0.5*(b0 - b2); 100 } 101 102 private static double sign(double x, double y) { 103 double abs = ((x < 0) ? -x : x); 104 return (y < 0.0) ? -abs : abs; 105 } 106 107 public static RubyFloat atan2(IRubyObject recv, IRubyObject x, IRubyObject y) { 108 double valuea = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 109 double valueb = ((RubyFloat)RubyKernel.new_float(recv,y)).getDoubleValue(); 110 return RubyFloat.newFloat(recv.getRuntime(), Math.atan2(valuea, valueb)); 111 } 112 113 public static RubyFloat cos(IRubyObject recv, IRubyObject x) { 114 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 115 return RubyFloat.newFloat(recv.getRuntime(),Math.cos(value)); 116 } 117 118 public static RubyFloat sin(IRubyObject recv, IRubyObject x) { 119 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 120 return RubyFloat.newFloat(recv.getRuntime(),Math.sin(value)); 121 } 122 123 public static RubyFloat tan(IRubyObject recv, IRubyObject x) { 124 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 125 return RubyFloat.newFloat(recv.getRuntime(),Math.tan(value)); 126 } 127 128 public static RubyFloat asin(IRubyObject recv, IRubyObject x) { 129 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 130 double result = Math.asin(value); 131 domainCheck(recv, result, "asin"); 132 return RubyFloat.newFloat(recv.getRuntime(),result); 133 } 134 135 public static RubyFloat acos(IRubyObject recv, IRubyObject x) { 136 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 137 double result = Math.acos(value); 138 domainCheck(recv, result, "acos"); 139 return RubyFloat.newFloat(recv.getRuntime(), result); 140 } 141 142 public static RubyFloat atan(IRubyObject recv, IRubyObject x) { 143 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 144 return RubyFloat.newFloat(recv.getRuntime(),Math.atan(value)); 145 } 146 147 public static RubyFloat cosh(IRubyObject recv, IRubyObject x) { 148 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 149 return RubyFloat.newFloat(recv.getRuntime(),(Math.exp(value) + Math.exp(-value)) / 2.0); 150 } 151 152 public static RubyFloat sinh(IRubyObject recv, IRubyObject x) { 153 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 154 return RubyFloat.newFloat(recv.getRuntime(),(Math.exp(value) - Math.exp(-value)) / 2.0); 155 } 156 157 public static RubyFloat tanh(IRubyObject recv, IRubyObject x) { 158 return RubyFloat.newFloat(recv.getRuntime(), sinh(recv, x).getDoubleValue() / cosh(recv, x).getDoubleValue()); 159 } 160 161 public static RubyFloat acosh(IRubyObject recv, IRubyObject x) { 162 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 163 double result; 164 if (Double.isNaN(value) || value < 1) { 165 result = Double.NaN; 166 } else if (value < 94906265.62) { 167 result = Math.log(value + Math.sqrt(value * value - 1.0)); 168 } else{ 169 result = 0.69314718055994530941723212145818 + Math.log(value); 170 } 171 172 domainCheck(recv, result, "acosh"); 173 174 return RubyFloat.newFloat(recv.getRuntime(),result); 175 } 176 177 private static final double ASINH_COEF[] = { 178 -.12820039911738186343372127359268e+0, 179 -.58811761189951767565211757138362e-1, 180 .47274654322124815640725249756029e-2, 181 -.49383631626536172101360174790273e-3, 182 .58506207058557412287494835259321e-4, 183 -.74669983289313681354755069217188e-5, 184 .10011693583558199265966192015812e-5, 185 -.13903543858708333608616472258886e-6, 186 .19823169483172793547317360237148e-7, 187 -.28847468417848843612747272800317e-8, 188 .42672965467159937953457514995907e-9, 189 -.63976084654366357868752632309681e-10, 190 .96991686089064704147878293131179e-11, 191 -.14844276972043770830246658365696e-11, 192 .22903737939027447988040184378983e-12, 193 -.35588395132732645159978942651310e-13, 194 .55639694080056789953374539088554e-14, 195 -.87462509599624678045666593520162e-15, 196 .13815248844526692155868802298129e-15, 197 -.21916688282900363984955142264149e-16, 198 .34904658524827565638313923706880e-17 199 }; 200 201 public static RubyFloat asinh(IRubyObject recv, IRubyObject x) { 202 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 203 double y = Math.abs(value); 204 double result; 205 206 if (Double.isNaN(value)) { 207 result = Double.NaN; 208 } else if (y <= 1.05367e-08) { 209 result = value; 210 } else if (y <= 1.0) { 211 result = value * (1.0 + chebylevSerie(2.0 * value * value - 1.0, ASINH_COEF)); 212 } else if (y < 94906265.62) { 213 result = Math.log(y + Math.sqrt(y * y + 1.0)); 214 } else { 215 result = 0.69314718055994530941723212145818 + Math.log(y); 216 } 217 if (value < 0.0) { 218 result = -result; 219 } 220 return RubyFloat.newFloat(recv.getRuntime(),result); 221 } 222 223 private static final double ATANH_COEF[] = { 224 .9439510239319549230842892218633e-1, 225 .4919843705578615947200034576668e-1, 226 .2102593522455432763479327331752e-2, 227 .1073554449776116584640731045276e-3, 228 .5978267249293031478642787517872e-5, 229 .3505062030889134845966834886200e-6, 230 .2126374343765340350896219314431e-7, 231 .1321694535715527192129801723055e-8, 232 .8365875501178070364623604052959e-10, 233 .5370503749311002163881434587772e-11, 234 .3486659470157107922971245784290e-12, 235 .2284549509603433015524024119722e-13, 236 .1508407105944793044874229067558e-14, 237 .1002418816804109126136995722837e-15, 238 .6698674738165069539715526882986e-17, 239 .4497954546494931083083327624533e-18 240 }; 241 242 public static RubyFloat atanh(IRubyObject recv, IRubyObject x) { 243 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 244 double y = Math.abs(value); 245 double result; 246 247 if (Double.isNaN(value)) { 248 result = Double.NaN; 249 } else if (y < 1.82501e-08) { 250 result = value; 251 } else if (y <= 0.5) { 252 result = value * (1.0 + chebylevSerie(8.0 * value * value - 1.0, ATANH_COEF)); 253 } else if (y < 1.0) { 254 result = 0.5 * Math.log((1.0 + value) / (1.0 - value)); 255 } else if (y == 1.0) { 256 result = value * Double.POSITIVE_INFINITY; 257 } else { 258 result = Double.NaN; 259 } 260 261 domainCheck(recv, result, "atanh"); 262 return RubyFloat.newFloat(recv.getRuntime(),result); 263 } 264 265 public static RubyFloat exp(IRubyObject recv, IRubyObject exponent) { 266 double value = ((RubyFloat)RubyKernel.new_float(recv,exponent)).getDoubleValue(); 267 return RubyFloat.newFloat(recv.getRuntime(),Math.exp(value)); 268 } 269 270 273 public static RubyFloat log(IRubyObject recv, IRubyObject x) { 274 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 275 double result = Math.log(value); 276 domainCheck(recv, result, "log"); 277 return RubyFloat.newFloat(recv.getRuntime(),result); 278 } 279 280 283 public static RubyFloat log10(IRubyObject recv, IRubyObject x) { 284 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 285 double result = Math.log(value) / Math.log(10); 286 domainCheck(recv, result, "log10"); 287 return RubyFloat.newFloat(recv.getRuntime(),result); 288 } 289 290 public static RubyFloat sqrt(IRubyObject recv, IRubyObject x) { 291 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 292 double result; 293 294 if (value < 0) { 295 result = Double.NaN; 296 } else{ 297 result = Math.sqrt(value); 298 } 299 300 domainCheck(recv, result, "sqrt"); 301 return RubyFloat.newFloat(recv.getRuntime(), result); 302 } 303 304 public static RubyFloat hypot(IRubyObject recv, IRubyObject x, IRubyObject y) { 305 double valuea = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 306 double valueb = ((RubyFloat)RubyKernel.new_float(recv,y)).getDoubleValue(); 307 double result; 308 309 if (Math.abs(valuea) > Math.abs(valueb)) { 310 result = valueb / valuea; 311 result = Math.abs(valuea) * Math.sqrt(1 + result * result); 312 } else if (valueb != 0) { 313 result = valuea / valueb; 314 result = Math.abs(valueb) * Math.sqrt(1 + result * result); 315 } else { 316 result = 0; 317 } 318 return RubyFloat.newFloat(recv.getRuntime(),result); 319 } 320 321 322 328 public static RubyArray frexp(IRubyObject recv, IRubyObject other) { 329 double mantissa = ((RubyFloat)RubyKernel.new_float(recv,other)).getDoubleValue(); 330 short sign = 1; 331 long exponent = 0; 332 333 if (mantissa != 0.0) { 334 if (mantissa < 0) { 336 mantissa = -mantissa; 337 sign = -1; 338 } 339 340 for (; mantissa < 0.5; mantissa *= 2.0, exponent -=1) { } 342 343 for (; mantissa >= 1.0; mantissa *= 0.5, exponent +=1) { } 345 } 346 347 return RubyArray.newArray(recv.getRuntime(), 348 RubyFloat.newFloat(recv.getRuntime(), sign * mantissa), 349 RubyNumeric.int2fix(recv.getRuntime(), exponent)); 350 } 351 352 355 public static RubyFloat ldexp(IRubyObject recv, IRubyObject mantissa, IRubyObject exponent) { 356 double mantissaValue = ((RubyFloat)RubyKernel.new_float(recv, mantissa)).getDoubleValue(); 357 return RubyFloat.newFloat(recv.getRuntime(),mantissaValue * Math.pow(2.0, RubyNumeric.num2int(exponent))); 358 } 359 360 private static final double ERFC_COEF[] = { 361 -.490461212346918080399845440334e-1, 362 -.142261205103713642378247418996e0, 363 .100355821875997955757546767129e-1, 364 -.576876469976748476508270255092e-3, 365 .274199312521960610344221607915e-4, 366 -.110431755073445076041353812959e-5, 367 .384887554203450369499613114982e-7, 368 -.118085825338754669696317518016e-8, 369 .323342158260509096464029309534e-10, 370 -.799101594700454875816073747086e-12, 371 .179907251139614556119672454866e-13, 372 -.371863548781869263823168282095e-15, 373 .710359900371425297116899083947e-17, 374 -.126124551191552258324954248533e-18 375 }; 376 377 public static RubyFloat erf(IRubyObject recv, IRubyObject x) { 378 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 379 380 double result; 381 double y = Math.abs(value); 382 383 if (y <= 1.49012e-08) { 384 result = 2 * value / 1.77245385090551602729816748334; 385 } else if (y <= 1) { 386 result = value * (1 + chebylevSerie(2 * value * value - 1, ERFC_COEF)); 387 } else if (y < 6.013687357) { 388 result = sign(1 - erfc(recv, RubyFloat.newFloat(recv.getRuntime(),y)).getDoubleValue(), value); 389 } else { 390 result = sign(1, value); 391 } 392 return RubyFloat.newFloat(recv.getRuntime(),result); 393 } 394 395 private static final double ERFC2_COEF[] = { 396 -.69601346602309501127391508262e-1, 397 -.411013393626208934898221208467e-1, 398 .391449586668962688156114370524e-2, 399 -.490639565054897916128093545077e-3, 400 .715747900137703638076089414183e-4, 401 -.115307163413123283380823284791e-4, 402 .199467059020199763505231486771e-5, 403 -.364266647159922287393611843071e-6, 404 .694437261000501258993127721463e-7, 405 -.137122090210436601953460514121e-7, 406 .278838966100713713196386034809e-8, 407 -.581416472433116155186479105032e-9, 408 .123892049175275318118016881795e-9, 409 -.269063914530674343239042493789e-10, 410 .594261435084791098244470968384e-11, 411 -.133238673575811957928775442057e-11, 412 .30280468061771320171736972433e-12, 413 -.696664881494103258879586758895e-13, 414 .162085454105392296981289322763e-13, 415 -.380993446525049199987691305773e-14, 416 .904048781597883114936897101298e-15, 417 -.2164006195089607347809812047e-15, 418 .522210223399585498460798024417e-16, 419 -.126972960236455533637241552778e-16, 420 .310914550427619758383622741295e-17, 421 -.766376292032038552400956671481e-18, 422 .190081925136274520253692973329e-18 423 }; 424 425 private static final double ERFCC_COEF[] = { 426 .715179310202924774503697709496e-1, 427 -.265324343376067157558893386681e-1, 428 .171115397792085588332699194606e-2, 429 -.163751663458517884163746404749e-3, 430 .198712935005520364995974806758e-4, 431 -.284371241276655508750175183152e-5, 432 .460616130896313036969379968464e-6, 433 -.822775302587920842057766536366e-7, 434 .159214187277090112989358340826e-7, 435 -.329507136225284321486631665072e-8, 436 .72234397604005554658126115389e-9, 437 -.166485581339872959344695966886e-9, 438 .401039258823766482077671768814e-10, 439 -.100481621442573113272170176283e-10, 440 .260827591330033380859341009439e-11, 441 -.699111056040402486557697812476e-12, 442 .192949233326170708624205749803e-12, 443 -.547013118875433106490125085271e-13, 444 .158966330976269744839084032762e-13, 445 -.47268939801975548392036958429e-14, 446 .14358733767849847867287399784e-14, 447 -.444951056181735839417250062829e-15, 448 .140481088476823343737305537466e-15, 449 -.451381838776421089625963281623e-16, 450 .147452154104513307787018713262e-16, 451 -.489262140694577615436841552532e-17, 452 .164761214141064673895301522827e-17, 453 -.562681717632940809299928521323e-18, 454 .194744338223207851429197867821e-18 455 }; 456 457 public static RubyFloat erfc(IRubyObject recv, IRubyObject x) { 458 double value = ((RubyFloat)RubyKernel.new_float(recv,x)).getDoubleValue(); 459 double result; 460 double y = Math.abs(value); 461 462 if (value <= -6.013687357) { 463 result = 2; 464 } else if (y < 1.49012e-08) { 465 result = 1 - 2 * value / 1.77245385090551602729816748334; 466 } else { 467 double ysq = y*y; 468 if (y < 1) { 469 result = 1 - value * (1 + chebylevSerie(2 * ysq - 1, ERFC_COEF)); 470 } else if (y <= 4.0) { 471 result = Math.exp(-ysq)/y*(0.5+chebylevSerie((8.0 / ysq - 5.0) / 3.0, ERFC2_COEF)); 472 if (value < 0) result = 2.0 - result; 473 if (value < 0) result = 2.0 - result; 474 if (value < 0) result = 2.0 - result; 475 } else { 476 result = Math.exp(-ysq) / y * (0.5 + chebylevSerie(8.0 / ysq - 1, ERFCC_COEF)); 477 if (value < 0) result = 2.0 - result; 478 } 479 } 480 return RubyFloat.newFloat(recv.getRuntime(),result); 481 } 482 483 } 484 | Popular Tags |