decimal 0.0.2 → 0.0.90.pre

Sign up to get free protection for your applications and to get access to all the features.
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
  }