decimal 0.0.2 → 0.0.90.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/inum192.h ADDED
@@ -0,0 +1,332 @@
1
+ /*
2
+ * Ruby's Integer part from ruby_1_9_2, r28085.
3
+ *
4
+ * These are hand copies (with few modifications) taken from original
5
+ * Ruby's code in "numeric.c" and "bignum.c," so the copyrights are
6
+ * held by matz and other contributors:
7
+ *
8
+ * Copyright (C) 1993-2010 Yukihiro Matsumoto
9
+ *
10
+ */
11
+
12
+ /*
13
+ * copied from bignum.c
14
+ */
15
+
16
+ #define BDIGITS(x) (RBIGNUM_DIGITS(x))
17
+
18
+ #ifndef HAVE_RB_BIGZERO_P
19
+ #error Ruby 1.9.2 should have rb_bigzero_p()!
20
+ #endif
21
+
22
+ static VALUE
23
+ rb_big_uminus(VALUE x)
24
+ {
25
+ VALUE z = rb_big_clone(x);
26
+
27
+ RBIGNUM_SET_SIGN(z, !RBIGNUM_SIGN(x));
28
+
29
+ return rb_big_norm(z); /* modified to use exported one */
30
+ }
31
+
32
+ static VALUE
33
+ rb_big_hash(VALUE x)
34
+ {
35
+ st_index_t hash;
36
+
37
+ hash = rb_memhash(BDIGITS(x), sizeof(BDIGIT)*RBIGNUM_LEN(x)) ^ RBIGNUM_SIGN(x);
38
+ return INT2FIX(hash);
39
+ }
40
+
41
+ static VALUE
42
+ rb_big_odd_p(VALUE num)
43
+ {
44
+ if (BDIGITS(num)[0] & 1) {
45
+ return Qtrue;
46
+ }
47
+ return Qfalse;
48
+ }
49
+
50
+ /*
51
+ * copied from numeric.c
52
+ */
53
+
54
+ static VALUE
55
+ flo_to_s(VALUE flt)
56
+ {
57
+ char buf[32];
58
+ double value = RFLOAT_VALUE(flt);
59
+ char *p, *e;
60
+
61
+ if (isinf(value))
62
+ return rb_usascii_str_new2(value < 0 ? "-Infinity" : "Infinity");
63
+ else if(isnan(value))
64
+ return rb_usascii_str_new2("NaN");
65
+
66
+ snprintf(buf, sizeof(buf), "%#.15g", value); /* ensure to print decimal point */
67
+ if (!(e = strchr(buf, 'e'))) {
68
+ e = buf + strlen(buf);
69
+ }
70
+ if (!ISDIGIT(e[-1])) { /* reformat if ended with decimal point (ex 111111111111111.) */
71
+ snprintf(buf, sizeof(buf), "%#.14e", value);
72
+ if (!(e = strchr(buf, 'e'))) {
73
+ e = buf + strlen(buf);
74
+ }
75
+ }
76
+ p = e;
77
+ while (p[-1]=='0' && ISDIGIT(p[-2]))
78
+ p--;
79
+ memmove(p, e, strlen(e)+1);
80
+ return rb_usascii_str_new2(buf);
81
+ }
82
+
83
+ static VALUE
84
+ fix_plus(VALUE x, VALUE y)
85
+ {
86
+ if (FIXNUM_P(y)) {
87
+ long a, b, c;
88
+ VALUE r;
89
+
90
+ a = FIX2LONG(x);
91
+ b = FIX2LONG(y);
92
+ c = a + b;
93
+ r = LONG2NUM(c);
94
+
95
+ return r;
96
+ }
97
+ return rb_big_plus(y, x); /* modified */
98
+ }
99
+
100
+ static VALUE
101
+ fix_minus(VALUE x, VALUE y)
102
+ {
103
+ if (FIXNUM_P(y)) {
104
+ long a, b, c;
105
+ VALUE r;
106
+
107
+ a = FIX2LONG(x);
108
+ b = FIX2LONG(y);
109
+ c = a - b;
110
+ r = LONG2NUM(c);
111
+
112
+ return r;
113
+ }
114
+ /* modified */
115
+ x = rb_int2big(FIX2LONG(x));
116
+ return rb_big_minus(x, y);
117
+ }
118
+
119
+ #define SQRT_LONG_MAX ((SIGNED_VALUE)1<<((SIZEOF_LONG*CHAR_BIT-1)/2))
120
+ /*tests if N*N would overflow*/
121
+ #define FIT_SQRT_LONG(n) (((n)<SQRT_LONG_MAX)&&((n)>=-SQRT_LONG_MAX))
122
+
123
+ static VALUE
124
+ fix_mul(VALUE x, VALUE y)
125
+ {
126
+ if (FIXNUM_P(y)) {
127
+ #ifdef __HP_cc
128
+ /* avoids an optimization bug of HP aC++/ANSI C B3910B A.06.05 [Jul 25 2005] */
129
+ volatile
130
+ #endif
131
+ long a, b;
132
+ #if SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
133
+ LONG_LONG d;
134
+ #else
135
+ long c;
136
+ VALUE r;
137
+ #endif
138
+
139
+ a = FIX2LONG(x);
140
+ b = FIX2LONG(y);
141
+
142
+ #if SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
143
+ d = (LONG_LONG)a * b;
144
+ if (FIXABLE(d)) return LONG2FIX(d);
145
+ return rb_ll2inum(d);
146
+ #else
147
+ if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b))
148
+ return LONG2FIX(a*b);
149
+ c = a * b;
150
+ r = LONG2FIX(c);
151
+
152
+ if (a == 0) return x;
153
+ if (FIX2LONG(r) != c || c/a != b) {
154
+ r = rb_big_mul(rb_int2big(a), rb_int2big(b));
155
+ }
156
+ return r;
157
+ #endif
158
+ }
159
+ /* modified */
160
+ return rb_big_mul(y, x);
161
+ }
162
+
163
+ static void
164
+ fixdivmod(long x, long y, long *divp, long *modp)
165
+ {
166
+ long div, mod;
167
+
168
+ if (y == 0) rb_bug("fixdivmod(): not reached"); /* modified */
169
+ if (y < 0) {
170
+ if (x < 0)
171
+ div = -x / -y;
172
+ else
173
+ div = - (x / -y);
174
+ }
175
+ else {
176
+ if (x < 0)
177
+ div = - (-x / y);
178
+ else
179
+ div = x / y;
180
+ }
181
+ mod = x - div*y;
182
+ if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
183
+ mod += y;
184
+ div -= 1;
185
+ }
186
+ if (divp) *divp = div;
187
+ if (modp) *modp = mod;
188
+ }
189
+
190
+ /* extracted from fix_divide() */
191
+ static VALUE
192
+ fix_div(VALUE x, VALUE y)
193
+ {
194
+ if (FIXNUM_P(y)) {
195
+ long div;
196
+
197
+ fixdivmod(FIX2LONG(x), FIX2LONG(y), &div, 0);
198
+ return LONG2NUM(div);
199
+ }
200
+ /* modified */
201
+ x = rb_int2big(FIX2LONG(x));
202
+ return rb_big_div(x, y);
203
+ }
204
+
205
+ static VALUE
206
+ fix_divmod(VALUE x, VALUE y)
207
+ {
208
+ if (FIXNUM_P(y)) {
209
+ long div, mod;
210
+
211
+ fixdivmod(FIX2LONG(x), FIX2LONG(y), &div, &mod);
212
+
213
+ return rb_assoc_new(LONG2NUM(div), LONG2NUM(mod));
214
+ }
215
+ /* modified */
216
+ x = rb_int2big(FIX2LONG(x));
217
+ return rb_big_divmod(x, y);
218
+ }
219
+
220
+ static VALUE
221
+ int_pow(long x, unsigned long y)
222
+ {
223
+ int neg = x < 0;
224
+ long z = 1;
225
+
226
+ if (neg) x = -x;
227
+ if (y & 1)
228
+ z = x;
229
+ else
230
+ neg = 0;
231
+ y &= ~1;
232
+ do {
233
+ while (y % 2 == 0) {
234
+ if (!FIT_SQRT_LONG(x)) {
235
+ VALUE v;
236
+ bignum:
237
+ v = rb_big_pow(rb_int2big(x), LONG2NUM(y));
238
+ if (z != 1) v = rb_big_mul(rb_int2big(neg ? -z : z), v);
239
+ return v;
240
+ }
241
+ x = x * x;
242
+ y >>= 1;
243
+ }
244
+ {
245
+ long xz = x * z;
246
+ if (!POSFIXABLE(xz) || xz / x != z) {
247
+ goto bignum;
248
+ }
249
+ z = xz;
250
+ }
251
+ } while (--y);
252
+ if (neg) z = -z;
253
+ return LONG2NUM(z);
254
+ }
255
+
256
+ static VALUE fix_odd_p(VALUE num);
257
+
258
+ static VALUE
259
+ fix_pow(VALUE x, VALUE y)
260
+ {
261
+ /* static const double zero = 0.0; */
262
+ long a = FIX2LONG(x);
263
+
264
+ if (FIXNUM_P(y)) {
265
+ long b = FIX2LONG(y);
266
+
267
+ if (b < 0)
268
+ return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
269
+
270
+ if (b == 0) return INT2FIX(1);
271
+ if (b == 1) return x;
272
+ if (a == 0) {
273
+ if (b > 0) return INT2FIX(0);
274
+ /* modified */
275
+ rb_bug("fix_pow(): infinity returned");
276
+ return Qnil;
277
+ }
278
+ if (a == 1) return INT2FIX(1);
279
+ if (a == -1) {
280
+ if (b % 2 == 0)
281
+ return INT2FIX(1);
282
+ else
283
+ return INT2FIX(-1);
284
+ }
285
+ return int_pow(a, b);
286
+ }
287
+ /* modified */
288
+ if (rb_funcall(y, '<', 1, INT2FIX(0)))
289
+ return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y);
290
+
291
+ if (a == 0) return INT2FIX(0);
292
+ if (a == 1) return INT2FIX(1);
293
+ if (a == -1) {
294
+ /* modified */
295
+ #define int_even_p(x) \
296
+ (FIXNUM_P(x) ? !fix_odd_p(x) : !rb_big_odd_p(x))
297
+ if (int_even_p(y)) return INT2FIX(1);
298
+ #undef int_even_p
299
+ else return INT2FIX(-1);
300
+ }
301
+ x = rb_int2big(FIX2LONG(x));
302
+ return rb_big_pow(x, y);
303
+ }
304
+
305
+ static VALUE
306
+ fix_equal(VALUE x, VALUE y)
307
+ {
308
+ if (x == y) return Qtrue;
309
+ if (FIXNUM_P(y)) return Qfalse;
310
+ return rb_big_eq(y, x); /* modified */
311
+ }
312
+
313
+ static VALUE
314
+ fix_cmp(VALUE x, VALUE y)
315
+ {
316
+ if (x == y) return INT2FIX(0);
317
+ if (FIXNUM_P(y)) {
318
+ if (FIX2LONG(x) > FIX2LONG(y)) return INT2FIX(1);
319
+ return INT2FIX(-1);
320
+ }
321
+ /* modified */
322
+ return rb_big_cmp(rb_int2big(FIX2LONG(x)), y);
323
+ }
324
+
325
+ static VALUE
326
+ fix_odd_p(VALUE num)
327
+ {
328
+ if (num & 2) {
329
+ return Qtrue;
330
+ }
331
+ return Qfalse;
332
+ }
data/lib/decimal.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'decimal.so'
2
+ require 'decimal/math'
@@ -0,0 +1,566 @@
1
+ module Decimal::Math
2
+ module_function
3
+
4
+ # algorithm of functions below are from book: ISBN4-87408-414-1
5
+ # sqrt, cbrt, erf, erfc, *p_gamma, *q_gamma, *bernoulli
6
+
7
+ # functions and variables that prefixed by "_decimal_internal" are
8
+ # indended to internal use only
9
+ def _decimal_internal_p_gamma(a, x, loggamma_a, scale, rounding=:down)
10
+ if x >= 1 + a
11
+ y = 1 - _decimal_internal_q_gamma(a, x, loggamma_a, scale+1, :down)
12
+ return y.round(scale, rounding)
13
+ end
14
+ return Decimal("0e#{-scale}") if x.zero?
15
+ y0 = exp(a * log(x, scale+1, :down) - x - loggamma_a, scale+1, :down)
16
+ y = term = y0.divide(a, scale+1, :down)
17
+ k = 1
18
+ loop do
19
+ tmp = x.divide(a + k, scale+1, :down)
20
+ term = (term * tmp).floor(scale+1)
21
+ break if term.zero?
22
+ y += term
23
+ k += 1
24
+ end
25
+ y.round(scale, rounding)
26
+ end
27
+
28
+ def _decimal_internal_q_gamma(a, x, loggamma_a, scale, rounding=:down)
29
+ la, lb = 1, 1 + x - a
30
+ if x < 1 + a
31
+ y = 1 - _decimal_internal_p_gamma(a, x, loggamma_a, scale+1, :down)
32
+ return y.round(scale, rounding)
33
+ end
34
+ w = exp(a * log(x, scale+1, :down) - x - loggamma_a, scale+1, :down)
35
+ y = w.divide(lb, scale+1, :down)
36
+ k = 2
37
+ loop do
38
+ tmp0 = (k - 1 - a) * (lb - la) + (k + x) * lb
39
+ tmp = tmp0.divide(k, scale+1, :down)
40
+ la, lb = lb, tmp
41
+ w0 = (k - 1 - a).divide(k, scale+1, :down)
42
+ w = (w * w0).floor(scale+1)
43
+ term = w.divide(la * lb, scale+1, :down)
44
+ break if term.zero?
45
+ y += term
46
+ end
47
+ y.round(scale, rounding)
48
+ end
49
+
50
+ def _decimal_internal_bernoulli(x, scale, rounding=:down)
51
+ return Decimal(1) if x == 0
52
+ return Decimal("-0.5") if x == 1
53
+ return Decimal(0) unless x % 2 == 0
54
+
55
+ t = Hash.new(0)
56
+ t[1] = 1
57
+ q = 1
58
+ n = 2
59
+ sign = -1
60
+ loop do
61
+ (1...n).each do |i|
62
+ t[i-1] = i * t[i]
63
+ end
64
+ t[n-1] = 0
65
+ n.downto(2) do |i|
66
+ t[i] += t[i - 2]
67
+ end
68
+ if n.even?
69
+ sign = -sign
70
+ q *= 4
71
+ b1 = n * t[0]
72
+ b2 = q * (q - 1)
73
+ return sign * Decimal(b1).divide(b2, scale, rounding) if n == x
74
+ end
75
+ n += 1
76
+ end
77
+ end
78
+
79
+ def _decimal_internal_fact(n)
80
+ return 1 if n < 2
81
+ (2..n).inject {|a, x| a * x}
82
+ end
83
+
84
+ #
85
+ # public functions
86
+ #
87
+
88
+ def sqrt(x, scale, rounding=:down)
89
+ x = Decimal(x) if x.integer?
90
+ return Decimal::NAN if x.nan?
91
+ return Decimal("0e#{-scale}") if x.zero?
92
+ raise Errno::EDOM if x < 0 # XXX
93
+ return Decimal::INFINITY if x.infinite?
94
+
95
+ s = x > 1 ? x : (x + 1).divide(2, scale+1, :down)
96
+ begin
97
+ last = s
98
+ t = x.divide(s, scale+1, :down) + s
99
+ s = t.divide(2, scale+1, :down)
100
+ end while s < last
101
+ last.round(scale, rounding)
102
+ end
103
+
104
+ def cbrt(x, scale, rounding=:down)
105
+ x = Decimal(x) if x.integer?
106
+ return x if x.nan? or x.infinite?
107
+ if x.zero?
108
+ negative_zero = Decimal(1).divide(x) < 0 # TODO
109
+ return negative_zero ? Decimal("-0e#{-scale}") : Decimal("0e#{-scale}")
110
+ end
111
+ x = -x if negative = x < 0
112
+
113
+ s = x > 1 ? x : Decimal(1)
114
+ begin
115
+ last = s
116
+ t = x.divide(s * s, scale+1, :down) + 2 * s
117
+ s = t.divide(3, scale+1, :down)
118
+ end while s < last
119
+ last = -last if negative
120
+ last.round(scale, rounding)
121
+ end
122
+
123
+ # functions below are copied from BigDecimal:
124
+ # sin, cos, exp, log, atan, pi
125
+
126
+ def sin(x, scale, rounding=:down)
127
+ x = Decimal(x) if x.integer?
128
+ return Decimal::NAN if x.infinite? or x.nan?
129
+ return Decimal("0e#{-scale}") if x.zero?
130
+ x = -x if negative = x < 0
131
+ x1 = x
132
+ x2 = x * x
133
+ sign = 1
134
+ y = x
135
+ i = z = 1
136
+ loop do
137
+ sign = -sign
138
+ x1 *= x2
139
+ i += 2
140
+ z *= (i - 1) * i
141
+ d = sign * x1.divide(z, scale+1, :down)
142
+ break if d.zero?
143
+ y += d
144
+ end
145
+ y = -y if negative
146
+ y.round(scale, rounding)
147
+ end
148
+
149
+ def cos(x, scale, rounding=:down)
150
+ x = Decimal(x) if x.integer?
151
+ return Decimal::NAN if x.infinite? or x.nan?
152
+ x = -x if x < 0
153
+ x1 = 1
154
+ x2 = x * x
155
+ sign = 1
156
+ y = Decimal(1)
157
+ i = 0
158
+ z = 1
159
+ loop do
160
+ sign = -sign
161
+ x1 *= x2
162
+ i += 2
163
+ z *= (i - 1) * i
164
+ d = sign * x1.divide(z, scale+1, :down)
165
+ break if d.zero?
166
+ y += d
167
+ end
168
+ y.round(scale, rounding)
169
+ end
170
+
171
+ def tan(x, scale, rounding=:down)
172
+ x = Decimal(x) if x.integer?
173
+ return Decimal::NAN if x.infinite? or x.nan?
174
+ return Decimal("0e#{-scale}") if x.zero?
175
+ raise Errno::EDOM if x.infinite? # XXX
176
+ s, c = sin(x, scale+1), cos(x, scale+1)
177
+ s.divide(c, scale, rounding)
178
+ end
179
+
180
+ def exp(x, scale, rounding=:down)
181
+ x = Decimal(x) if x.integer?
182
+ return Decimal::NAN if x.infinite? or x.nan?
183
+ return Decimal(1) if x.zero?
184
+ if x.infinite?
185
+ return x > 0 ? Decimal::INFINITY : Decimal("0e#{-scale}")
186
+ end
187
+ x = -x if negative = x < 0
188
+ z = x1 = y = 1
189
+ i = 0
190
+ loop do
191
+ x1 *= x
192
+ i += 1
193
+ z *= i
194
+ d = x1.divide(z, scale+1, :down)
195
+ break if d.zero?
196
+ y += d
197
+ end
198
+ unless negative
199
+ y.round(scale, rounding)
200
+ else
201
+ Decimal(1).divide(y, scale, rounding)
202
+ end
203
+ end
204
+
205
+ def e(scale, rounding=:down)
206
+ exp(1, scale, rounding)
207
+ end
208
+
209
+ def log(x, *args) # args:(base=nil, scale, rounding=:down)
210
+ case args.size
211
+ when 1
212
+ base = nil
213
+ scale = args[0]
214
+ rounding = :down
215
+ when 2
216
+ case args[1]
217
+ when Symbol
218
+ base = nil
219
+ scale, rounding = *args
220
+ unless scale.is_a?(Integer)
221
+ raise TypeError, "scale #{scale} must be Integer"
222
+ end
223
+ when Integer
224
+ base, scale = *args
225
+ unless base.is_a?(Integer)
226
+ raise TypeError, "base #{base} must be Integer"
227
+ end
228
+ rounding = :down
229
+ else
230
+ raise ArgumentError, "3rd argument #{args[1]} must be Integer or Symbol"
231
+ end
232
+ when 3
233
+ base, scale, rounding = *args
234
+ else
235
+ raise ArgumentError, "wrong number of arguments (#{args.size+1} for 2..4)"
236
+ end
237
+
238
+ x = Decimal(x) if x.integer?
239
+ return Decimal::NAN if x.nan?
240
+ return Decimal("0e#{-scale}") if x == 1
241
+ raise Errno::EDOM if x < 0 # XXX
242
+ raise Errno::ERANGE if x.zero? # XXX
243
+ return Decimal::INFINITY if x.infinite?
244
+
245
+ if x > 10 or x < Decimal("0.1")
246
+ x2, n = frexp10(x)
247
+ y = n * log(10, base, scale+1, :down) + log(x2, base, scale+1, :down)
248
+ return y.round(scale, rounding)
249
+ end
250
+
251
+ u = (x - 1).divide(x + 1, scale+1, :down)
252
+ u2 = u * u
253
+ y = u
254
+ i = 1
255
+ loop do
256
+ u = (u * u2).floor(scale+1)
257
+ i += 2
258
+ d = u.divide(i, scale+1, :down)
259
+ break if d.zero?
260
+ y += d
261
+ end
262
+ y *= 2
263
+ if base
264
+ divisor = log(base, scale+1, :down) # divisor = ln(base)
265
+ y = y.divide(divisor, scale+1, :down)
266
+ end
267
+ y.round(scale, rounding)
268
+ end
269
+
270
+ # internal use only
271
+ @@_decimal_internal_sqrt_01 = Decimal("0.316227766016838")
272
+ @@_decimal_internal_sqrt_10 = Decimal("3.16227766016838")
273
+ # TODO: better thresholds needed
274
+ def log10(x, scale, rounding=:down)
275
+ x = Decimal(x) if x.integer?
276
+ return Decimal::INFINITY if x.infinite?
277
+ if x > @@_decimal_internal_sqrt_10 or x < @@_decimal_internal_sqrt_01
278
+ x2, n = frexp10(x)
279
+ (log(x2, 10, scale+1) + n).round(scale, rounding)
280
+ else
281
+ log(x, 10, scale, rounding)
282
+ end
283
+ end
284
+
285
+ def log2(x, scale, rounding=:down)
286
+ log(x, 2, scale, rounding)
287
+ end
288
+
289
+ def pi(scale, rounding=:down)
290
+ pi = 0
291
+
292
+ k = 1
293
+ t = Decimal(-80)
294
+ u = nil
295
+ loop do
296
+ t = t.divide(-25, scale+1, :down)
297
+ u = t.divide(k, scale+1, :down)
298
+ break if u.zero?
299
+ pi += u
300
+ k += 2
301
+ end
302
+
303
+ k = 1
304
+ t = Decimal(956)
305
+ loop do
306
+ t = t.divide(-57121, scale+1, :down)
307
+ u = t.divide(k, scale+1, :down)
308
+ break if u.zero?
309
+ pi += u
310
+ k += 2
311
+ end
312
+ pi.round(scale, rounding)
313
+ end
314
+
315
+ def atan(x, scale, rounding=:down)
316
+ x = Decimal(x) if x.integer?
317
+ return Decimal::NAN if x.nan?
318
+ return Decimal("0e#{-scale}") if x.zero?
319
+ x = -x if negative = x < 0
320
+ local_pi = lambda{pi(scale+1, :down)}
321
+ return local_pi[].divide(negative ? -2 : 2, scale, rounding) if x.infinite?
322
+ return local_pi[].divide(negative ? -4 : 4, scale, rounding) if x == 1
323
+ x = Decimal(1).divide(x, scale+1, :down) if inverse = x > 1
324
+ if double = x > Decimal("0.5")
325
+ inx = -1 + sqrt(1 + x * x, scale+1, :down)
326
+ x = inx.divide(x, scale+1,:down)
327
+ end
328
+ t = y = x
329
+ r = 3
330
+ x2 = (x * x).floor(scale+1)
331
+ loop do
332
+ t = ((-t) * x2).floor(scale+1)
333
+ d = t.divide(r, scale+1, :down)
334
+ break if d.zero?
335
+ y += d
336
+ r += 2
337
+ end
338
+ y *= 2 if double
339
+ y = local_pi[].divide(2, scale+1, :down) - y if inverse
340
+ y = -y if negative
341
+ y.round(scale, rounding)
342
+ end
343
+
344
+ def asin(x, scale, rounding=:down)
345
+ x = Decimal(x) if x.integer?
346
+ return Decimal::NAN if x.nan?
347
+ return Decimal("0e#{-scale}") if x.zero?
348
+ raise Errno::EDOM if x > 1 or x < -1 # XXX
349
+ x2 = sqrt(1 - x * x, scale+1, :down)
350
+ atan(x.divide(x2, scale+1, :down), scale, rounding)
351
+ end
352
+
353
+ def acos(x, scale, rounding=:down)
354
+ x = Decimal(x) if x.integer?
355
+ return Decimal::NAN if x.nan?
356
+ return Decimal("0e#{-scale}") if x == 1
357
+ raise Errno::EDOM if x.infinite? or x > 1 or x < -1 # XXX
358
+ pi_half = pi(scale+1, :down).divide(2, scale+1, :down)
359
+ as = asin(x, scale+1, :down)
360
+ (pi_half - as).round(scale, rounding)
361
+ end
362
+
363
+ def atan2(y, x, scale, rounding=:down)
364
+ x = Decimal(x) if x.integer?
365
+ y = Decimal(y) if y.integer?
366
+ return Decimal::NAN if x.nan? or y.nan?
367
+ if y_sign = y.infinite?
368
+ z = pi(scale+1, :down)
369
+ divisor = nil
370
+ if x_sign = x.infinite?
371
+ z *= 3 if x_sign < 0
372
+ divisor = 4
373
+ else
374
+ divisor = 2
375
+ end
376
+ return y_sign * z.divide(divisor, scale, rounding)
377
+ elsif y.zero?
378
+ y_sign = Decimal(1).divide(y) < 0
379
+ x_negative = x < 0 or (x.zero? and Decimal(1).divide(x) < 0)
380
+ z = x_negative ? pi(scale, rounding) : Decimal("0e#{-scale}")
381
+ return y_sign ? -z : z
382
+ elsif x.zero?
383
+ z = pi(scale+1, :down).divide(2, scale, rounding)
384
+ return y < 0 ? -z : z
385
+ elsif x_sign = x.infinite?
386
+ z = x_sign < 0 ? pi(scale, rounding) : Decimal("0e#{-scale}")
387
+ return y < 0 ? -z : z
388
+ end
389
+
390
+ z = x.divide(y, scale+1, :down)
391
+ atan(z, scale, rounding)
392
+ end
393
+
394
+ def sinh(x, scale, rounding=:down)
395
+ x = Decimal(x) if x.integer?
396
+ return Decimal::NAN if x.nan?
397
+ return x if x.infinite?
398
+ return Decimal("0e#{-scale}") if x.zero?
399
+ e_x = exp(x, scale+1, :down)
400
+ inv_e_x = Decimal(1).divide(e_x, scale+1, :down)
401
+ (e_x - inv_e_x).divide(2, scale, rounding)
402
+ end
403
+
404
+ def cosh(x, scale, rounding=:down)
405
+ x = Decimal(x) if x.integer?
406
+ return Decimal::NAN if x.nan?
407
+ return Decimal::INFINITY if x.infinite?
408
+ if x.zero?
409
+ return scale > 0 ? Decimal(1) : Decimal("1e#{-scale}")
410
+ end
411
+ e_x = exp(x, scale+1, :down)
412
+ inv_e_x = Decimal(1).divide(e_x, scale+1, :down)
413
+ (e_x + inv_e_x).divide(2, scale, rounding)
414
+ end
415
+
416
+ def tanh(x, scale, rounding=:down)
417
+ x = Decimal(x) if x.integer?
418
+ return Decimal::NAN if x.nan?
419
+ return Decimal("0e#{-scale}") if x.zero?
420
+ if y = x.infinite?
421
+ return y
422
+ end
423
+ s, c = sinh(x, scale+1, :down), cosh(x, scale+1, :down)
424
+ s.divide(c, scale, rounding)
425
+ end
426
+
427
+ def asinh(x, scale, rounding=:down)
428
+ x = Decimal(x) if x.integer?
429
+ return Decimal::NAN if x.nan?
430
+ return Decimal("0e#{-scale}") if x.zero?
431
+ return x if x.infinite?
432
+ x2 = sqrt(x * x + 1, scale, :down)
433
+ log(x + x2, scale, rounding)
434
+ end
435
+
436
+ def acosh(x, scale, rounding=:down)
437
+ x = Decimal(x) if x.integer?
438
+ return Decimal::NAN if x.nan?
439
+ return Decimal("0e#{-scale}") if x == 1
440
+ raise Errno::EDOM if x < 1
441
+ return Decimal::INFINITY if x.infinite?
442
+ x2 = sqrt(x * x - 1, scale, :down)
443
+ log(x + x2, scale, rounding)
444
+ end
445
+
446
+ def atanh(x, scale, rounding=:down)
447
+ x = Decimal(x) if x.integer?
448
+ return Decimal::NAN if x.nan?
449
+ return Decimal("0e#{-scale}") if x.zero?
450
+ raise Errno::ERANGE if x == 1 or x == -1 # XXX
451
+ raise Errno::EDOM if x.abs > 1 # XXX
452
+ x2 = (1 + x).divide(1 - x, scale+1, :down)
453
+ y = Decimal("0.5") * log(x2, scale+1, :down)
454
+ y.round(scale, rounding)
455
+ end
456
+
457
+ def hypot(x, y, scale, rounding=:down)
458
+ x = Decimal(x) if x.integer?
459
+ y = Decimal(y) if y.integer?
460
+ return Decimal::INFINITY if x.infinite? or y.infinite?
461
+ return Decimal::NAN if x.nan? or y.nan?
462
+ sqrt(x * x + y * y, scale, rounding)
463
+ end
464
+
465
+ def erf(x, scale, rounding=:down)
466
+ x = Decimal(x) if x.integer?
467
+ return Decimal::NAN if x.nan?
468
+ if y = x.infinite?
469
+ return y
470
+ end
471
+ half = Decimal("0.5")
472
+ half_log_pi = half * log(pi(scale+1, :down), scale+1, :down)
473
+ x2 = (x * x).floor(scale+1)
474
+ y = if x >= 0
475
+ _decimal_internal_p_gamma(half, x2, half_log_pi, scale+1)
476
+ else
477
+ -_decimal_internal_p_gamma(half, x2, half_log_pi, scale+1)
478
+ end
479
+ y.round(scale, rounding)
480
+ end
481
+
482
+ def erfc(x, scale, rounding=:down)
483
+ x = Decimal(x) if x.integer?
484
+ return Decimal::NAN if x.nan?
485
+ if x.zero?
486
+ return scale > 0 ? Decimal("1."+"0"*scale) : Decimal(1)
487
+ end
488
+ if y = x.infinite?
489
+ if y > 0
490
+ return Decimal("0e#{-scale}")
491
+ else
492
+ return scale > 0 ? Decimal("2."+"0"*scale) : Decimal(2)
493
+ end
494
+ end
495
+ half = Decimal("0.5")
496
+ half_log_pi = half * log(pi(scale+1, :down), scale+1, :down)
497
+ x2 = (x * x).floor(scale+1)
498
+ y = if x >= 0
499
+ _decimal_internal_q_gamma(half, x2, half_log_pi, scale+1)
500
+ else
501
+ 1 + _decimal_internal_p_gamma(half, x2, half_log_pi, scale+1)
502
+ end
503
+ y.round(scale, rounding)
504
+ end
505
+
506
+ def gamma(x, scale, rounding=:down)
507
+ x = Decimal(x) if x.integer?
508
+ return Decimal::NAN if x.nan?
509
+ if inf = x.infinite?
510
+ return Decimal::INFINITY if inf > 0
511
+ raise Errno::EDOM # XXX
512
+ end
513
+ raise Errno::EDOM if x < 0 and x % 1 == 0 # XXX
514
+ raise Errno::ERANGE if x.zero? # XXX
515
+
516
+ if x < 0
517
+ pi_tmp = pi(scale+2, :down)
518
+ pi_x = (pi_tmp * x).floor(scale+2)
519
+ div1 = sin(pi_x, scale+2, :down)
520
+ div2 = exp(lgamma(1 - x, scale+2, :down)[0], scale+2, :down)
521
+ divisor = (div1 * div2).floor(scale+2)
522
+ return pi_tmp.divide(divisor, scale, rounding)
523
+ end
524
+ return Decimal(_decimal_internal_fact(x.to_i - 1)) if (x % 1).zero?
525
+ exp(lgamma(x, scale+2, :down)[0], scale, rounding)
526
+ end
527
+
528
+ def lgamma(x, scale, rounding=:down)
529
+ x = Decimal(x) if x.integer?
530
+ sign = 1
531
+ return [Decimal::NAN, sign] if x.nan?
532
+ return [Decimal("0e#{-scale}"), sign] if x == 1 or x == 2
533
+ if inf = x.infinite?
534
+ raise Errno::EDOM if inf < 0
535
+ return [Decimal::INFINITY, sign]
536
+ end
537
+
538
+ if (x % 1).zero?
539
+ raise Errno::ERANGE if x <= 0 # XXX
540
+ return [log(_decimal_internal_fact(x.to_i-1), scale, rounding), sign]
541
+ end
542
+ sign = -1 if x < 0 and x % 2 > 1
543
+ threshold = scale # XXX
544
+ v = 1
545
+ while x < threshold
546
+ v *= x
547
+ x += 1
548
+ end
549
+ half = Decimal("0.5")
550
+ y = (x - half) * log(x, scale+2, :down) - x +
551
+ half * log(2 * pi(scale+2, :down), scale+2, :down) -
552
+ log(v.abs, scale+2, :down)
553
+ n = 2
554
+ x2 = x * x
555
+ w = x
556
+ loop do
557
+ bn = _decimal_internal_bernoulli(n, scale+2)
558
+ term = bn.divide(n * (n - 1) * w, scale+2, :down)
559
+ break if term.zero?
560
+ y += term
561
+ n += 2
562
+ w *= x2
563
+ end
564
+ [y.round(scale, rounding), sign]
565
+ end
566
+ end