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/COPYING CHANGED
@@ -1,5 +1,5 @@
1
- Decimal is copyrighted free software by Tadashi Saito <shiba AT
2
- mail2.accsnet.ne.jp>.
1
+ Decimal is copyrighted free software by Tadashi Saito <tad.a.diggier[at]
2
+ gmail.com>.
3
3
  You can redistribute it and/or modify it under either the terms of the GPL
4
4
  version 2 (see the file GPL), or the conditions below:
5
5
 
data/INSTALL CHANGED
@@ -1,5 +1,4 @@
1
1
  $ ruby extconf.rb
2
2
  $ make
3
- $ su
4
- # make install
3
+ $ sudo make install
5
4
 
data/README CHANGED
@@ -1 +1,57 @@
1
- ALL YOUR DECIMAL BASE ARE BELONG TO US
1
+ = Decimal - multi-precision decimal arithmetic library
2
+
3
+ Decimal is (yet another) multi-precision decimal arithmetic library,
4
+ which aims to surpass BigDecimal. It provides simple, compact, fast,
5
+ precise, stable and easy-to-use solution.
6
+
7
+ == Webpages
8
+
9
+ * {Home}[http://decimal.rubyforge.org/]
10
+ * {Latest API Documents}[http://decimal.rubyforge.org/rdoc/]
11
+ * {Project Page at RubyForge}[http://rubyforge.org/projects/decimal/]
12
+ * {Mailing Lists}[http://rubyforge.org/mail/?group_id=1994]
13
+
14
+ == Requirements
15
+
16
+ Ruby 1.8.6 / 1.8.7 / 1.9.1 / 1.9.2dev (experimental)
17
+
18
+ == Install
19
+
20
+ With rubygems,
21
+
22
+ sudo gem install decimal
23
+
24
+ or to build by yourself,
25
+
26
+ ruby extconf.rb
27
+ make
28
+ sudo make install
29
+
30
+ Read INSTALL for less details.
31
+
32
+ == Examples
33
+
34
+ Use like Float with few exceptions including Decimal#divide.
35
+
36
+ require 'decimal'
37
+
38
+ N = 3 # larger N may take huge time and more inaccurate result
39
+ pi = 0
40
+ i = 0
41
+
42
+ loop do
43
+ term = (-1) ** i * Decimal(4).divide(2 * i + 1, N + 2, :down)
44
+ break if term.zero?
45
+ pi += term
46
+ i += 1
47
+ end
48
+
49
+ puts pi.round(N)
50
+
51
+ == License
52
+
53
+ Ruby's. See COPYING and GPL for more details.
54
+
55
+ == Author
56
+
57
+ {Tadashi Saito}[mailto:tad.a.digger(at)gmail.com]
data/README.1st ADDED
@@ -0,0 +1 @@
1
+ ALL YOUR DECIMAL BASE ARE BELONG TO US
data/TODO ADDED
@@ -0,0 +1,25 @@
1
+ * Preserve scale of zeros
2
+ * Implement "decimal/compat/bigdecimal", a bigdecimal-compatible layer
3
+ * Implement decimal ** otherdecimal, decimal ** -integer
4
+ (with Decimal#power(other, scale=decimal.scale, mode=Decimal::ROUND_XXX))
5
+ * Be a good friend with other Numeric classes (using Kernel.autoload?)
6
+ - OtherNumerics#to_decimal, Decimal#to_*
7
+ * Define `marshal_dump' and `marshal_load'
8
+
9
+ * Implement Decimal.pi / Decimal.e with a precise option
10
+ * Decimal#format_s based on format of Excel
11
+ * Embedded decimal32/64 (that size equals to pointer's)
12
+ * GMP support with "--with-gmp" and inumgmp.h
13
+ * Static value for well-used value like 0, 1 or 10 ?
14
+
15
+ done:
16
+ - Implement Math functions
17
+ - Implement webpages
18
+ - Support RubyGems
19
+ - Support Ruby 1.9
20
+ - Implement NaN/+-Infinity as a singleton object
21
+ - Write tests
22
+ - Write RDocs
23
+ - Implement decimal ** fixnum
24
+ - Create .document
25
+
data/decimal.c CHANGED
@@ -2,40 +2,39 @@
2
2
  * decimal.c - implementation of Decimal,
3
3
  * a multi-precision decimal arithmetic library
4
4
  *
5
- * Copyright (C) 2003-2008 Tadashi Saito
5
+ * Copyright (C) 2003-2010 Tadashi Saito
6
6
  *
7
- * This program is free software; you can
8
- * 0. use this program for any purpose.
9
- * 1. study how the program works, and adapt it to your needs.
10
- * 2. redistribute copies so you can help your neighbor.
11
- * 3. improve the program, and release your improvements
12
- * to the public, so that the whole community benefits.
13
- * with the accessibility to the source code.
14
- *
15
- * This program is licensed under the terms of the Ruby License.
16
- * See the file "COPYING" for more details.
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of the Ruby License. See the file "COPYING" for
9
+ * more details.
17
10
  */
18
11
 
19
12
  #include <ctype.h>
20
13
  #include <float.h>
14
+ #define _ISOC99_SOURCE
21
15
  #include <math.h>
22
16
  #include <stdio.h>
23
17
  #include <string.h>
24
18
 
25
19
  #include <ruby.h>
26
- #include <rubysig.h>
27
- #include <version.h>
20
+ #ifdef HAVE_RUBY_UTIL_H
21
+ #include <ruby/util.h>
22
+ #else
28
23
  #include <util.h>
24
+ #endif
25
+
26
+ /* we need support both of 1.8/1.9 with the same source! */
27
+ #include "ruby18compat.h"
29
28
 
30
29
  /*
31
- * unfortunately, a few copies of Integer functions
30
+ * unfortunately, few copies of Integer functions
32
31
  * are needed from original Ruby
33
32
  */
34
- #include "inum18.h"
33
+ #include INUM_SOURCE_FILE
35
34
 
36
35
  /*
37
36
  * INUM_* macros: receive both Fixnum and Bignum,
38
- * to operate Integers transparently
37
+ * to operate any types of Integers transparently
39
38
  */
40
39
  #define INUM_PLUS(a, b) \
41
40
  (FIXNUM_P(a) ? fix_plus(a, b) : rb_big_plus(a, b))
@@ -44,27 +43,32 @@
44
43
  #define INUM_MUL(a, b) \
45
44
  (FIXNUM_P(a) ? fix_mul(a, b) : rb_big_mul(a, b))
46
45
  #define INUM_DIV(a, b) \
47
- (FIXNUM_P(a) ? fix_div(a, b) : RARRAY(rb_big_divmod(a, b))->ptr[0])
46
+ (FIXNUM_P(a) ? fix_div(a, b) : rb_big_div(a, b))
48
47
  #define INUM_DIVMOD(a, b) \
49
48
  (FIXNUM_P(a) ? fix_divmod(a, b) : rb_big_divmod(a, b))
49
+ #define INUM_POW(a, b) \
50
+ (FIXNUM_P(a) ? fix_pow(a, b) : rb_big_pow(a, b))
50
51
  #define INUM_EQ(a, b) \
51
52
  (FIXNUM_P(a) ? fix_equal(a, b) : rb_big_eq(a, b))
52
53
  #define INUM_CMP(a, b) \
53
54
  (FIXNUM_P(a) ? fix_cmp(a, b) : rb_big_cmp(a, b))
55
+ #define INUM_GT(a, b) (FIX2INT(INUM_CMP(a, b)) > 0)
54
56
  #define INUM_UMINUS(n) \
55
- (FIXNUM_P(n) ? LONG2NUM(-FIX2LONG(n)) : big_uminus(n))
57
+ (FIXNUM_P(n) ? LONG2NUM(-FIX2LONG(n)) : rb_big_uminus(n))
56
58
  #define INUM_HASH(n) \
57
- (FIXNUM_P(n) ? LONG2NUM((long)n) : rb_big_hash(n))
59
+ (FIXNUM_P(n) ? rb_obj_id(n) : rb_big_hash(n))
58
60
  #define INUM2STR(n) \
59
61
  (FIXNUM_P(n) ? rb_fix2str(n, 10) : rb_big2str(n, 10))
62
+ #define INUM_ODD_P(n) \
63
+ (FIXNUM_P(n) ? fix_odd_p(n) : rb_big_odd_p(n))
60
64
 
65
+ /* implementation-independent INUM_* macros */
61
66
  #define INUM_INC(n) do { n = INUM_PLUS(n, INT2FIX(1)); } while (0)
62
67
  #define INUM_DEC(n) do { n = INUM_MINUS(n, INT2FIX(1)); } while (0)
63
68
  #define INUM_ZERO_P(n) (FIXNUM_P(n) && FIX2LONG(n) == 0)
64
- #define INUM_NEGATIVE_P(n) (FIXNUM_P(n) ? FIX2LONG(n) < 0 : !RBIGNUM(n)->sign)
69
+ #define INUM_NEGATIVE_P(n) (FIXNUM_P(n) ? FIX2LONG(n) < 0 : RBIGNUM_NEGATIVE_P(n))
65
70
  #define INUM_BOTTOMDIG(n) (FIXNUM_P(n) ? FIX2LONG(n) % 10 : \
66
- RBIGNUM(n)->len ? FIX2INT(RARRAY(rb_big_divmod(n, INT2FIX(10)))->ptr[1]) : 0)
67
- #define INUM_ODD_P(n) (FIXNUM_P(n) ? n & 2 : BDIGITS(n)[0] & 1)
71
+ !rb_bigzero_p(n) ? FIX2INT(rb_big_modulo(n, INT2FIX(10))) : 0)
68
72
 
69
73
  /* the body */
70
74
  typedef struct {
@@ -76,23 +80,43 @@ typedef struct {
76
80
  static Decimal *const DEC_NaN = (Decimal *)1;
77
81
  static Decimal *const DEC_PINF = (Decimal *)3;
78
82
  static Decimal *const DEC_NINF = (Decimal *)7;
79
- /* and their representation as Ruby object */
83
+ /* and their representation as Ruby objects */
80
84
  static VALUE VALUE_NaN, VALUE_PINF, VALUE_NINF;
81
85
 
82
- /* special constants - i.e. non-zero and non-fixnum constants */
86
+ #define CHECK_NAN_WITH_VAL(v, retval) do { \
87
+ if (v == VALUE_NaN) return retval; } while (0)
88
+ #define CHECK_NAN2_WITH_VAL(v1, v2, retval) do { \
89
+ if (v1 == VALUE_NaN || v2 == VALUE_NaN) return retval; } while (0)
90
+ #define CHECK_NAN(v) CHECK_NAN_WITH_VAL(v, VALUE_NaN)
91
+ #define CHECK_NAN2(v1, v2) CHECK_NAN2_WITH_VAL(v1, v2, VALUE_NaN)
92
+
93
+ /* special constants - i.e. non-zero and non-fixnum */
83
94
  /* used for signed zeros that never meet any fixnums nor normal VALUEs */
84
95
  static const VALUE DEC_PZERO = 2, DEC_NZERO = 6;
85
- #define dec_pzero() WrapDecimal(inum_to_dec(DEC_PZERO))
86
- #define dec_nzero() WrapDecimal(inum_to_dec(DEC_NZERO))
96
+ #define dec_pzero(scale) WrapDecimal(dec_raw_new(DEC_PZERO, scale))
97
+ #define dec_nzero(scale) WrapDecimal(dec_raw_new(DEC_NZERO, scale))
87
98
 
88
99
  #define DEC_ISINF(d) ((d) == DEC_PINF || (d) == DEC_NINF)
100
+ #define DEC_VALUE_ISINF(v) ((v) == VALUE_PINF || (v) == VALUE_NINF)
89
101
  /* immediate means non-finite */
90
- #define DEC_IMMEDIATE_P(d) (DEC_ISINF(d) || d == DEC_NaN)
102
+ #define DEC_IMMEDIATE_P(d) (DEC_ISINF(d) || (d) == DEC_NaN)
91
103
  /* special signed zeros */
92
- #define DEC_ZERO_P(d) ((d)->inum == DEC_PZERO || (d)->inum == DEC_NZERO)
93
104
  #define INUM_SPZERO_P(n) ((n) == DEC_PZERO || (n) == DEC_NZERO)
105
+ #define DEC_ZERO_P(d) INUM_SPZERO_P((d)->inum)
106
+
107
+ /* use internally in to_f */
108
+ static Decimal *DEC_DBL_MIN = NULL, *DEC_DBL_MAX = NULL;
109
+ static VALUE INUM_DBL_MAX = Qnil;
110
+ #define GET_DEC_DBL_MAX() (DEC_DBL_MAX != NULL ? DEC_DBL_MAX : \
111
+ (DEC_DBL_MAX = dbl_threshold_to_dec(DBL_MAX)))
112
+ #define GET_DEC_DBL_MIN() (DEC_DBL_MIN != NULL ? DEC_DBL_MIN : \
113
+ (DEC_DBL_MIN = dbl_threshold_to_dec(DBL_MIN)))
114
+ #define GET_INUM_DBL_MAX() (INUM_DBL_MAX != Qnil ? INUM_DBL_MAX : \
115
+ dbl_threshold_to_inum(DBL_MAX, &INUM_DBL_MAX))
94
116
 
95
- /* all rounding modes, corresponding to DEF_ROUNDING_MODE() */
117
+ /*
118
+ * all rounding modes
119
+ */
96
120
  static VALUE ROUND_CEILING;
97
121
  static VALUE ROUND_DOWN;
98
122
  static VALUE ROUND_FLOOR;
@@ -106,17 +130,15 @@ static VALUE ROUND_UNNECESSARY;
106
130
  Data_Get_Struct(obj, Decimal, d); \
107
131
  if (d == NULL) rb_raise(rb_eArgError, "uninitialized Decimal object"); \
108
132
  } while (0)
109
- #define WrapDecimal(d) \
110
- Data_Wrap_Struct(cDecimal, dec_mark, dec_free, d)
111
- #define WrapImmediate(d) \
112
- Data_Wrap_Struct(cDecimal, NULL, NULL, d)
133
+ #define WrapDecimal(d) Data_Wrap_Struct(cDecimal, dec_mark, dec_free, d)
134
+ #define WrapStatic(d) Data_Wrap_Struct(cDecimal, NULL, NULL, d)
113
135
  #define DECIMAL_P(d) (CLASS_OF(d) == cDecimal)
114
136
 
115
137
  static VALUE cDecimal;
116
138
  static VALUE eDomainError;
117
139
  static VALUE eArithmeticError;
118
140
 
119
- /* mark if d->inum is Bignum */
141
+ /* mark if d->inum is a Bignum */
120
142
  static void
121
143
  dec_mark(void *p)
122
144
  {
@@ -124,7 +146,7 @@ dec_mark(void *p)
124
146
 
125
147
  if (d == NULL) return; /* uninitialized object */
126
148
  if (!FIXNUM_P(d->inum) && !INUM_SPZERO_P(d->inum)) {
127
- rb_gc_mark(d->inum); /* mark a Bignum */
149
+ rb_gc_mark(d->inum); /* mark a Bignum */
128
150
  }
129
151
  }
130
152
 
@@ -144,18 +166,22 @@ dec_free(void *p)
144
166
  }
145
167
  #endif
146
168
 
147
- static Decimal *
148
- inum_to_dec(VALUE x)
169
+ static inline Decimal *
170
+ dec_raw_new(VALUE inum, long scale)
149
171
  {
150
172
  Decimal *d = ALLOC(Decimal);
151
173
 
152
- d = ALLOC(Decimal);
153
- if (INUM_ZERO_P(x)) d->inum = DEC_PZERO;
154
- else d->inum = x;
155
- d->scale = 0;
174
+ d->inum = inum;
175
+ d->scale = scale;
156
176
  return d;
157
177
  }
158
178
 
179
+ static Decimal *
180
+ inum_to_dec(VALUE x)
181
+ {
182
+ return dec_raw_new(INUM_ZERO_P(x) ? DEC_PZERO : x, 0);
183
+ }
184
+
159
185
  static VALUE
160
186
  cstr_to_inum(VALUE str)
161
187
  {
@@ -175,59 +201,46 @@ invalid_str(VALUE arg)
175
201
  static Decimal *
176
202
  cstr_to_dec(const char *str)
177
203
  {
178
- Decimal *d;
179
204
  char *const s = strdup(str);
180
- char *ss, *ss2;
205
+ char *ss;
181
206
  long scale = 0;
182
207
  VALUE inum, assoc[2];
183
208
 
184
209
  assoc[0] = (VALUE)s;
185
210
  assoc[1] = (VALUE)str;
186
- if (ss = strpbrk(s, "be")) {
187
- *ss++ = '\0'; /* for strchr() */
188
- inum = rb_rescue(cstr_to_inum, (VALUE)ss, invalid_str, (VALUE)assoc);
189
- scale -= NUM2LONG(inum);
211
+ if (ss = strpbrk(s, "Ee")) {
212
+ *ss++ = '\0'; /* for strchr() */
213
+ inum = rb_rescue(cstr_to_inum, (VALUE)ss, invalid_str, (VALUE)assoc);
214
+ scale -= NUM2LONG(inum);
190
215
  }
191
216
  if (ss = strchr(s, '.')) {
192
- const char *p;
217
+ const char *p;
193
218
 
194
- #if RUBY_RELEASE_CODE == 20070924 /* bug workaround for 1.8.6-p111 */
195
- if (ss == s || ss[-1] != '0') goto out;
196
- ss2 = ss;
197
- do {
198
- ss2--;
199
- } while (*ss2 == '0' && ss2 > s);
200
- if (*ss2 == '0' || *ss2 == '-' || *ss2 == '+' || ISSPACE(*ss2))
201
- *ss = '0';
202
- else
203
- out:
204
- #endif
205
- *ss = '_'; /* so that rb_cstr_to_inum() can ignore '.' */
206
- for (p = ss + 1; ISDIGIT(*p) || *p == '_'; p++) {
207
- if (ISDIGIT(*p)) scale++;
208
- }
219
+ *ss = '_'; /* so that rb_cstr_to_inum() can ignore '.' */
220
+ for (p = ss + 1; ISDIGIT(*p) || *p == '_'; p++) {
221
+ if (ISDIGIT(*p)) scale++;
222
+ }
209
223
  }
210
224
  inum = rb_rescue(cstr_to_inum, (VALUE)s, invalid_str, (VALUE)assoc);
211
- d = ALLOC(Decimal);
212
225
  if (INUM_ZERO_P(inum)) {
213
- d->inum = strchr(s, '-') ? DEC_NZERO : DEC_PZERO;
226
+ inum = strchr(s, '-') ? DEC_NZERO : DEC_PZERO;
214
227
  }
215
- else d->inum = inum;
216
- d->scale = scale;
217
228
  xfree(s);
218
- return d;
229
+ return dec_raw_new(inum, scale);
219
230
  }
220
231
 
221
232
  static Decimal *
222
- finite_dup(Decimal *d)
233
+ finite_dup(const Decimal *d)
223
234
  {
224
- Decimal *d2 = ALLOC(Decimal);
235
+ VALUE inum;
225
236
 
226
- *d2 = *d;
227
- if (!FIXNUM_P(d->inum) && !INUM_SPZERO_P(d->inum)) {
228
- d2->inum = rb_big_clone(d->inum); /* inum is a Bignum */
237
+ if (FIXNUM_P(d->inum) || INUM_SPZERO_P(d->inum)) {
238
+ inum = d->inum;
229
239
  }
230
- return d2;
240
+ else {
241
+ inum = rb_big_clone(d->inum); /* inum is a Bignum */
242
+ }
243
+ return dec_raw_new(inum, d->scale);
231
244
  }
232
245
 
233
246
  static Decimal *
@@ -236,80 +249,105 @@ create_dec(VALUE arg)
236
249
  switch (TYPE(arg)) {
237
250
  case T_FIXNUM:
238
251
  case T_BIGNUM:
239
- return inum_to_dec(arg);
252
+ return inum_to_dec(arg);
240
253
  case T_STRING:
241
- return cstr_to_dec(StringValueCStr(arg));
242
- case T_DATA:
243
- if (DECIMAL_P(arg)) {
244
- Decimal *d;
245
-
246
- GetDecimal(arg, d);
247
- if (DEC_IMMEDIATE_P(d))
248
- return d;
249
- return finite_dup(d);
250
- }
251
- /* fall through */
254
+ return cstr_to_dec(StringValueCStr(arg));
252
255
  case T_FLOAT:
253
- rb_raise(rb_eArgError, "invalid value Float(%s) for Decimal",
254
- RSTRING(rb_inspect(arg))->ptr);
256
+ rb_raise(rb_eArgError, "invalid type Float: %s",
257
+ RSTRING_PTR(rb_inspect(arg)));
255
258
  default:
256
- rb_raise(rb_eArgError, "invalid value for Decimal: %s",
257
- RSTRING(rb_inspect(arg))->ptr);
259
+ rb_raise(rb_eArgError, "invalid value for Decimal: %s",
260
+ RSTRING_PTR(rb_inspect(arg)));
258
261
  }
259
262
  return NULL; /* not reached */
260
263
  }
261
264
 
262
- static VALUE
263
- f_decimal(VALUE klass_unused, VALUE arg)
264
- {
265
- if (DECIMAL_P(arg)) return arg;
266
- return WrapDecimal(create_dec(arg));
267
- }
268
-
269
- /* TODO: should know about allocation framework */
265
+ /* TODO: should know about allocation framework for dumping/loading */
270
266
  static VALUE
271
267
  dec_s_allocate(VALUE klass)
272
268
  {
273
269
  return Data_Wrap_Struct(klass, dec_mark, dec_free, NULL);
274
270
  }
275
271
 
276
- /* TODO: check whether arg is a Decimal or not */
272
+ /*
273
+ * call-seq:
274
+ * Decimal.new(arg) => decimal
275
+ *
276
+ * Returns a new decimal made from _arg_. The _arg_ must be an +Integer+
277
+ * or a +String+. An acceptable format of +String+ is equal to
278
+ * <code>Kernel.Float()</code>'s one. In a +Regexp+, it should be:
279
+ *
280
+ * digits = /(\d+_)*\d+/
281
+ * number = /(\+-)?#{digits}/
282
+ * body = /#{number}(\.#{digits})?([eE]#{number})?/
283
+ * decimal = /\A\s*#{body}\s*\z/
284
+ *
285
+ * And its samples are:
286
+ *
287
+ * Decimal(1) #=> Decimal(1)
288
+ * Decimal(2**64) #=> Decimal(18446744073709551616)
289
+ * Decimal("1") #=> Decimal(1)
290
+ * Decimal("1.1") #=> Decimal(1.1)
291
+ * Decimal("1e10") #=> Decimal(10000000000)
292
+ * Decimal("299_792_458") #=> Decimal(299792458)
293
+ * Decimal("2.99_792_458e8") #=> Decimal(299792458)
294
+ *
295
+ * Notice that a +Float+ is *not* acceptable for _arg_ to keep exactness.
296
+ *
297
+ * Decimal.new(1.1) #=> (ArgumentError)
298
+ */
277
299
  static VALUE
278
300
  dec_initialize(VALUE self, VALUE arg)
279
301
  {
280
- Decimal *d = create_dec(arg);
281
-
282
- if (DEC_IMMEDIATE_P(d)) { /* no need to manage about memory */
283
- RDATA(self)->dmark = RDATA(self)->dmark = NULL;
302
+ if (DECIMAL_P(arg)) {
303
+ return arg;
284
304
  }
285
- DATA_PTR(self) = d;
305
+ DATA_PTR(self) = create_dec(arg);
286
306
  return self;
287
307
  }
288
308
 
309
+ #ifdef __GNUC__
310
+ #define UNUSED __attribute__((unused))
311
+ #else
312
+ #define UNUSED /* nothing */
313
+ #endif
314
+ /*
315
+ * call-seq:
316
+ * Decimal(arg) => decimal
317
+ *
318
+ * Identical to <code>Decimal.new(arg)</code>, except that this method
319
+ * never be affected from overriding <code>Decimal#initialize</code>.
320
+ */
321
+ static VALUE
322
+ f_decimal(VALUE klass UNUSED, VALUE arg)
323
+ {
324
+ return dec_initialize(dec_s_allocate(cDecimal), arg);
325
+ }
326
+
289
327
  #ifdef DEBUG
328
+ /* :nodoc: */
290
329
  static VALUE
291
330
  dec_scale(VALUE self)
292
331
  {
293
332
  Decimal *d;
294
333
 
295
- GetDecimal(self, d);
296
- if (!DEC_IMMEDIATE_P(d)) return LONG2NUM(d->scale);
297
- return Qnil;
334
+ GetDecimal(self, d);
335
+ if (DEC_IMMEDIATE_P(d)) return Qnil;
336
+ return LONG2NUM(d->scale);
298
337
  }
299
338
 
339
+ /* :nodoc: */
300
340
  static VALUE
301
341
  dec_unscaled_value(VALUE self)
302
342
  {
303
343
  Decimal *d;
304
344
 
305
345
  GetDecimal(self, d);
306
- if (!DEC_IMMEDIATE_P(d)) {
307
- return INUM_SPZERO_P(d->inum) ? INT2FIX(0) : d->inum;
308
- }
309
- return Qnil;
346
+ if (DEC_IMMEDIATE_P(d)) return Qnil;
347
+ return DEC_ZERO_P(d) ? INT2FIX(0) : d->inum;
310
348
  }
311
- #endif
312
349
 
350
+ /* :nodoc: */
313
351
  static VALUE
314
352
  dec_strip_trailing_zeros(VALUE self)
315
353
  {
@@ -318,14 +356,13 @@ dec_strip_trailing_zeros(VALUE self)
318
356
  GetDecimal(self, d);
319
357
  if (DEC_IMMEDIATE_P(d))
320
358
  return self;
321
- if (INUM_SPZERO_P(d->inum)) { /* XXX: negative scale? */
359
+ if (DEC_ZERO_P(d)) { /* XXX: negative scale? */
322
360
  if (d->scale <= 0) return self;
323
361
  d2 = finite_dup(d);
324
- d2->scale = 0;
362
+ d2->scale = 0;
325
363
  return WrapDecimal(d2);
326
364
  }
327
- d2 = ALLOC(Decimal);
328
- *d2 = *d;
365
+ d2 = finite_dup(d);
329
366
  /* TODO: can be optimized with dividing each part
330
367
  * for Bignums and Fixnums */
331
368
  while (INUM_BOTTOMDIG(d2->inum) == 0) {
@@ -334,14 +371,15 @@ dec_strip_trailing_zeros(VALUE self)
334
371
  }
335
372
  return WrapDecimal(d2);
336
373
  }
374
+ #endif /* DEBUG */
337
375
 
338
376
  /* FIXME: should return "%g" format string */
339
377
  static VALUE
340
- finite_to_s(Decimal *d)
378
+ finite_to_s(const Decimal *d)
341
379
  {
342
380
  const VALUE str = INUM2STR(d->inum);
343
- const char *s = RSTRING(str)->ptr;
344
- const long slen = RSTRING(str)->len;
381
+ const char *s = RSTRING_PTR(str);
382
+ const long slen = RSTRING_LEN(str);
345
383
  const long scale = d->scale;
346
384
  long snumlen, sslen, diff;
347
385
  int negative;
@@ -380,25 +418,62 @@ finite_to_s(Decimal *d)
380
418
  memcpy(ss2+diff, s, snumlen);
381
419
  }
382
420
  coda:
383
- newstr = rb_str_new(ss, sslen);
421
+ newstr = rb_usascii_str_new(ss, sslen);
384
422
  xfree(ss);
385
423
  return newstr;
386
424
  }
387
425
 
426
+ /*
427
+ * call-seq:
428
+ * dec.to_s => string
429
+ *
430
+ * *WARNING*: The behavior of this method may change.
431
+ *
432
+ * Returns a string containing a simple representation of self.
433
+ *
434
+ * Decimal(1).to_s #=> "1"
435
+ * Decimal("1.1").to_s #=> "1.1"
436
+ * Decimal::INFINITY.to_s #=> "Infinity"
437
+ */
388
438
  static VALUE
389
439
  dec_to_s(VALUE self)
390
440
  {
391
441
  Decimal *d;
392
442
 
443
+ CHECK_NAN_WITH_VAL(self, rb_usascii_str_new_cstr("NaN"));
444
+ if (self == VALUE_PINF) return rb_usascii_str_new_cstr("Infinity");
445
+ if (self == VALUE_NINF) return rb_usascii_str_new_cstr("-Infinity");
393
446
  GetDecimal(self, d);
394
- if (d == DEC_NaN) return rb_str_new2("NaN");
395
- if (d == DEC_PINF) return rb_str_new2("Infinity");
396
- if (d == DEC_NINF) return rb_str_new2("-Infinity");
397
- if (d->inum == DEC_PZERO) return rb_str_new2("0");
398
- if (d->inum == DEC_NZERO) return rb_str_new2("-0");
447
+ if (DEC_ZERO_P(d)) {
448
+ const size_t HEAD_LEN = d->inum == DEC_PZERO ? 2U : 3U; /* "-0.".length */
449
+ long len = HEAD_LEN + d->scale;
450
+ char *buf;
451
+
452
+ /* FIXME: use "0eN" style when the scale is negative? */
453
+ if (d->scale <= 0) /* ignore the case of negative scale */
454
+ return d->inum == DEC_PZERO ?
455
+ rb_usascii_str_new_cstr("0") : rb_usascii_str_new_cstr("-0");
456
+ buf = xmalloc(len);
457
+ if (d->inum == DEC_PZERO)
458
+ memcpy(buf, "0.", HEAD_LEN);
459
+ else
460
+ memcpy(buf, "-0.", HEAD_LEN);
461
+ memset(buf + HEAD_LEN, '0', d->scale);
462
+ return rb_usascii_str_new(buf, len);
463
+ }
399
464
  return finite_to_s(d);
400
465
  }
401
466
 
467
+ /*
468
+ * call-seq:
469
+ * dec.inspect => string
470
+ *
471
+ * Returns a easy-to-distinguish string: <code>"Decimal(#{dec})"</code>.
472
+ *
473
+ * Decimal(1).inspect #=> "Decimal(1)"
474
+ * Decimal("1.1").inspect #=> "Decimal(1.1)"
475
+ * Decimal::INFINITY.inspect #=> "Decimal(Infinity)"
476
+ */
402
477
  static VALUE
403
478
  dec_inspect(VALUE self)
404
479
  {
@@ -407,14 +482,26 @@ dec_inspect(VALUE self)
407
482
  long len;
408
483
 
409
484
  str = dec_to_s(self);
410
- len = 9 + RSTRING(str)->len; /* 9 == strlen("Decimal()") */
485
+ len = 9 + RSTRING_LEN(str); /* 9 == strlen("Decimal()") */
411
486
  s = ALLOC_N(char, len + 1); /* +1 for NUL */
412
- sprintf(s, "Decimal(%s)", RSTRING(str)->ptr);
413
- newstr = rb_str_new(s, len);
487
+ sprintf(s, "Decimal(%s)", RSTRING_PTR(str));
488
+ newstr = rb_usascii_str_new(s, len);
414
489
  xfree(s);
415
490
  return newstr;
416
491
  }
417
492
 
493
+ /*
494
+ * call-seq:
495
+ * dec.coerce(other) => array
496
+ *
497
+ * Returns array <code>[Decimal(other), dec]</code> if _other_ has a
498
+ * compatible type, +Integer+ or +Decimal+.
499
+ * Otherwise raises a +TypeError+.
500
+ *
501
+ * Decimal(1).coerce(2) #=> [Decimal(2), Decimal(1)]
502
+ * Decimal(1).coerce(Decimal(2)) #=> [Decimal(2), Decimal(1)]
503
+ * Decimal(1).coerce(2.5) #=> (TypeError)
504
+ */
418
505
  static VALUE
419
506
  dec_coerce(VALUE x, VALUE y)
420
507
  {
@@ -440,25 +527,30 @@ dec_coerce(VALUE x, VALUE y)
440
527
  return Qnil; /* not reached */
441
528
  }
442
529
 
530
+ /*
531
+ * call-seq:
532
+ * -dec => decimal
533
+ *
534
+ * Returns a negated value of _dec_.
535
+ */
443
536
  static VALUE
444
537
  dec_uminus(VALUE num)
445
538
  {
446
- Decimal *d, *d2;
539
+ VALUE inum;
540
+ Decimal *d;
447
541
 
448
- GetDecimal(num, d);
449
- if (d == DEC_NaN) return num;
450
- if (d == DEC_PINF) return VALUE_NINF;
451
- if (d == DEC_NINF) return VALUE_PINF;
542
+ CHECK_NAN(num);
543
+ if (num == VALUE_PINF) return VALUE_NINF;
544
+ if (num == VALUE_NINF) return VALUE_PINF;
452
545
 
453
- d2 = ALLOC(Decimal);
454
- d2->scale = d->scale;
546
+ GetDecimal(num, d);
455
547
  if (d->inum == DEC_PZERO)
456
- d2->inum = DEC_NZERO;
548
+ inum = DEC_NZERO;
457
549
  else if (d->inum == DEC_NZERO)
458
- d2->inum = DEC_PZERO;
550
+ inum = DEC_PZERO;
459
551
  else
460
- d2->inum = INUM_UMINUS(d->inum);
461
- return WrapDecimal(d2);
552
+ inum = INUM_UMINUS(d->inum);
553
+ return WrapDecimal(dec_raw_new(inum, d->scale));
462
554
  }
463
555
 
464
556
  /* returns x * (10 ** n) */
@@ -472,11 +564,10 @@ inum_lshift(VALUE x, long n)
472
564
  return INUM_MUL(x, y);
473
565
  }
474
566
 
475
- /* the "normal" number means "finite and nonzero." */
567
+ /* the "normal" number means "finite and non-zero" */
476
568
  static Decimal *
477
- normal_plus(Decimal *x, Decimal *y, const int add)
569
+ normal_plus(const Decimal *x, const Decimal *y, const int add)
478
570
  {
479
- Decimal *z;
480
571
  VALUE inum;
481
572
  long scale;
482
573
 
@@ -486,29 +577,34 @@ normal_plus(Decimal *x, Decimal *y, const int add)
486
577
  scale = x->scale;
487
578
  }
488
579
  else {
489
- Decimal *max, *min;
580
+ const Decimal *max, *min;
490
581
  VALUE min_inum;
491
582
 
492
583
  if (x->scale > y->scale) max = x, min = y;
493
584
  else max = y, min = x;
494
585
  scale = max->scale;
495
586
  min_inum = inum_lshift(min->inum, max->scale - min->scale);
496
- if (add) inum = INUM_PLUS(min_inum, max->inum); /* ? + ? */
497
- else if (max == x) inum = INUM_MINUS(max->inum, min_inum); /* x - y */
498
- else inum = INUM_MINUS(min_inum, max->inum); /* y - x */
587
+ if (add) inum = INUM_PLUS(min_inum, max->inum);
588
+ else if (max == x) inum = INUM_MINUS(max->inum, min_inum);
589
+ else inum = INUM_MINUS(min_inum, max->inum);
499
590
  }
500
591
  if (INUM_ZERO_P(inum)) inum = DEC_PZERO;
501
- z = ALLOC(Decimal);
502
- z->inum = inum;
503
- z->scale = scale;
504
- return z;
592
+ return dec_raw_new(inum, scale);
505
593
  }
506
594
 
595
+ #define MAX(x, y) ((x) > (y) ? (x) : (y))
596
+ /*
597
+ * call-seq:
598
+ * dec + other => decimal
599
+ *
600
+ * Returns a new decimal which is the sum of _dec_ and _other_.
601
+ */
507
602
  static VALUE
508
603
  dec_plus(VALUE x, VALUE y)
509
604
  {
510
605
  Decimal *a, *b;
511
606
 
607
+ CHECK_NAN2(x, y);
512
608
  switch (TYPE(y)) {
513
609
  case T_FIXNUM:
514
610
  case T_BIGNUM:
@@ -520,40 +616,60 @@ dec_plus(VALUE x, VALUE y)
520
616
  case T_DATA:
521
617
  if (DECIMAL_P(y)) {
522
618
  GetDecimal(y, b);
523
- if (b == DEC_NaN) return VALUE_NaN;
524
619
  break;
525
620
  }
526
621
  /* fall through */
527
622
  default:
528
- return rb_num_coerce_bin(x, y);
623
+ return rb_num_coerce_bin(x, y, '+');
529
624
  }
530
- GetDecimal(x, a);
531
- if (a == DEC_NaN) return VALUE_NaN;
532
-
533
- /* now, x and y are not NaNs */
534
- if (DEC_ISINF(a)) {
535
- if (DEC_ISINF(b) && a != b) return VALUE_NaN;
625
+
626
+ if (DEC_VALUE_ISINF(x)) {
627
+ if (DEC_VALUE_ISINF(y) && x != y) return VALUE_NaN;
536
628
  return x;
537
629
  }
538
- if (INUM_SPZERO_P(a->inum)) {
539
- if (!DEC_IMMEDIATE_P(b) && DEC_ZERO_P(b)) { /* XXX */
630
+ if (DEC_VALUE_ISINF(y)) return y;
631
+ /* now, x and y are not NaN nor +-INFINITY */
632
+ GetDecimal(x, a);
633
+ if (DEC_ZERO_P(a)) {
634
+ VALUE inum;
635
+
636
+ if (DEC_ZERO_P(b)) {
637
+ const long scale = MAX(a->scale, b->scale);
638
+
540
639
  if (a->inum == DEC_NZERO && b->inum == DEC_NZERO)
541
- return dec_nzero(); /* FIXME: scale policy for 0? */
542
- return dec_pzero(); /* FIXME: ditto */
640
+ return dec_nzero(scale);
641
+ return dec_pzero(scale);
543
642
  }
544
- return y;
643
+ if (a->scale <= b->scale)
644
+ return y;
645
+ inum = inum_lshift(b->inum, a->scale - b->scale);
646
+ return WrapDecimal(dec_raw_new(inum, a->scale));
647
+ }
648
+ if (DEC_ZERO_P(b)) {
649
+ VALUE inum;
650
+
651
+ if (a->scale >= b->scale)
652
+ return x;
653
+ inum = inum_lshift(a->inum, b->scale - a->scale);
654
+ return WrapDecimal(dec_raw_new(inum, b->scale));
545
655
  }
546
- if (DEC_ISINF(b)) return y;
547
- if (INUM_SPZERO_P(b->inum)) return x; /* FIXME: ditto */
548
656
  /* "true" means addition */
549
657
  return WrapDecimal(normal_plus(a, b, Qtrue));
550
658
  }
551
659
 
660
+ #define NEGATE_INF(x) ((x) == VALUE_PINF ? VALUE_NINF : VALUE_PINF)
661
+ /*
662
+ * call-seq:
663
+ * dec - other => decimal
664
+ *
665
+ * Returns a new float which is the difference of _dec_ and _other_.
666
+ */
552
667
  static VALUE
553
668
  dec_minus(VALUE x, VALUE y)
554
669
  {
555
670
  Decimal *a, *b;
556
671
 
672
+ CHECK_NAN2(x, y);
557
673
  switch (TYPE(y)) {
558
674
  case T_FIXNUM:
559
675
  case T_BIGNUM:
@@ -565,47 +681,49 @@ dec_minus(VALUE x, VALUE y)
565
681
  case T_DATA:
566
682
  if (DECIMAL_P(y)) {
567
683
  GetDecimal(y, b);
568
- if (b == DEC_NaN) return VALUE_NaN;
569
684
  break;
570
685
  }
571
686
  /* fall through */
572
687
  default:
573
- return rb_num_coerce_bin(x, y);
688
+ return rb_num_coerce_bin(x, y, '-');
574
689
  }
575
- GetDecimal(x, a);
576
- if (a == DEC_NaN) return VALUE_NaN;
577
-
578
- if (DEC_ISINF(a)) {
579
- if (a == b) return VALUE_NaN;
690
+ if (DEC_VALUE_ISINF(x)) {
691
+ if (x == y) return VALUE_NaN;
580
692
  return x;
581
693
  }
582
- if (INUM_SPZERO_P(a->inum)) { /* FIXME: need to refactor */
694
+ if (DEC_VALUE_ISINF(y)) return NEGATE_INF(y);
695
+
696
+ GetDecimal(x, a);
697
+ if (DEC_ZERO_P(a)) { /* FIXME: needs refactoring */
583
698
  if (!DEC_ISINF(b) && DEC_ZERO_P(b) && a->inum == b->inum) {
584
- return dec_pzero(); /* FIXME: for scaling */
699
+ /* FIXME: UNDER CONSTRUCTION for scaling */
700
+ return dec_pzero(MAX(a->scale, b->scale));
585
701
  }
586
702
  return dec_uminus(y);
587
703
  }
588
- if (DEC_ISINF(b)) return dec_uminus(y);
589
704
  if (DEC_ZERO_P(b)) return x;
590
705
  /* "false" means subtraction */
591
706
  return WrapDecimal(normal_plus(a, b, Qfalse));
592
707
  }
593
708
 
594
709
  static Decimal *
595
- normal_mul(Decimal *x, Decimal *y)
710
+ normal_mul(const Decimal *x, const Decimal *y)
596
711
  {
597
- Decimal *z = ALLOC(Decimal);
598
-
599
- z->inum = INUM_MUL(x->inum, y->inum);
600
- z->scale = x->scale + y->scale;
601
- return z;
712
+ return dec_raw_new(INUM_MUL(x->inum, y->inum), x->scale + y->scale);
602
713
  }
603
714
 
715
+ /*
716
+ * call-seq:
717
+ * dec * other => decimal
718
+ *
719
+ * Returns a new decimal which is the product of _dec_ and _other_.
720
+ */
604
721
  static VALUE
605
722
  dec_mul(VALUE x, VALUE y)
606
723
  {
607
724
  Decimal *a, *b;
608
725
 
726
+ CHECK_NAN2(x, y);
609
727
  switch (TYPE(y)) {
610
728
  case T_FIXNUM:
611
729
  /* TODO: can be optimized if y = 0, 1 or -1 */
@@ -618,31 +736,29 @@ dec_mul(VALUE x, VALUE y)
618
736
  case T_DATA:
619
737
  if (DECIMAL_P(y)) {
620
738
  GetDecimal(y, b);
621
- if (b == DEC_NaN) return VALUE_NaN;
622
739
  break;
623
740
  }
624
741
  /* fall through */
625
742
  default:
626
- return rb_num_coerce_bin(x, y);
743
+ return rb_num_coerce_bin(x, y, '*');
627
744
  }
628
745
  GetDecimal(x, a);
629
- if (a == DEC_NaN) return VALUE_NaN;
630
746
 
631
747
  if (DEC_ISINF(a)) {
632
- if (DEC_ISINF(b)) return a == DEC_PINF ? y : dec_uminus(y);
748
+ if (DEC_ISINF(b)) return x == y ? VALUE_PINF : VALUE_NINF;
633
749
  if (DEC_ZERO_P(b)) return VALUE_NaN;
634
750
  if (!INUM_NEGATIVE_P(b->inum)) return x;
635
751
  return dec_uminus(x);
636
752
  }
637
753
  if (DEC_ZERO_P(a)) {
638
754
  if (DEC_ISINF(b)) return VALUE_NaN;
639
- if (INUM_SPZERO_P(b->inum)) {
755
+ if (DEC_ZERO_P(b)) {
640
756
  return a->inum == DEC_PZERO ? y : dec_uminus(y);
641
757
  }
642
758
  if (INUM_NEGATIVE_P(b->inum)) return dec_uminus(x);
643
759
  return x;
644
760
  }
645
- if (DEC_IMMEDIATE_P(b) || INUM_SPZERO_P(b->inum)) {
761
+ if (DEC_IMMEDIATE_P(b) || DEC_ZERO_P(b)) {
646
762
  if (INUM_NEGATIVE_P(a->inum)) return dec_uminus(y);
647
763
  return y;
648
764
  }
@@ -650,21 +766,21 @@ dec_mul(VALUE x, VALUE y)
650
766
  }
651
767
 
652
768
  static Decimal *
653
- do_round(Decimal *d, long scale, VALUE mode, VALUE *inump)
769
+ do_round(const Decimal *d, long scale, VALUE mode, VALUE *inump)
654
770
  {
655
771
  Decimal *d2;
656
772
  long diff;
657
773
  int lower;
658
774
  int trailing_nonzero, negative;
659
- VALUE inum, inumabs, shift, tmp, ary;
775
+ VALUE inum, inumabs, shift, ary;
660
776
 
661
777
  if (d == DEC_PINF) rb_raise(eDomainError, "Infinity");
662
778
  if (d == DEC_NINF) rb_raise(eDomainError, "-Infinity");
663
779
  if (d == DEC_NaN) rb_raise(eDomainError, "NaN");
664
780
  if (INUM_SPZERO_P(d->inum)) {
665
781
  if (inump) {
666
- if (scale != 0) rb_bug("do_round(): "
667
- "scale != 0 with Integer request");
782
+ if (scale > 0) rb_bug("do_round(): "
783
+ "scale > 0 with Integer request");
668
784
  *inump = INT2FIX(0);
669
785
  return NULL;
670
786
  }
@@ -673,11 +789,11 @@ do_round(Decimal *d, long scale, VALUE mode, VALUE *inump)
673
789
  return d2;
674
790
  }
675
791
  if (d->scale <= scale) { /* no need to round */
676
- /* return Decimal */
677
- if (scale) return finite_dup(d);
792
+ if (scale) return finite_dup(d); /* return Decimal */
678
793
  /* return Integer */
679
794
  if (!inump) /* XXX: may be reached when Decimal(1)/1 */
680
- rb_bug("do_round(): not reached[2]");
795
+ rb_bug("do_round(): not reached[2]");
796
+ /* FIXME: scaling policy, no need to grow scale? */
681
797
  if (d->scale == 0) *inump = d->inum;
682
798
  else *inump = inum_lshift(d->inum, -d->scale);
683
799
  return NULL;
@@ -685,16 +801,16 @@ do_round(Decimal *d, long scale, VALUE mode, VALUE *inump)
685
801
  negative = INUM_NEGATIVE_P(d->inum);
686
802
  diff = d->scale - scale;
687
803
  inumabs = negative ? INUM_UMINUS(d->inum) : d->inum;
688
- if (mode == ROUND_CEILING ||
804
+ if (mode == ROUND_CEILING || /* don't need lower digit */
689
805
  mode == ROUND_DOWN ||
690
806
  mode == ROUND_FLOOR ||
691
807
  mode == ROUND_UP ||
692
808
  mode == ROUND_UNNECESSARY) {
693
809
  shift = inum_lshift(INT2FIX(1), diff);
694
810
  ary = INUM_DIVMOD(inumabs, shift);
695
- inum = RARRAY(ary)->ptr[0];
811
+ inum = RARRAY_PTR(ary)[0];
696
812
  if (mode == ROUND_DOWN) goto coda;
697
- trailing_nonzero = !INUM_ZERO_P(RARRAY(ary)->ptr[1]);
813
+ trailing_nonzero = !INUM_ZERO_P(RARRAY_PTR(ary)[1]);
698
814
  if (mode == ROUND_CEILING) {
699
815
  if (!negative && trailing_nonzero) INUM_INC(inum);
700
816
  }
@@ -713,16 +829,13 @@ do_round(Decimal *d, long scale, VALUE mode, VALUE *inump)
713
829
  else if (mode == ROUND_HALF_DOWN || /* needs lower digit */
714
830
  mode == ROUND_HALF_UP ||
715
831
  mode == ROUND_HALF_EVEN) {
716
- if (diff != 1)
832
+ if (diff > 1) { /* needs shift */
717
833
  shift = inum_lshift(INT2FIX(1), diff-1);
718
- else
719
- shift = INT2FIX(1); /* FIXME!!! */
720
- ary = INUM_DIVMOD(inumabs, shift);
721
- tmp = RARRAY(ary)->ptr[0];
722
-
723
- ary = INUM_DIVMOD(tmp, INT2FIX(10));
724
- inum = RARRAY(ary)->ptr[0];
725
- lower = FIX2INT(RARRAY(ary)->ptr[1]);
834
+ inumabs = INUM_DIV(inumabs, shift);
835
+ }
836
+ ary = INUM_DIVMOD(inumabs, INT2FIX(10));
837
+ inum = RARRAY_PTR(ary)[0];
838
+ lower = FIX2INT(RARRAY_PTR(ary)[1]);
726
839
  if (mode == ROUND_HALF_DOWN) {
727
840
  if (lower > 5) INUM_INC(inum);
728
841
  }
@@ -740,46 +853,43 @@ do_round(Decimal *d, long scale, VALUE mode, VALUE *inump)
740
853
  }
741
854
  coda:
742
855
  if (negative) inum = INUM_UMINUS(inum);
743
- if (scale == 0 && inump) { /* return Integer */
856
+ if (scale <= 0 && inump != NULL) {
857
+ /* return Integer */
858
+ if (scale < 0) inum = inum_lshift(inum, -scale);
744
859
  *inump = inum;
745
860
  return NULL;
746
861
  }
747
862
  /* return Decimal */
748
- d2 = ALLOC(Decimal);
749
863
  if (INUM_ZERO_P(inum)) {
750
- d2->inum = negative ? DEC_NZERO : DEC_PZERO;
751
- d2->scale = 0;
864
+ inum = negative ? DEC_NZERO : DEC_PZERO;
865
+ scale = 0;
752
866
  }
753
- else {
754
- d2->inum = inum;
755
- d2->scale = scale;
756
- }
757
- return d2;
867
+ return dec_raw_new(inum, scale);
758
868
  }
759
869
 
760
870
  static Decimal *
761
- normal_divide(Decimal *x, Decimal *y, long scale, VALUE mode)
871
+ normal_divide(const Decimal *x, const Decimal *y, long scale, VALUE mode)
762
872
  {
763
- long diff;
873
+ long diff, z_scale;
764
874
  VALUE xx;
765
- Decimal *z = ALLOC(Decimal);
875
+ Decimal *z;
766
876
 
767
877
  diff = x->scale - y->scale;
768
878
  if (diff <= scale) {
769
879
  xx = inum_lshift(x->inum, scale-diff+1); /* +1 for rounding */
770
- z->scale = scale + 1;
880
+ z_scale = scale + 1;
771
881
  }
772
882
  else {
773
883
  /* FIXME: may be a bug...? */
774
884
  xx = x->inum;
775
- z->scale = diff;
885
+ z_scale = diff;
776
886
  }
777
- z->inum = INUM_DIV(xx, y->inum);
778
- return do_round(z, scale, mode, 0);
887
+ z = dec_raw_new(INUM_DIV(xx, y->inum), z_scale);
888
+ return do_round(z, scale, mode, NULL);
779
889
  }
780
890
 
781
891
  static int
782
- valid_rounding_mode(VALUE sym)
892
+ valid_rounding_mode_p(VALUE sym)
783
893
  {
784
894
  if (sym == ROUND_CEILING ||
785
895
  sym == ROUND_DOWN ||
@@ -794,25 +904,35 @@ valid_rounding_mode(VALUE sym)
794
904
  return Qfalse;
795
905
  }
796
906
 
907
+ /*
908
+ * call-seq:
909
+ * dec.divide(other, scale=0, mode=Decimal::ROUND_UNNECESSARY) #=> decimal or integer
910
+ *
911
+ * *WARNING*: The behavior of this method may change.
912
+ *
913
+ * Returns a new decimal which is the result of dividing _dec_ by _other_.
914
+ *
915
+ * *FIXME*: write details
916
+ */
797
917
  static VALUE
798
918
  dec_divide(int argc, VALUE *argv, VALUE x)
799
919
  {
800
920
  VALUE y;
801
921
  Decimal *a, *b;
802
922
  VALUE mode = ROUND_UNNECESSARY;
803
- long scale, l;
923
+ long l, scale = 0; /* FIXME: dummy 0 */
804
924
  VALUE vscale, vmode;
805
925
 
926
+ CHECK_NAN(x);
806
927
  GetDecimal(x, a);
807
- if (a == DEC_NaN) return VALUE_NaN; /* no need to check b */
808
928
 
809
929
  rb_scan_args(argc, argv, "12", &y, &vscale, &vmode);
810
930
  switch (argc) {
811
931
  case 3:
812
932
  Check_Type(vmode, T_SYMBOL);
813
- if (!valid_rounding_mode(vmode)) {
933
+ if (!valid_rounding_mode_p(vmode)) {
814
934
  rb_raise(rb_eArgError, "invalid rounding mode %s",
815
- RSTRING(rb_inspect(mode))->ptr);
935
+ RSTRING_PTR(rb_inspect(vmode)));
816
936
  }
817
937
  mode = vmode;
818
938
  /* fall through */
@@ -823,15 +943,15 @@ dec_divide(int argc, VALUE *argv, VALUE x)
823
943
  if (mode != ROUND_UNNECESSARY) {
824
944
  rb_raise(rb_eArgError, "scale number argument needed");
825
945
  }
826
- scale = 0; /* FIXME: dummy */
827
946
  }
947
+ CHECK_NAN(y);
828
948
 
829
949
  switch (TYPE(y)) {
830
950
  case T_FIXNUM:
831
951
  l = FIX2LONG(y);
832
952
  if (l == 0) {
833
- if (DEC_ZERO_P(a)) return VALUE_NaN;
834
953
  if (DEC_ISINF(a)) return x;
954
+ if (DEC_ZERO_P(a)) return VALUE_NaN;
835
955
  return INUM_NEGATIVE_P(a->inum) ? VALUE_NINF : VALUE_PINF;
836
956
  }
837
957
  else if (l == 1) return x;
@@ -846,19 +966,18 @@ dec_divide(int argc, VALUE *argv, VALUE x)
846
966
  case T_DATA:
847
967
  if (DECIMAL_P(y)) {
848
968
  GetDecimal(y, b);
849
- if (b == DEC_NaN) return VALUE_NaN;
850
969
  break;
851
970
  }
852
971
  /* fall through */
853
972
  default:
854
- return rb_num_coerce_bin(x, y);
973
+ return rb_num_coerce_bin(x, y, rb_intern("divide"));
855
974
  }
856
- /* TODO: can be optimized if b == 0, 1 or -1 */
975
+
857
976
  if (DEC_ISINF(a)) {
858
977
  if (DEC_ISINF(b)) return VALUE_NaN;
859
978
  if (b->inum == DEC_PZERO) return x;
860
- if (b->inum == DEC_NZERO) return dec_uminus(x);
861
- return INUM_NEGATIVE_P(b->inum) ? dec_uminus(x) : x;
979
+ if (b->inum == DEC_NZERO) return NEGATE_INF(x);
980
+ return INUM_NEGATIVE_P(b->inum) ? NEGATE_INF(x) : x;
862
981
  }
863
982
  if (DEC_ZERO_P(a)) {
864
983
  if (b == DEC_PINF) return x;
@@ -868,9 +987,9 @@ dec_divide(int argc, VALUE *argv, VALUE x)
868
987
  }
869
988
  if (DEC_ISINF(b)) {
870
989
  if (INUM_NEGATIVE_P(a->inum) == (b == DEC_NINF)) {
871
- return dec_pzero();
990
+ return dec_pzero(0); /* FIXME for scaling */
872
991
  }
873
- return dec_nzero();
992
+ return dec_nzero(0); /* FIXME for scaling */
874
993
  }
875
994
  if (DEC_ZERO_P(b)) {
876
995
  if (INUM_NEGATIVE_P(a->inum) == (b->inum == DEC_NZERO)) {
@@ -882,6 +1001,7 @@ dec_divide(int argc, VALUE *argv, VALUE x)
882
1001
  }
883
1002
 
884
1003
  #ifdef DEBUG
1004
+ /* :nodoc: */
885
1005
  static VALUE
886
1006
  dec_div(VALUE x, VALUE y)
887
1007
  {
@@ -889,75 +1009,72 @@ dec_div(VALUE x, VALUE y)
889
1009
  }
890
1010
  #endif
891
1011
 
892
- /*
893
- * FIXME: test needed!
894
- */
1012
+ /* never accepts NaN for a and b */
895
1013
  static void
896
- divmod(Decimal *a, Decimal *b, VALUE *divp, VALUE *modp)
1014
+ divmod(const Decimal *a, const Decimal *b, VALUE *divp, VALUE *modp)
897
1015
  {
898
- Decimal *div, *mod;
899
- Decimal *tmp;
1016
+ VALUE div;
1017
+ Decimal *mod;
900
1018
 
901
- if (a == DEC_NaN || DEC_ISINF(a) || b == DEC_NaN ||
902
- (!DEC_ISINF(b) && DEC_ZERO_P(b))) {
903
- div = mod = DEC_NaN;
1019
+ if (DEC_ISINF(a) || (!DEC_ISINF(b) && DEC_ZERO_P(b))) {
1020
+ if (divp) *divp = VALUE_NaN;
1021
+ if (modp) *modp = VALUE_NaN;
1022
+ return;
904
1023
  }
905
1024
  else if (INUM_SPZERO_P(a->inum)) {
906
- div = ALLOC(Decimal);
907
- div->scale = 0;
908
- if (b == DEC_NINF || (b != DEC_PINF && INUM_NEGATIVE_P(b->inum))) {
909
- div->inum = DEC_NZERO;
910
- }
911
- else {
912
- div->inum = DEC_PZERO;
913
- }
1025
+ div = INT2FIX(0);
914
1026
  mod = finite_dup(a);
915
1027
  }
916
1028
  else if (DEC_ISINF(b)) {
917
1029
  const int a_negative = INUM_NEGATIVE_P(a->inum);
1030
+ VALUE div_inum;
918
1031
 
919
- div = ALLOC(Decimal);
920
- div->scale = 0;
921
1032
  if (a_negative != (b == DEC_NINF)) { /* signs differ */
922
- div->inum = INT2FIX(-1);
923
- mod = b;
924
- }
925
- else {
926
- div->inum = a_negative ? DEC_NZERO : DEC_PZERO;
927
- mod = finite_dup(a);
1033
+ if (divp) *divp = INT2FIX(-1);
1034
+ if (modp) *modp = b == DEC_PINF ? VALUE_PINF : VALUE_NINF;
1035
+ return;
928
1036
  }
1037
+ div = INT2FIX(0);
1038
+ mod = finite_dup(a);
929
1039
  }
930
1040
  else {
931
1041
  /* both of a and b are finite and nonzero */
932
- div = normal_divide(a, b, 0, ROUND_DOWN); /* div = x / y */
933
- if (INUM_SPZERO_P(div->inum)) {
934
- if (INUM_NEGATIVE_P(b->inum)) div->inum = DEC_NZERO;
1042
+ Decimal *ddiv = normal_divide(a, b, 0, ROUND_DOWN); /* div = x / y */
1043
+ Decimal *tmp;
1044
+
1045
+ if (INUM_SPZERO_P(ddiv->inum)) {
1046
+ div = INT2FIX(0);
935
1047
  mod = finite_dup(a);
936
1048
  }
937
1049
  else {
938
- tmp = normal_mul(div, b);
939
- mod = normal_plus(a, tmp, 0); /* mod = x - div*y; */
1050
+ div = FIXNUM_P(ddiv->inum) ? ddiv->inum : rb_big_clone(ddiv->inum);
1051
+ tmp = normal_mul(ddiv, b);
1052
+ mod = normal_plus(a, tmp, Qfalse); /* mod = x - div*y; */
940
1053
  xfree(tmp);
941
1054
  }
1055
+ xfree(ddiv);
942
1056
  /* if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) { */
943
- if (INUM_NEGATIVE_P(mod->inum) != INUM_NEGATIVE_P(b->inum) &&
944
- INUM_SPZERO_P(mod->inum) && INUM_SPZERO_P(b->inum)) {
945
- mod = normal_plus(mod, b, 1); /* mod += y; */
946
- INUM_DEC(div->inum); /* div -= 1; */
1057
+ if (!INUM_SPZERO_P(mod->inum) && !INUM_SPZERO_P(b->inum) &&
1058
+ INUM_NEGATIVE_P(mod->inum) != INUM_NEGATIVE_P(b->inum)) {
1059
+ tmp = mod;
1060
+ mod = normal_plus(tmp, b, Qtrue); /* mod += y; */
1061
+ xfree(tmp);
1062
+ INUM_DEC(div); /* div -= 1; */
947
1063
  }
948
1064
  }
949
- if (divp) *divp = WrapDecimal(div);
950
- else if (!DEC_IMMEDIATE_P(div)) xfree(div);
1065
+ if (divp) *divp = div;
951
1066
  if (modp) *modp = WrapDecimal(mod);
952
1067
  else if (!DEC_IMMEDIATE_P(mod)) xfree(mod);
953
1068
  }
954
1069
 
1070
+ /* :nodoc: */
955
1071
  static VALUE
956
1072
  dec_idiv(VALUE x, VALUE y)
957
1073
  {
958
1074
  Decimal *a, *b;
959
1075
  VALUE div;
960
1076
 
1077
+ CHECK_NAN2(x, y);
961
1078
  switch (TYPE(y)) {
962
1079
  case T_FIXNUM:
963
1080
  case T_BIGNUM:
@@ -972,19 +1089,30 @@ dec_idiv(VALUE x, VALUE y)
972
1089
  }
973
1090
  /* fall through */
974
1091
  default:
975
- return rb_num_coerce_bin(x, y);
1092
+ return rb_num_coerce_bin(x, y, rb_intern("div"));
976
1093
  }
977
1094
  GetDecimal(x, a);
978
1095
  divmod(a, b, &div, NULL);
979
1096
  return div;
980
1097
  }
981
1098
 
1099
+ /*
1100
+ * call-seq:
1101
+ * dec % other => decimal
1102
+ * dec.modulo(other) => decimal
1103
+ *
1104
+ * Return the modulo after division of _dec_ by _other_.
1105
+ *
1106
+ * Decimal("6543.21").modulo(137) #=> Decimal(104.21)
1107
+ * Decimal("6543.21").modulo(Decimal("137.24")) #=> Decimal(92.9299999999996)
1108
+ */
982
1109
  static VALUE
983
1110
  dec_mod(VALUE x, VALUE y)
984
1111
  {
985
1112
  Decimal *a, *b;
986
1113
  VALUE mod;
987
1114
 
1115
+ CHECK_NAN2(x, y);
988
1116
  switch (TYPE(y)) {
989
1117
  case T_FIXNUM:
990
1118
  case T_BIGNUM:
@@ -999,19 +1127,35 @@ dec_mod(VALUE x, VALUE y)
999
1127
  }
1000
1128
  /* fall through */
1001
1129
  default:
1002
- return rb_num_coerce_bin(x, y);
1130
+ return rb_num_coerce_bin(x, y, '%');
1003
1131
  }
1004
1132
  GetDecimal(x, a);
1005
1133
  divmod(a, b, NULL, &mod);
1006
1134
  return mod;
1007
1135
  }
1008
1136
 
1137
+ /*
1138
+ * call-seq:
1139
+ * dec.divmod(other) => array
1140
+ *
1141
+ * Returns an array containing the quotient and modulus obtained by
1142
+ * dividing _dec_ by _other_.
1143
+ *
1144
+ * Decimal(11).divmod(3) #=> [3, Decimal(2)]
1145
+ * Decimal(11).divmod(-3) #=> [-4, Decimal(-1)]
1146
+ * Decimal(11).divmod(Decimal("3.5")) #=> [3, Decimal(0.5)]
1147
+ * Decimal(-11).divmod(Decimal("3.5")) #=> [-4, Decimal(3.0)]
1148
+ * Decimal("11.5").divmod(Decimal("3.5")) #=> [3, Decimal(1.0)]
1149
+ *
1150
+ * See Numeric#divmod for more details.
1151
+ */
1009
1152
  static VALUE
1010
1153
  dec_divmod(VALUE x, VALUE y)
1011
1154
  {
1012
1155
  Decimal *a, *b;
1013
1156
  VALUE div, mod;
1014
1157
 
1158
+ CHECK_NAN2_WITH_VAL(x, y, rb_assoc_new(VALUE_NaN, VALUE_NaN));
1015
1159
  switch (TYPE(y)) {
1016
1160
  case T_FIXNUM:
1017
1161
  case T_BIGNUM:
@@ -1026,137 +1170,150 @@ dec_divmod(VALUE x, VALUE y)
1026
1170
  }
1027
1171
  /* fall through */
1028
1172
  default:
1029
- return rb_num_coerce_bin(x, y);
1173
+ return rb_num_coerce_bin(x, y, rb_intern("divmod"));
1030
1174
  }
1031
1175
  GetDecimal(x, a);
1032
1176
  divmod(a, b, &div, &mod);
1033
1177
  return rb_assoc_new(div, mod);
1034
1178
  }
1035
1179
 
1036
- /* XXX: may have bugs; try "GC.stress = true" to reproduce */
1037
- /* TODO: can be optimized with removing sign "flip flap?" */
1038
1180
  static VALUE
1039
- power_with_long(Decimal *x, long y) /* requires y > 1 */
1181
+ power_with_fixnum(const Decimal *x, VALUE y)
1040
1182
  {
1041
- Decimal *z = x, *const orig_x = x, *tmp;
1183
+ VALUE inum;
1042
1184
 
1043
- for (;;) {
1044
- y--;
1045
- if (y == 0) break;
1046
- while ((y & 1) == 0) {
1047
- y >>= 1;
1048
- x = normal_mul(x, x);
1049
- if (!FIXNUM_P(x->inum)) rb_gc_mark(x->inum);
1050
- }
1051
- tmp = z;
1052
- z = normal_mul(z, x);
1053
- if (!FIXNUM_P(z->inum)) rb_gc_mark(z->inum);
1054
- if (tmp != orig_x)
1055
- xfree(tmp);
1056
- }
1057
- return WrapDecimal(z);
1185
+ /* XXX: valid to rb_warn() out of here by rb_big_pow()? */
1186
+ inum = INUM_POW(x->inum, y);
1187
+ if (TYPE(inum) == T_FLOAT) /* got Infinity with warning, by too-big y */
1188
+ return VALUE_PINF;
1189
+ return WrapDecimal(dec_raw_new(inum, x->scale * FIX2LONG(y)));
1058
1190
  }
1059
1191
 
1192
+ /* TODO: implement dec ** otherdec */
1193
+ /*
1194
+ * call-seq:
1195
+ * dec ** fix => decimal
1196
+ *
1197
+ * *WARNING*: The behavior of this method may change.
1198
+ *
1199
+ * Raises _dec_ the _fix_ power.
1200
+ */
1060
1201
  static VALUE
1061
1202
  dec_pow(VALUE x, VALUE y)
1062
1203
  {
1063
1204
  Decimal *a;
1064
1205
  long l;
1065
1206
 
1066
- GetDecimal(x, a);
1207
+ CHECK_NAN(x);
1067
1208
  Check_Type(y, T_FIXNUM);
1068
1209
  l = FIX2LONG(y);
1069
1210
  if (l < 0) rb_raise(rb_eArgError, "in a**b, b should be positive integer");
1070
- if (l == 0) {
1071
- Decimal *d = ALLOC(Decimal);
1072
-
1073
- d->inum = INT2FIX(1);
1074
- d->scale = 0;
1075
- return WrapDecimal(d);
1076
- }
1077
- if (a == DEC_NaN || l == 1) return x;
1078
- if (a == DEC_PINF || (a != DEC_NINF && a->inum == DEC_PZERO)) return x;
1079
- if (a == DEC_NINF || a->inum == DEC_NZERO) {
1080
- if (l % 2 == 0) {
1081
- return a == DEC_NINF ? VALUE_PINF : dec_uminus(x);
1082
- }
1083
- return x;
1211
+ if (l == 0) return WrapDecimal(dec_raw_new(INT2FIX(1), 0));
1212
+ if (l == 1) return x;
1213
+
1214
+ if (x == VALUE_PINF) return x;
1215
+ if (x == VALUE_NINF) {
1216
+ return l % 2 == 0 ? VALUE_PINF : VALUE_NINF;
1217
+ }
1218
+ GetDecimal(x, a);
1219
+ if (a->inum == DEC_PZERO) return x;
1220
+ if (a->inum == DEC_NZERO) {
1221
+ return l % 2 == 0 ? dec_uminus(x) : x;
1084
1222
  }
1085
- return power_with_long(a, l);
1223
+ return power_with_fixnum(a, y);
1086
1224
  }
1087
1225
 
1088
1226
  static int
1089
- normal_cmp(Decimal *x, Decimal *y)
1227
+ normal_cmp(const Decimal *x, const Decimal *y)
1090
1228
  {
1091
- Decimal *max, *min;
1092
- VALUE n;
1093
- const int c = FIX2INT(INUM_CMP(x->inum, y->inum));
1094
-
1095
- if (x->scale == y->scale) return c;
1096
- if (c == 0) {
1097
- return x->scale > y->scale ? -1 : 1;
1229
+ if (INUM_NEGATIVE_P(x->inum) && !INUM_NEGATIVE_P(y->inum)) {
1230
+ return -1;
1231
+ }
1232
+ if (!INUM_NEGATIVE_P(x->inum) && INUM_NEGATIVE_P(y->inum)) {
1233
+ return 1;
1234
+ }
1235
+ if (x->scale == y->scale) return FIX2INT(INUM_CMP(x->inum, y->inum));
1236
+ /* XXX: can be optimized with INUM_EQ()? */
1237
+ if (x->scale < y->scale) {
1238
+ VALUE x_scaled = inum_lshift(x->inum, y->scale - x->scale);
1239
+ return FIX2INT(INUM_CMP(x_scaled, y->inum));
1240
+ }
1241
+ else {
1242
+ VALUE y_scaled = inum_lshift(y->inum, x->scale - y->scale);
1243
+ return FIX2INT(INUM_CMP(x->inum, y_scaled));
1098
1244
  }
1099
- if (c < 0 && x->scale > y->scale) return -1;
1100
- if (c > 0 && x->scale < y->scale) return 1;
1101
- /* XXX: align scales */
1102
- if (x->scale < y->scale) min = x, max = y;
1103
- else min = y, max = x;
1104
- n = inum_lshift(min->inum, max->scale - min->scale);
1105
- if (x == max) return FIX2INT(INUM_CMP(max->inum, n));
1106
- return FIX2INT(INUM_CMP(n, max->inum));
1107
1245
  }
1108
1246
 
1109
- /* never accepts NaN for x and y */
1247
+ /* never accepts NaN for x or y */
1110
1248
  static int
1111
- cmp(Decimal *x, Decimal *y)
1249
+ cmp(const Decimal *x, const Decimal *y)
1112
1250
  {
1113
1251
  if (x == y) return 0;
1114
1252
  if (x == DEC_PINF || y == DEC_NINF) return 1;
1115
1253
  if (x == DEC_NINF || y == DEC_PINF) return -1;
1116
1254
  if (INUM_SPZERO_P(x->inum)) {
1117
1255
  if (INUM_SPZERO_P(y->inum)) return 0;
1118
- return INUM_NEGATIVE_P(y->inum) ? -1 : 1;
1256
+ return INUM_NEGATIVE_P(y->inum) ? 1 : -1;
1119
1257
  }
1120
1258
  if (INUM_SPZERO_P(y->inum)) {
1121
1259
  return INUM_NEGATIVE_P(x->inum) ? -1 : 1;
1122
1260
  }
1123
- return normal_cmp(x, y);
1261
+ return normal_cmp(x, y);
1124
1262
  }
1125
1263
 
1264
+ /*
1265
+ * call-seq:
1266
+ * dec == other => true or false
1267
+ *
1268
+ * Returns +true+ only if _other_ has the same value as _dec_.
1269
+ * Contrast this with eql?, which requires _other_
1270
+ * to be the same class, a +Decimal+.
1271
+ *
1272
+ * Decimal(1) == 1 #=> true
1273
+ * Decimal(1) == Decimal("1.0") #=> true
1274
+ * Decimal(1) == 1.0 #=> false
1275
+ */
1126
1276
  static VALUE
1127
1277
  dec_eq(VALUE x, VALUE y)
1128
1278
  {
1129
1279
  Decimal *a, *b;
1130
1280
 
1281
+ CHECK_NAN2_WITH_VAL(x, y, Qfalse);
1131
1282
  GetDecimal(x, a);
1132
- if (a == DEC_NaN) return Qfalse;
1133
1283
  switch (TYPE(y)) {
1134
1284
  case T_FIXNUM:
1135
1285
  case T_BIGNUM:
1136
1286
  b = inum_to_dec(y);
1137
1287
  break;
1138
1288
  case T_FLOAT:
1139
- return Qnil;
1289
+ return Qfalse;
1140
1290
  case T_DATA:
1141
1291
  if (DECIMAL_P(y)) {
1142
1292
  GetDecimal(y, b);
1143
- if (b == DEC_NaN) return Qfalse;
1144
1293
  break;
1145
1294
  }
1146
1295
  /* fall through */
1147
1296
  default:
1148
- return rb_num_coerce_cmp(x, y);
1297
+ return RTEST(rb_num_coerce_cmp(x, y, rb_intern("==")));
1149
1298
  }
1150
1299
  return cmp(a, b) == 0 ? Qtrue : Qfalse;
1151
1300
  }
1152
1301
 
1302
+ /*
1303
+ * call-seq:
1304
+ * dec <=> other => -1, 0, +1
1305
+ *
1306
+ * Returns -1, 0, or +1 depending on whether _dec_ is less than,
1307
+ * equal to, or greater than _other_. This is the basis for the
1308
+ * tests in +Comparable+.
1309
+ */
1153
1310
  static VALUE
1154
1311
  dec_cmp(VALUE x, VALUE y)
1155
1312
  {
1156
1313
  Decimal *a, *b;
1157
1314
 
1315
+ CHECK_NAN2_WITH_VAL(x, y, Qnil);
1158
1316
  GetDecimal(x, a);
1159
- if (a == DEC_NaN) return Qnil;
1160
1317
  switch (TYPE(y)) {
1161
1318
  case T_FIXNUM:
1162
1319
  case T_BIGNUM:
@@ -1167,23 +1324,28 @@ dec_cmp(VALUE x, VALUE y)
1167
1324
  case T_DATA:
1168
1325
  if (DECIMAL_P(y)) {
1169
1326
  GetDecimal(y, b);
1170
- if (b == DEC_NaN) return Qnil;
1171
1327
  break;
1172
1328
  }
1173
1329
  /* fall through */
1174
1330
  default:
1175
- return rb_num_coerce_cmp(x, y);
1331
+ return rb_num_coerce_cmp(x, y, rb_intern("<=>"));
1176
1332
  }
1177
1333
  return INT2FIX(cmp(a, b));
1178
1334
  }
1179
1335
 
1336
+ /*
1337
+ * call-seq:
1338
+ * dec > other => true or false
1339
+ *
1340
+ * Returns +true+ if _dec_ is greater than _other_.
1341
+ */
1180
1342
  static VALUE
1181
1343
  dec_gt(VALUE x, VALUE y)
1182
1344
  {
1183
1345
  Decimal *a, *b;
1184
1346
 
1347
+ CHECK_NAN2_WITH_VAL(x, y, Qfalse);
1185
1348
  GetDecimal(x, a);
1186
- if (a == DEC_NaN) return Qfalse;
1187
1349
  switch (TYPE(y)) {
1188
1350
  case T_FIXNUM:
1189
1351
  case T_BIGNUM:
@@ -1195,23 +1357,28 @@ dec_gt(VALUE x, VALUE y)
1195
1357
  case T_DATA:
1196
1358
  if (DECIMAL_P(y)) {
1197
1359
  GetDecimal(y, b);
1198
- if (b == DEC_NaN) return Qfalse;
1199
1360
  break;
1200
1361
  }
1201
1362
  /* fall through */
1202
1363
  default:
1203
- return rb_num_coerce_relop(x, y);
1364
+ return rb_num_coerce_relop(x, y, '>');
1204
1365
  }
1205
1366
  return cmp(a, b) > 0 ? Qtrue : Qfalse;
1206
1367
  }
1207
1368
 
1369
+ /*
1370
+ * call-seq:
1371
+ * dec >= other => true or false
1372
+ *
1373
+ * Returns +true+ if _dec_ is greater than or equal to _other_.
1374
+ */
1208
1375
  static VALUE
1209
1376
  dec_ge(VALUE x, VALUE y)
1210
1377
  {
1211
1378
  Decimal *a, *b;
1212
1379
 
1380
+ CHECK_NAN2_WITH_VAL(x, y, Qfalse);
1213
1381
  GetDecimal(x, a);
1214
- if (a == DEC_NaN) return Qfalse;
1215
1382
  switch (TYPE(y)) {
1216
1383
  case T_FIXNUM:
1217
1384
  case T_BIGNUM:
@@ -1223,23 +1390,28 @@ dec_ge(VALUE x, VALUE y)
1223
1390
  case T_DATA:
1224
1391
  if (DECIMAL_P(y)) {
1225
1392
  GetDecimal(y, b);
1226
- if (b == DEC_NaN) return Qfalse;
1227
1393
  break;
1228
1394
  }
1229
1395
  /* fall through */
1230
1396
  default:
1231
- return rb_num_coerce_relop(x, y);
1397
+ return rb_num_coerce_relop(x, y, rb_intern(">="));
1232
1398
  }
1233
1399
  return cmp(a, b) >= 0 ? Qtrue : Qfalse;
1234
1400
  }
1235
1401
 
1402
+ /*
1403
+ * call-seq:
1404
+ * dec < other => true or false
1405
+ *
1406
+ * Returns +true+ if _dec_ is less than _other_.
1407
+ */
1236
1408
  static VALUE
1237
1409
  dec_lt(VALUE x, VALUE y)
1238
1410
  {
1239
1411
  Decimal *a, *b;
1240
1412
 
1413
+ CHECK_NAN2_WITH_VAL(x, y, Qfalse);
1241
1414
  GetDecimal(x, a);
1242
- if (a == DEC_NaN) return Qfalse;
1243
1415
  switch (TYPE(y)) {
1244
1416
  case T_FIXNUM:
1245
1417
  case T_BIGNUM:
@@ -1251,23 +1423,28 @@ dec_lt(VALUE x, VALUE y)
1251
1423
  case T_DATA:
1252
1424
  if (DECIMAL_P(y)) {
1253
1425
  GetDecimal(y, b);
1254
- if (b == DEC_NaN) return Qfalse;
1255
1426
  break;
1256
1427
  }
1257
1428
  /* fall through */
1258
1429
  default:
1259
- return rb_num_coerce_relop(x, y);
1430
+ return rb_num_coerce_relop(x, y, '<');
1260
1431
  }
1261
1432
  return cmp(a, b) < 0 ? Qtrue : Qfalse;
1262
1433
  }
1263
1434
 
1435
+ /*
1436
+ * call-seq:
1437
+ * dec <= other => true or false
1438
+ *
1439
+ * Returns +true+ if _dec_ is less than or equal to _other_.
1440
+ */
1264
1441
  static VALUE
1265
1442
  dec_le(VALUE x, VALUE y)
1266
1443
  {
1267
1444
  Decimal *a, *b;
1268
1445
 
1446
+ CHECK_NAN2_WITH_VAL(x, y, Qfalse);
1269
1447
  GetDecimal(x, a);
1270
- if (a == DEC_NaN) return Qfalse;
1271
1448
  switch (TYPE(y)) {
1272
1449
  case T_FIXNUM:
1273
1450
  case T_BIGNUM:
@@ -1279,16 +1456,27 @@ dec_le(VALUE x, VALUE y)
1279
1456
  case T_DATA:
1280
1457
  if (DECIMAL_P(y)) {
1281
1458
  GetDecimal(y, b);
1282
- if (b == DEC_NaN) return Qfalse;
1283
1459
  break;
1284
1460
  }
1285
1461
  /* fall through */
1286
1462
  default:
1287
- return rb_num_coerce_relop(x, y);
1463
+ return rb_num_coerce_relop(x, y, rb_intern("<="));
1288
1464
  }
1289
1465
  return cmp(a, b) <= 0 ? Qtrue : Qfalse;
1290
1466
  }
1291
1467
 
1468
+ /*
1469
+ * call-seq:
1470
+ * dec.eql?(other) => true or false
1471
+ *
1472
+ * Returns +true+ if _other_ is a +Decimal+ and is equal to _dec_
1473
+ * including their values of scale.
1474
+ *
1475
+ * Decimal(1) == 1 #=> true
1476
+ * Decimal(1).eql?(1) #=> false
1477
+ * Decimal(1).eql?(Decimal(1)) #=> true
1478
+ * Decimal(1).eql?(Decimal("1.0"))) #=> false
1479
+ */
1292
1480
  static VALUE
1293
1481
  dec_eql(VALUE x, VALUE y)
1294
1482
  {
@@ -1297,12 +1485,12 @@ dec_eql(VALUE x, VALUE y)
1297
1485
  if (TYPE(y) != T_DATA || !DECIMAL_P(y))
1298
1486
  return Qfalse;
1299
1487
 
1488
+ CHECK_NAN2_WITH_VAL(x, y, Qfalse);
1489
+ if (DEC_VALUE_ISINF(x) || DEC_VALUE_ISINF(y))
1490
+ return x == y ? Qtrue : Qfalse;
1491
+
1300
1492
  GetDecimal(x, a);
1301
1493
  GetDecimal(y, b);
1302
- if (a == DEC_NaN || b == DEC_NaN) return Qfalse;
1303
- if (DEC_ISINF(a) || DEC_ISINF(b))
1304
- return a == b ? Qtrue : Qfalse;
1305
-
1306
1494
  if (a->scale != b->scale)
1307
1495
  return Qfalse;
1308
1496
  if (a->inum == b->inum)
@@ -1314,6 +1502,12 @@ dec_eql(VALUE x, VALUE y)
1314
1502
  return Qfalse;
1315
1503
  }
1316
1504
 
1505
+ /*
1506
+ * call-seq:
1507
+ * dec.hash => integer
1508
+ *
1509
+ * Returns a hash code for _dec_.
1510
+ */
1317
1511
  static VALUE
1318
1512
  dec_hash(VALUE x)
1319
1513
  {
@@ -1322,93 +1516,156 @@ dec_hash(VALUE x)
1322
1516
 
1323
1517
  GetDecimal(x, d);
1324
1518
  if (!DEC_IMMEDIATE_P(d)) {
1325
- hash = NUM2LONG(INUM_HASH(d->inum));
1519
+ VALUE inum = d->inum;
1520
+
1521
+ if (INUM_SPZERO_P(inum)) inum = INT2FIX(0);
1522
+ hash = NUM2LONG(INUM_HASH(inum));
1326
1523
  hash ^= d->scale;
1327
1524
  }
1328
1525
  else hash = (long)d;
1329
1526
  return LONG2NUM(hash);
1330
1527
  }
1331
1528
 
1332
- /* XXX: any other sane way? */
1333
- #define QUIET(stmt) do { \
1334
- RUBY_CRITICAL( \
1335
- const VALUE verbose = ruby_verbose; \
1336
- ruby_verbose = Qnil; \
1337
- stmt; \
1338
- ruby_verbose = verbose; \
1339
- ); \
1340
- } while (0)
1529
+ static Decimal *
1530
+ dbl_threshold_to_dec(double threshold)
1531
+ {
1532
+ VALUE v = flo_to_s(rb_float_new(threshold));
1533
+ Decimal *d = cstr_to_dec(StringValueCStr(v));
1341
1534
 
1342
- static double
1343
- normal_to_f(Decimal *d)
1535
+ if (!IMMEDIATE_P(d->inum)) {
1536
+ rb_global_variable(&d->inum);
1537
+ }
1538
+ return d;
1539
+ }
1540
+
1541
+ static VALUE
1542
+ dbl_threshold_to_inum(double threshold, VALUE *val)
1344
1543
  {
1345
- double f;
1544
+ const double f = floor(threshold);
1545
+
1546
+ if (FIXABLE(f)) {
1547
+ return *val = LONG2FIX((long)f);
1548
+ }
1549
+ rb_global_variable(val);
1550
+ return *val = rb_dbl2big(f);
1551
+ }
1346
1552
 
1347
- if (d->scale == 0) QUIET(f = NUM2DBL(d->inum));
1348
- else if (d->scale < 0) {
1349
- VALUE n;
1553
+ static int
1554
+ out_of_double_range_p(const Decimal *d, double *f)
1555
+ {
1556
+ const Decimal *d_abs;
1557
+ int negative, out_of_range = Qfalse;
1350
1558
 
1351
- n = inum_lshift(d->inum, -d->scale);
1352
- QUIET(f = NUM2DBL(n));
1559
+ if (!INUM_NEGATIVE_P(d->inum)) {
1560
+ negative = Qfalse;
1561
+ d_abs = d;
1353
1562
  }
1354
1563
  else {
1355
- /* FIXME: more strict handling needed for huge value */
1356
- double divf;
1357
- VALUE div;
1564
+ negative = Qtrue;
1565
+ d_abs = dec_raw_new(INUM_UMINUS(d->inum), d->scale);
1566
+ }
1358
1567
 
1359
- QUIET(f = NUM2DBL(d->inum));
1360
- div = inum_lshift(INT2FIX(1), d->scale);
1361
- QUIET(divf = NUM2DBL(div));
1362
- f /= divf;
1568
+ if (normal_cmp(d_abs, GET_DEC_DBL_MIN()) < 0) { /* too small */
1569
+ *f = negative ? -0.0 : 0.0;
1570
+ out_of_range = Qtrue;
1363
1571
  }
1364
- if (isinf(f)) {
1365
- rb_warn("Decimal out of Float range");
1366
- f = HUGE_VAL;
1572
+ else if (normal_cmp(d_abs, GET_DEC_DBL_MAX()) > 0) { /* too big */
1573
+ *f = negative ? -INFINITY : INFINITY;
1574
+ out_of_range = Qtrue;
1575
+ }
1576
+ if (d_abs != d) xfree((void *)d_abs);
1577
+ return out_of_range;
1578
+ }
1579
+
1580
+ static double
1581
+ normal_to_f(const Decimal *d)
1582
+ {
1583
+ double f;
1584
+
1585
+ if (d->scale <= 0) {
1586
+ f = NUM2DBL(d->inum) * pow(10.0, -d->scale);
1587
+ }
1588
+ else { /* NUM2DBL() may warn */
1589
+ const int negative = INUM_NEGATIVE_P(d->inum);
1590
+ long scale = d->scale;
1591
+ VALUE inum_abs = negative ? INUM_UMINUS(d->inum) : d->inum;
1592
+
1593
+ while (INUM_GT(inum_abs, GET_INUM_DBL_MAX())) {
1594
+ inum_abs = INUM_DIV(inum_abs, INT2FIX(10));
1595
+ scale--;
1596
+ }
1597
+ f = NUM2DBL(inum_abs) / pow(10.0, scale); /* scale may be negative */
1598
+ if (negative) f = -f;
1367
1599
  }
1368
1600
  return f;
1369
1601
  }
1370
1602
 
1603
+ /*
1604
+ * call-seq:
1605
+ * dec.to_f => float
1606
+ *
1607
+ * Converts _dec_ to a +Float+. Note that this may lose some precision
1608
+ * and/or exactness.
1609
+ * If you want to operate +Decimal+ with +Float+, use this method explicitly.
1610
+ */
1371
1611
  static VALUE
1372
1612
  dec_to_f(VALUE num)
1373
1613
  {
1374
1614
  Decimal *d;
1375
1615
  double f;
1376
1616
 
1617
+ CHECK_NAN_WITH_VAL(num, rb_float_new(NAN));
1618
+ if (num == VALUE_PINF)
1619
+ return rb_float_new(INFINITY);
1620
+ if (num == VALUE_NINF)
1621
+ return rb_float_new(-INFINITY);
1622
+
1377
1623
  GetDecimal(num, d);
1378
- if (d == DEC_NaN)
1379
- f = 0.0 / 0.0;
1380
- else if (d == DEC_PINF)
1381
- f = 1.0 / 0.0;
1382
- else if (d == DEC_NINF)
1383
- f = -1.0 / 0.0;
1384
- else if (d->inum == DEC_PZERO)
1624
+ if (d->inum == DEC_PZERO)
1385
1625
  f = 0.0;
1386
1626
  else if (d->inum == DEC_NZERO)
1387
1627
  f = -0.0;
1628
+ else if (out_of_double_range_p(d, &f))
1629
+ rb_warning("Decimal out of Float range");
1388
1630
  else
1389
1631
  f = normal_to_f(d);
1390
1632
 
1391
1633
  return rb_float_new(f);
1392
1634
  }
1393
1635
 
1636
+ /*
1637
+ * call-seq:
1638
+ * dec.abs => decimal
1639
+ *
1640
+ * Returns the absolute value of _dec_.
1641
+ *
1642
+ * Decimal("34.56").abs #=> Decimal(34.56)
1643
+ * Decimal("-34.56").abs #=> Decimal(34.56)
1644
+ */
1394
1645
  static VALUE
1395
1646
  dec_abs(VALUE num)
1396
1647
  {
1397
- Decimal *d, *d2;
1648
+ Decimal *d;
1649
+ VALUE inum;
1398
1650
 
1399
- GetDecimal(num, d);
1400
- if (d == DEC_NINF)
1651
+ CHECK_NAN(num);
1652
+ if (DEC_VALUE_ISINF(num))
1401
1653
  return VALUE_PINF;
1402
- if (d == DEC_PINF || d == DEC_NaN ||
1403
- d->inum == DEC_PZERO || !INUM_NEGATIVE_P(d->inum)) {
1654
+ GetDecimal(num, d);
1655
+ if (d->inum == DEC_PZERO ||
1656
+ (d->inum != DEC_NZERO && !INUM_NEGATIVE_P(d->inum))) {
1404
1657
  return num;
1405
1658
  }
1406
- d2 = ALLOC(Decimal);
1407
- d2->inum = (d->inum == DEC_NZERO) ? DEC_PZERO : INUM_UMINUS(d->inum);
1408
- d2->scale = d->scale;
1409
- return WrapDecimal(d2);
1659
+ inum = (d->inum == DEC_NZERO) ? DEC_PZERO : INUM_UMINUS(d->inum);
1660
+ return WrapDecimal(dec_raw_new(inum, d->scale));
1410
1661
  }
1411
1662
 
1663
+ /*
1664
+ * call-seq:
1665
+ * dec.zero? => true or false
1666
+ *
1667
+ * Returns +true+ if _dec_ is zero.
1668
+ */
1412
1669
  static VALUE
1413
1670
  dec_zero_p(VALUE num)
1414
1671
  {
@@ -1421,6 +1678,12 @@ dec_zero_p(VALUE num)
1421
1678
  return Qfalse;
1422
1679
  }
1423
1680
 
1681
+ /*
1682
+ * call-seq:
1683
+ * dec.to_i => integer
1684
+ *
1685
+ * Returns _dec_ truncated to an +Integer+.
1686
+ */
1424
1687
  static VALUE
1425
1688
  dec_to_i(VALUE num)
1426
1689
  {
@@ -1428,113 +1691,315 @@ dec_to_i(VALUE num)
1428
1691
  VALUE inum;
1429
1692
 
1430
1693
  GetDecimal(num, d);
1431
- do_round(d, 0, ROUND_DOWN, &inum); /* identical to "d.round(0, :down)" */
1694
+ do_round(d, 0, ROUND_DOWN, &inum); /* equal to "d.round(0, :down)" */
1432
1695
  return inum;
1433
- }
1696
+ }
1434
1697
 
1435
1698
  static VALUE
1436
1699
  rounding_method(int argc, VALUE *argv, VALUE x, VALUE mode)
1437
1700
  {
1438
1701
  Decimal *d;
1439
- VALUE scale, inum;
1702
+ VALUE vscale, inum;
1703
+ long scale = 0;
1440
1704
 
1441
- rb_scan_args(argc, argv, "01", &scale);
1705
+ rb_scan_args(argc, argv, "01", &vscale);
1442
1706
  GetDecimal(x, d);
1443
- if (argc == 0) {
1444
- do_round(d, 0, mode, &inum);
1707
+ if (argc == 1) scale = NUM2LONG(vscale);
1708
+ if (scale <= 0) {
1709
+ do_round(d, scale, mode, &inum);
1445
1710
  return inum;
1446
1711
  }
1447
- return WrapDecimal(do_round(d, NUM2LONG(scale), mode, 0));
1712
+ return WrapDecimal(do_round(d, scale, mode, NULL));
1448
1713
  }
1449
1714
 
1715
+ /*
1716
+ * call-seq:
1717
+ * dec.truncate(n=0) => integer or decimal
1718
+ *
1719
+ * Returns _dec_ truncated to an +Integer+.
1720
+ *
1721
+ * This is identical to <code>dec.round(n, Decimal::ROUND_DOWN)</code>.
1722
+ * See <code>Decimal#round</code> for more details.
1723
+ */
1450
1724
  static VALUE
1451
1725
  dec_truncate(int argc, VALUE *argv, VALUE x)
1452
1726
  {
1453
1727
  return rounding_method(argc, argv, x, ROUND_DOWN);
1454
1728
  }
1455
1729
 
1730
+ /*
1731
+ * call-seq:
1732
+ * dec.floor(n=0) => integer or decimal
1733
+ *
1734
+ * Returns the largest integer less than or equal to _dec_.
1735
+ *
1736
+ * Decimal("1.2").floor #=> 1
1737
+ * Decimal("2.0").floor #=> 2
1738
+ * Decimal("-1.2").floor #=> -2
1739
+ * Decimal("-2.0").floor #=> -2
1740
+ *
1741
+ * This is identical to <code>dec.round(n, Decimal::ROUND_FLOOR)</code>.
1742
+ * See <code>Decimal#round</code> for more details.
1743
+ */
1456
1744
  static VALUE
1457
1745
  dec_floor(int argc, VALUE *argv, VALUE x)
1458
1746
  {
1459
1747
  return rounding_method(argc, argv, x, ROUND_FLOOR);
1460
1748
  }
1461
1749
 
1750
+ /*
1751
+ * call-seq:
1752
+ * dec.ceil(n=0) => integer or decimal
1753
+ *
1754
+ * Returns the smallest +Integer+ greater than or equal to _dec_.
1755
+ *
1756
+ * Decimal("1.2").ceil #=> 2
1757
+ * Decimal("2.0").ceil #=> 2
1758
+ * Decimal("-1.2").ceil #=> -1
1759
+ * Decimal("-2.0").ceil #=> -2
1760
+ *
1761
+ * This is identical to <code>dec.round(n, Decimal::ROUND_CEILING)</code>.
1762
+ * See <code>Decimal#round</code> for more details.
1763
+ */
1462
1764
  static VALUE
1463
1765
  dec_ceil(int argc, VALUE *argv, VALUE x)
1464
1766
  {
1465
1767
  return rounding_method(argc, argv, x, ROUND_CEILING);
1466
1768
  }
1467
1769
 
1770
+ /*
1771
+ * call-seq:
1772
+ * dec.round(n=0, mode=Decimal::ROUND_HALF_UP) => integer or decimal
1773
+ *
1774
+ * *FIXME*: more examples
1775
+ *
1776
+ * Rounds _dec_ to a given precision _n_ in decimal digits (default 0 digits)
1777
+ * with rounding mode _mode_. Precision may be negative. Returns a
1778
+ * +Decimal+ when _n_ is greater than 0, +Integer+ otherwise.
1779
+ *
1780
+ * Decimal("1.5").round #=> 2
1781
+ * Decimal("-1.5").round #=> -2
1782
+ */
1468
1783
  static VALUE
1469
1784
  dec_round(int argc, VALUE *argv, VALUE x)
1470
1785
  {
1471
1786
  Decimal *d;
1472
- VALUE vscale;
1787
+ VALUE vscale, mode;
1473
1788
  long scale = 0;
1474
- VALUE mode = ROUND_HALF_UP, tmpmode;
1475
1789
 
1476
- rb_scan_args(argc, argv, "02", &vscale, &tmpmode);
1790
+ rb_scan_args(argc, argv, "02", &vscale, &mode);
1477
1791
  switch (argc) {
1478
1792
  case 2:
1479
1793
  Check_Type(mode, T_SYMBOL);
1480
- if (!valid_rounding_mode(mode)) {
1794
+ if (!valid_rounding_mode_p(mode)) {
1481
1795
  rb_raise(rb_eArgError, "invalid rounding mode %s",
1482
- RSTRING(rb_inspect(mode))->ptr);
1796
+ RSTRING_PTR(rb_inspect(mode)));
1483
1797
  }
1484
- mode = tmpmode;
1485
1798
  /* fall through */
1486
1799
  case 1:
1487
1800
  scale = NUM2LONG(vscale);
1488
1801
  /* fall through */
1489
1802
  default:
1803
+ if (NIL_P(mode)) mode = ROUND_HALF_UP;
1490
1804
  break;
1491
1805
  }
1492
1806
  GetDecimal(x, d);
1493
- if (scale == 0) {
1807
+ if (scale <= 0) {
1494
1808
  VALUE inum;
1495
1809
 
1496
1810
  do_round(d, scale, mode, &inum);
1497
1811
  return inum;
1498
1812
  }
1499
- return WrapDecimal(do_round(d, scale, mode, 0));
1813
+ return WrapDecimal(do_round(d, scale, mode, NULL));
1500
1814
  }
1501
1815
 
1502
1816
 
1817
+ /*
1818
+ * call-seq:
1819
+ * dec.nan? => true or false
1820
+ *
1821
+ * Returns +true+ if _dec_ is an invalid point number, NaN.
1822
+ *
1823
+ * Decimal(-1).nan? #=> false
1824
+ * Decimal(1).divide(0).nan? #=> false
1825
+ * Decimal(0).divide(0).nan? #=> true
1826
+ */
1503
1827
  static VALUE
1504
1828
  dec_nan_p(VALUE num)
1505
1829
  {
1506
- Decimal *d;
1507
-
1508
- GetDecimal(num, d);
1509
- return d == DEC_NaN ? Qtrue : Qfalse;
1830
+ return num == VALUE_NaN;
1510
1831
  }
1511
1832
 
1833
+ /*
1834
+ * call-seq:
1835
+ * dec.finite? => true or false
1836
+ *
1837
+ * Returns +true+ if _dec_ is a finite number (it is not infinite
1838
+ * nor NaN).
1839
+ *
1840
+ * Decimal(0).finite? #=> true
1841
+ * Decimal(1).divide(0).finite? #=> false
1842
+ * Decimal(0).divide(0).finite? #=> false
1843
+ */
1512
1844
  static VALUE
1513
1845
  dec_finite_p(VALUE num)
1514
1846
  {
1515
- Decimal *d;
1516
-
1517
- GetDecimal(num, d);
1518
- return !DEC_IMMEDIATE_P(d) ? Qtrue : Qfalse;
1847
+ if (!DEC_VALUE_ISINF(num) && num != VALUE_NaN) {
1848
+ return Qtrue;
1849
+ }
1850
+ return Qfalse;
1519
1851
  }
1520
1852
 
1853
+ /*
1854
+ * call-seq:
1855
+ * dec.infinite? => nil, -1, +1
1856
+ *
1857
+ * Returns +nil+, -1, or +1 depending on whether _dec_ is finite,
1858
+ * -infinity, or +infinity.
1859
+ *
1860
+ * Decimal(0).infinite? #=> nil
1861
+ * Decimal(-1).divide(0).infinite? #=> -1
1862
+ * Decimal(+1).divide(0).infinite? #=> 1
1863
+ */
1521
1864
  static VALUE
1522
1865
  dec_infinite_p(VALUE num)
1523
1866
  {
1524
- Decimal *d;
1525
-
1526
- GetDecimal(num, d);
1527
- if (d == DEC_PINF) return INT2FIX(1);
1528
- if (d == DEC_NINF) return INT2FIX(-1);
1867
+ if (num == VALUE_PINF) return INT2FIX(1);
1868
+ if (num == VALUE_NINF) return INT2FIX(-1);
1529
1869
  return Qnil;
1530
1870
  }
1531
1871
 
1872
+
1873
+ /*
1874
+ * Mathematical part
1875
+ */
1876
+ static VALUE mMath;
1877
+
1878
+ /* :nodoc: */
1879
+ static VALUE
1880
+ math_ldexp10(VALUE module UNUSED, VALUE x, VALUE exp)
1881
+ {
1882
+ int integer;
1883
+ long lexp;
1884
+ Decimal *d, *d2;
1885
+
1886
+ lexp = NUM2LONG(exp);
1887
+ if (lexp == 0)
1888
+ return x;
1889
+ CHECK_NAN(x);
1890
+ if (DEC_VALUE_ISINF(x))
1891
+ return x;
1892
+
1893
+ if (TYPE(x) == T_FIXNUM || TYPE(x) == T_BIGNUM) {
1894
+ integer = Qtrue;
1895
+ d = inum_to_dec(x);
1896
+ }
1897
+ else {
1898
+ integer = Qfalse;
1899
+ GetDecimal(x, d);
1900
+ }
1901
+ if (lexp > 0 && LONG_MIN + lexp > d->scale)
1902
+ rb_raise(rb_eArgError, "%ld is too big", lexp);
1903
+ if (lexp < 0 && LONG_MAX + lexp < d->scale)
1904
+ rb_raise(rb_eArgError, "%ld is too small", lexp);
1905
+ d2 = finite_dup(d);
1906
+ d2->scale = d->scale - lexp;
1907
+ if (integer) xfree(d);
1908
+ return WrapDecimal(d2);
1909
+ }
1910
+
1911
+ /* :nodoc: */
1912
+ static VALUE
1913
+ math_frexp10(VALUE module UNUSED, VALUE x)
1914
+ {
1915
+ int negative, integer;
1916
+ long exp;
1917
+ VALUE inum;
1918
+ Decimal *d, *mant;
1919
+ static const Decimal *min = NULL /* to be 0.1 */, *max; /* to be 1 */
1920
+
1921
+ CHECK_NAN_WITH_VAL(x, rb_assoc_new(VALUE_NaN, INT2FIX(0)));
1922
+ if (DEC_VALUE_ISINF(x))
1923
+ return rb_assoc_new(x, INT2FIX(0));
1924
+
1925
+ if (TYPE(x) == T_FIXNUM || TYPE(x) == T_BIGNUM) {
1926
+ integer = Qtrue;
1927
+ d = inum_to_dec(x);
1928
+ }
1929
+ else {
1930
+ integer = Qfalse;
1931
+ GetDecimal(x, d);
1932
+ }
1933
+ if (DEC_ZERO_P(d)) {
1934
+ if (integer) xfree(d);
1935
+ return rb_assoc_new(x, INT2FIX(0));
1936
+ }
1937
+
1938
+ if (INUM_NEGATIVE_P(d->inum)) {
1939
+ negative = Qtrue;
1940
+ inum = INUM_UMINUS(d->inum);
1941
+ } else {
1942
+ negative = Qfalse;
1943
+ inum = d->inum;
1944
+ }
1945
+ mant = dec_raw_new(inum, d->scale);
1946
+ exp = 0;
1947
+ if (min == NULL) {
1948
+ min = dec_raw_new(INT2FIX(1), 1); /* 0.1 */
1949
+ max = dec_raw_new(INT2FIX(1), 0); /* 1 */
1950
+ }
1951
+ if (normal_cmp(mant, min) < 0) {
1952
+ do {
1953
+ mant->scale--;
1954
+ exp--;
1955
+ } while (normal_cmp(mant, min) < 0);
1956
+ goto coda;
1957
+ }
1958
+ if (normal_cmp(mant, max) >= 0) {
1959
+ do {
1960
+ mant->scale++;
1961
+ exp++;
1962
+ } while (normal_cmp(mant, max) >= 0);
1963
+ goto coda;
1964
+ }
1965
+ /* x is already normalized, return untouched */
1966
+ return rb_assoc_new(x, INT2FIX(0));
1967
+ coda:
1968
+ /* normalized with changing some values */
1969
+ if (integer) xfree(d);
1970
+ if (negative) mant->inum = INUM_UMINUS(mant->inum);
1971
+ return rb_assoc_new(WrapDecimal(mant), LONG2NUM(exp));
1972
+ }
1973
+
1974
+ /* initialize minimum Math functions in C */
1975
+ static void
1976
+ init_math(void)
1977
+ {
1978
+ mMath = rb_define_module_under(cDecimal, "Math");
1979
+ rb_define_module_function(mMath, "ldexp10", math_ldexp10, 2);
1980
+ rb_define_module_function(mMath, "frexp10", math_frexp10, 1);
1981
+ }
1982
+
1983
+
1984
+ /*
1985
+ * +Decimal+ is a decimal fraction that holds exact number in the decimal
1986
+ * system unlike +Float+. It can hold multi-precision digits, so you can
1987
+ * calculate any detailed number as you likes.
1988
+ *
1989
+ * *FIXME*: write exceptions raised by Float and details about scales
1990
+ */
1532
1991
  void
1533
1992
  Init_decimal(void)
1534
1993
  {
1535
1994
  cDecimal = rb_define_class("Decimal", rb_cNumeric);
1995
+ /* Raised when infinite or NaN was rounded. */
1536
1996
  eDomainError = rb_define_class_under(cDecimal, "DomainError",
1537
1997
  rb_eRangeError);
1998
+ /*
1999
+ * Raised when rounding is necessary in spite of a constant
2000
+ * <code>Decimal::ROUND_UNNECESSARY</code> was passed to
2001
+ * <code>Decimal#round</code>.
2002
+ */
1538
2003
  eArithmeticError = rb_define_class_under(cDecimal, "ArithmeticError",
1539
2004
  rb_eStandardError);
1540
2005
 
@@ -1543,36 +2008,51 @@ Init_decimal(void)
1543
2008
  rb_define_alloc_func(cDecimal, dec_s_allocate);
1544
2009
  rb_define_method(cDecimal, "initialize", dec_initialize, 1);
1545
2010
 
1546
- /* Singleton objects, should not be freed */
1547
- /* FIXME: register objects to prevent GC */
1548
- VALUE_PINF = Data_Wrap_Struct(cDecimal, NULL, NULL, DEC_PINF);
1549
- VALUE_NINF = Data_Wrap_Struct(cDecimal, NULL, NULL, DEC_NINF);
1550
- VALUE_NaN = Data_Wrap_Struct(cDecimal, NULL, NULL, DEC_NaN);
2011
+ /* static objects, should not be freed */
2012
+ VALUE_PINF = WrapStatic(DEC_PINF);
2013
+ VALUE_NINF = WrapStatic(DEC_NINF);
2014
+ VALUE_NaN = WrapStatic(DEC_NaN);
2015
+ /* and register them with GC */
1551
2016
  rb_global_variable(&VALUE_PINF);
1552
2017
  rb_global_variable(&VALUE_NINF);
1553
2018
  rb_global_variable(&VALUE_NaN);
1554
-
1555
- #define DEF_ROUNDING_MODE(MODE, mode) do { \
1556
- ROUND_ ## MODE = ID2SYM(rb_intern(#mode)); \
1557
- rb_define_const(cDecimal, "ROUND_" #MODE, ROUND_ ## MODE); \
1558
- } while (0)
1559
- DEF_ROUNDING_MODE(CEILING, ceiling);
1560
- DEF_ROUNDING_MODE(DOWN, down);
1561
- DEF_ROUNDING_MODE(FLOOR, floor);
1562
- DEF_ROUNDING_MODE(HALF_DOWN, half_down);
1563
- DEF_ROUNDING_MODE(HALF_EVEN, half_even);
1564
- DEF_ROUNDING_MODE(HALF_UP, half_up);
1565
- DEF_ROUNDING_MODE(UP, up);
1566
- DEF_ROUNDING_MODE(UNNECESSARY, unnecessary);
2019
+ /* then define as constants */
2020
+ rb_define_const(cDecimal, "INFINITY", VALUE_PINF);
2021
+ rb_define_const(cDecimal, "NAN", VALUE_NaN);
2022
+
2023
+ /* generated by:
2024
+ * %w(ceiling down floor half_down half_even half_up up
2025
+ * unnecessary).each do |s|
2026
+ * r = "ROUND_#{s.upcase}"
2027
+ * puts %(#{r} = ID2SYM(rb_intern("#{s}"));)
2028
+ * puts %(rb_define_const(cDecimal, "#{r}", #{r});)
2029
+ * end
2030
+ */
2031
+ ROUND_CEILING = ID2SYM(rb_intern("ceiling"));
2032
+ rb_define_const(cDecimal, "ROUND_CEILING", ROUND_CEILING);
2033
+ ROUND_DOWN = ID2SYM(rb_intern("down"));
2034
+ rb_define_const(cDecimal, "ROUND_DOWN", ROUND_DOWN);
2035
+ ROUND_FLOOR = ID2SYM(rb_intern("floor"));
2036
+ rb_define_const(cDecimal, "ROUND_FLOOR", ROUND_FLOOR);
2037
+ ROUND_HALF_DOWN = ID2SYM(rb_intern("half_down"));
2038
+ rb_define_const(cDecimal, "ROUND_HALF_DOWN", ROUND_HALF_DOWN);
2039
+ ROUND_HALF_EVEN = ID2SYM(rb_intern("half_even"));
2040
+ rb_define_const(cDecimal, "ROUND_HALF_EVEN", ROUND_HALF_EVEN);
2041
+ ROUND_HALF_UP = ID2SYM(rb_intern("half_up"));
2042
+ rb_define_const(cDecimal, "ROUND_HALF_UP", ROUND_HALF_UP);
2043
+ ROUND_UP = ID2SYM(rb_intern("up"));
2044
+ rb_define_const(cDecimal, "ROUND_UP", ROUND_UP);
2045
+ ROUND_UNNECESSARY = ID2SYM(rb_intern("unnecessary"));
2046
+ rb_define_const(cDecimal, "ROUND_UNNECESSARY", ROUND_UNNECESSARY);
1567
2047
 
1568
2048
  #ifdef DEBUG
1569
2049
  rb_define_method(cDecimal, "scale", dec_scale, 0);
1570
2050
  rb_define_method(cDecimal, "unscaled_value", dec_unscaled_value, 0);
1571
- #endif
1572
2051
  rb_define_method(cDecimal, "strip_trailing_zeros",
1573
2052
  dec_strip_trailing_zeros, 0);
1574
2053
  rb_define_method(cDecimal, "strip", dec_strip_trailing_zeros, 0);
1575
-
2054
+ #endif
2055
+
1576
2056
  rb_define_method(cDecimal, "to_s", dec_to_s, 0);
1577
2057
  rb_define_method(cDecimal, "inspect", dec_inspect, 0);
1578
2058
  rb_define_method(cDecimal, "coerce", dec_coerce, 1);
@@ -1602,7 +2082,6 @@ Init_decimal(void)
1602
2082
  rb_define_method(cDecimal, "zero?", dec_zero_p, 0);
1603
2083
 
1604
2084
  rb_define_method(cDecimal, "to_i", dec_to_i, 0);
1605
- rb_define_method(cDecimal, "to_int", dec_to_i, 0);
1606
2085
  rb_define_method(cDecimal, "truncate", dec_truncate, -1);
1607
2086
  rb_define_method(cDecimal, "floor", dec_floor, -1);
1608
2087
  rb_define_method(cDecimal, "ceil", dec_ceil, -1);
@@ -1611,4 +2090,6 @@ Init_decimal(void)
1611
2090
  rb_define_method(cDecimal, "nan?", dec_nan_p, 0);
1612
2091
  rb_define_method(cDecimal, "finite?", dec_finite_p, 0);
1613
2092
  rb_define_method(cDecimal, "infinite?", dec_infinite_p, 0);
2093
+
2094
+ init_math();
1614
2095
  }