KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyMath


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
15  * Copyright (C) 2001-2002 Jan Arne Petersen <jpetersen@uni-bonn.de>
16  * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
17  * Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org>
18  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
19  *
20  * Alternatively, the contents of this file may be used under the terms of
21  * either of the GNU General Public License Version 2 or later (the "GPL"),
22  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23  * in which case the provisions of the GPL or the LGPL are applicable instead
24  * of those above. If you wish to allow use of your version of this file only
25  * under the terms of either the GPL or the LGPL, and not to allow others to
26  * use your version of this file under the terms of the CPL, indicate your
27  * decision by deleting the provisions above and replace them with the notice
28  * and other provisions required by the GPL or the LGPL. If you do not delete
29  * the provisions above, a recipient may use your version of this file under
30  * the terms of any one of the CPL, the GPL or the LGPL.
31  ***** END LICENSE BLOCK *****/

32 package org.jruby;
33
34 import org.jruby.runtime.CallbackFactory;
35 import org.jruby.runtime.builtin.IRubyObject;
36
37 public class RubyMath {
38     /** Create the Math module and add it to the Ruby runtime.
39      *
40      */

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 JavaDoc 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     /** Returns the natural logarithm of x.
271      *
272      */

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     /** Returns the base 10 logarithm of x.
281      *
282      */

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     /*
323      * x = mantissa * 2 ** exponent
324      *
325      * Where mantissa is in the range of [.5, 1)
326      *
327      */

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             // Make mantissa same sign so we only have one code path.
335
if (mantissa < 0) {
336                 mantissa = -mantissa;
337                 sign = -1;
338             }
339
340             // Increase value to hit lower range.
341
for (; mantissa < 0.5; mantissa *= 2.0, exponent -=1) { }
342
343             // Decrease value to hit upper range.
344
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     /*
353      * r = x * 2 ** y
354      */

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