decimal 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (10) hide show
  1. data/COPYING +57 -0
  2. data/GPL +340 -0
  3. data/INSTALL +5 -0
  4. data/README +1 -0
  5. data/decimal.c +1614 -0
  6. data/decimal.gemspec +17 -0
  7. data/depend +3 -0
  8. data/extconf.rb +3 -0
  9. data/inum18.h +302 -0
  10. metadata +63 -0
data/COPYING ADDED
@@ -0,0 +1,57 @@
1
+ Decimal is copyrighted free software by Tadashi Saito <shiba AT
2
+ mail2.accsnet.ne.jp>.
3
+ You can redistribute it and/or modify it under either the terms of the GPL
4
+ version 2 (see the file GPL), or the conditions below:
5
+
6
+ 1. You may make and give away verbatim copies of the source form of the
7
+ software without restriction, provided that you duplicate all of the
8
+ original copyright notices and associated disclaimers.
9
+
10
+ 2. You may modify your copy of the software in any way, provided that
11
+ you do at least ONE of the following:
12
+
13
+ a) place your modifications in the Public Domain or otherwise
14
+ make them Freely Available, such as by posting said
15
+ modifications to Usenet or an equivalent medium, or by allowing
16
+ the author to include your modifications in the software.
17
+
18
+ b) use the modified software only within your corporation or
19
+ organization.
20
+
21
+ c) give non-standard binaries non-standard names, with
22
+ instructions on where to get the original software distribution.
23
+
24
+ d) make other distribution arrangements with the author.
25
+
26
+ 3. You may distribute the software in object code or binary form,
27
+ provided that you do at least ONE of the following:
28
+
29
+ a) distribute the binaries and library files of the software,
30
+ together with instructions (in the manual page or equivalent)
31
+ on where to get the original distribution.
32
+
33
+ b) accompany the distribution with the machine-readable source of
34
+ the software.
35
+
36
+ c) give non-standard binaries non-standard names, with
37
+ instructions on where to get the original software distribution.
38
+
39
+ d) make other distribution arrangements with the author.
40
+
41
+ 4. You may modify and include the part of the software into any other
42
+ software (possibly commercial). But some files in the distribution
43
+ are not written by the author, so that they are not under these terms.
44
+
45
+ For the list of those files and their copying conditions, see the
46
+ file LEGAL.
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
data/GPL ADDED
@@ -0,0 +1,340 @@
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Library General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ <one line to give the program's name and a brief idea of what it does.>
294
+ Copyright (C) <year> <name of author>
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License
307
+ along with this program; if not, write to the Free Software
308
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
309
+
310
+
311
+ Also add information on how to contact you by electronic and paper mail.
312
+
313
+ If the program is interactive, make it output a short notice like this
314
+ when it starts in an interactive mode:
315
+
316
+ Gnomovision version 69, Copyright (C) year name of author
317
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
318
+ This is free software, and you are welcome to redistribute it
319
+ under certain conditions; type `show c' for details.
320
+
321
+ The hypothetical commands `show w' and `show c' should show the appropriate
322
+ parts of the General Public License. Of course, the commands you use may
323
+ be called something other than `show w' and `show c'; they could even be
324
+ mouse-clicks or menu items--whatever suits your program.
325
+
326
+ You should also get your employer (if you work as a programmer) or your
327
+ school, if any, to sign a "copyright disclaimer" for the program, if
328
+ necessary. Here is a sample; alter the names:
329
+
330
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
331
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
332
+
333
+ <signature of Ty Coon>, 1 April 1989
334
+ Ty Coon, President of Vice
335
+
336
+ This General Public License does not permit incorporating your program into
337
+ proprietary programs. If your program is a subroutine library, you may
338
+ consider it more useful to permit linking proprietary applications with the
339
+ library. If this is what you want to do, use the GNU Library General
340
+ Public License instead of this License.
data/INSTALL ADDED
@@ -0,0 +1,5 @@
1
+ $ ruby extconf.rb
2
+ $ make
3
+ $ su
4
+ # make install
5
+
data/README ADDED
@@ -0,0 +1 @@
1
+ ALL YOUR DECIMAL BASE ARE BELONG TO US
data/decimal.c ADDED
@@ -0,0 +1,1614 @@
1
+ /*
2
+ * decimal.c - implementation of Decimal,
3
+ * a multi-precision decimal arithmetic library
4
+ *
5
+ * Copyright (C) 2003-2008 Tadashi Saito
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.
17
+ */
18
+
19
+ #include <ctype.h>
20
+ #include <float.h>
21
+ #include <math.h>
22
+ #include <stdio.h>
23
+ #include <string.h>
24
+
25
+ #include <ruby.h>
26
+ #include <rubysig.h>
27
+ #include <version.h>
28
+ #include <util.h>
29
+
30
+ /*
31
+ * unfortunately, a few copies of Integer functions
32
+ * are needed from original Ruby
33
+ */
34
+ #include "inum18.h"
35
+
36
+ /*
37
+ * INUM_* macros: receive both Fixnum and Bignum,
38
+ * to operate Integers transparently
39
+ */
40
+ #define INUM_PLUS(a, b) \
41
+ (FIXNUM_P(a) ? fix_plus(a, b) : rb_big_plus(a, b))
42
+ #define INUM_MINUS(a, b) \
43
+ (FIXNUM_P(a) ? fix_minus(a, b) : rb_big_minus(a, b))
44
+ #define INUM_MUL(a, b) \
45
+ (FIXNUM_P(a) ? fix_mul(a, b) : rb_big_mul(a, b))
46
+ #define INUM_DIV(a, b) \
47
+ (FIXNUM_P(a) ? fix_div(a, b) : RARRAY(rb_big_divmod(a, b))->ptr[0])
48
+ #define INUM_DIVMOD(a, b) \
49
+ (FIXNUM_P(a) ? fix_divmod(a, b) : rb_big_divmod(a, b))
50
+ #define INUM_EQ(a, b) \
51
+ (FIXNUM_P(a) ? fix_equal(a, b) : rb_big_eq(a, b))
52
+ #define INUM_CMP(a, b) \
53
+ (FIXNUM_P(a) ? fix_cmp(a, b) : rb_big_cmp(a, b))
54
+ #define INUM_UMINUS(n) \
55
+ (FIXNUM_P(n) ? LONG2NUM(-FIX2LONG(n)) : big_uminus(n))
56
+ #define INUM_HASH(n) \
57
+ (FIXNUM_P(n) ? LONG2NUM((long)n) : rb_big_hash(n))
58
+ #define INUM2STR(n) \
59
+ (FIXNUM_P(n) ? rb_fix2str(n, 10) : rb_big2str(n, 10))
60
+
61
+ #define INUM_INC(n) do { n = INUM_PLUS(n, INT2FIX(1)); } while (0)
62
+ #define INUM_DEC(n) do { n = INUM_MINUS(n, INT2FIX(1)); } while (0)
63
+ #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)
65
+ #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)
68
+
69
+ /* the body */
70
+ typedef struct {
71
+ VALUE inum;
72
+ long scale;
73
+ } Decimal;
74
+
75
+ /* singleton objects for NaN, +Infinity, -Infinity */
76
+ static Decimal *const DEC_NaN = (Decimal *)1;
77
+ static Decimal *const DEC_PINF = (Decimal *)3;
78
+ static Decimal *const DEC_NINF = (Decimal *)7;
79
+ /* and their representation as Ruby object */
80
+ static VALUE VALUE_NaN, VALUE_PINF, VALUE_NINF;
81
+
82
+ /* special constants - i.e. non-zero and non-fixnum constants */
83
+ /* used for signed zeros that never meet any fixnums nor normal VALUEs */
84
+ 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))
87
+
88
+ #define DEC_ISINF(d) ((d) == DEC_PINF || (d) == DEC_NINF)
89
+ /* immediate means non-finite */
90
+ #define DEC_IMMEDIATE_P(d) (DEC_ISINF(d) || d == DEC_NaN)
91
+ /* special signed zeros */
92
+ #define DEC_ZERO_P(d) ((d)->inum == DEC_PZERO || (d)->inum == DEC_NZERO)
93
+ #define INUM_SPZERO_P(n) ((n) == DEC_PZERO || (n) == DEC_NZERO)
94
+
95
+ /* all rounding modes, corresponding to DEF_ROUNDING_MODE() */
96
+ static VALUE ROUND_CEILING;
97
+ static VALUE ROUND_DOWN;
98
+ static VALUE ROUND_FLOOR;
99
+ static VALUE ROUND_HALF_DOWN;
100
+ static VALUE ROUND_HALF_EVEN;
101
+ static VALUE ROUND_HALF_UP;
102
+ static VALUE ROUND_UP;
103
+ static VALUE ROUND_UNNECESSARY;
104
+
105
+ #define GetDecimal(obj, d) do { \
106
+ Data_Get_Struct(obj, Decimal, d); \
107
+ if (d == NULL) rb_raise(rb_eArgError, "uninitialized Decimal object"); \
108
+ } 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)
113
+ #define DECIMAL_P(d) (CLASS_OF(d) == cDecimal)
114
+
115
+ static VALUE cDecimal;
116
+ static VALUE eDomainError;
117
+ static VALUE eArithmeticError;
118
+
119
+ /* mark if d->inum is Bignum */
120
+ static void
121
+ dec_mark(void *p)
122
+ {
123
+ const Decimal *const d = p;
124
+
125
+ if (d == NULL) return; /* uninitialized object */
126
+ if (!FIXNUM_P(d->inum) && !INUM_SPZERO_P(d->inum)) {
127
+ rb_gc_mark(d->inum); /* mark a Bignum */
128
+ }
129
+ }
130
+
131
+ #ifndef DEBUG
132
+ #define dec_free (-1) /* just xfree() the objects */
133
+ #else
134
+ static void
135
+ dec_free(void *p)
136
+ {
137
+ static void *prev = NULL;
138
+
139
+ if (p == prev) {
140
+ fprintf(stderr, "dec_free(): double-free occurred on %p\n", p);
141
+ }
142
+ xfree(p);
143
+ prev = p;
144
+ }
145
+ #endif
146
+
147
+ static Decimal *
148
+ inum_to_dec(VALUE x)
149
+ {
150
+ Decimal *d = ALLOC(Decimal);
151
+
152
+ d = ALLOC(Decimal);
153
+ if (INUM_ZERO_P(x)) d->inum = DEC_PZERO;
154
+ else d->inum = x;
155
+ d->scale = 0;
156
+ return d;
157
+ }
158
+
159
+ static VALUE
160
+ cstr_to_inum(VALUE str)
161
+ {
162
+ return rb_cstr_to_inum((const char *)str, 10, Qtrue);
163
+ }
164
+
165
+ static VALUE
166
+ invalid_str(VALUE arg)
167
+ {
168
+ VALUE *assoc = (VALUE *)arg;
169
+
170
+ xfree((char *)assoc[0]);
171
+ rb_invalid_str((const char *)assoc[1], "Decimal");
172
+ return Qnil; /* not reached */
173
+ }
174
+
175
+ static Decimal *
176
+ cstr_to_dec(const char *str)
177
+ {
178
+ Decimal *d;
179
+ char *const s = strdup(str);
180
+ char *ss, *ss2;
181
+ long scale = 0;
182
+ VALUE inum, assoc[2];
183
+
184
+ assoc[0] = (VALUE)s;
185
+ 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);
190
+ }
191
+ if (ss = strchr(s, '.')) {
192
+ const char *p;
193
+
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
+ }
209
+ }
210
+ inum = rb_rescue(cstr_to_inum, (VALUE)s, invalid_str, (VALUE)assoc);
211
+ d = ALLOC(Decimal);
212
+ if (INUM_ZERO_P(inum)) {
213
+ d->inum = strchr(s, '-') ? DEC_NZERO : DEC_PZERO;
214
+ }
215
+ else d->inum = inum;
216
+ d->scale = scale;
217
+ xfree(s);
218
+ return d;
219
+ }
220
+
221
+ static Decimal *
222
+ finite_dup(Decimal *d)
223
+ {
224
+ Decimal *d2 = ALLOC(Decimal);
225
+
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 */
229
+ }
230
+ return d2;
231
+ }
232
+
233
+ static Decimal *
234
+ create_dec(VALUE arg)
235
+ {
236
+ switch (TYPE(arg)) {
237
+ case T_FIXNUM:
238
+ case T_BIGNUM:
239
+ return inum_to_dec(arg);
240
+ 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 */
252
+ case T_FLOAT:
253
+ rb_raise(rb_eArgError, "invalid value Float(%s) for Decimal",
254
+ RSTRING(rb_inspect(arg))->ptr);
255
+ default:
256
+ rb_raise(rb_eArgError, "invalid value for Decimal: %s",
257
+ RSTRING(rb_inspect(arg))->ptr);
258
+ }
259
+ return NULL; /* not reached */
260
+ }
261
+
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 */
270
+ static VALUE
271
+ dec_s_allocate(VALUE klass)
272
+ {
273
+ return Data_Wrap_Struct(klass, dec_mark, dec_free, NULL);
274
+ }
275
+
276
+ /* TODO: check whether arg is a Decimal or not */
277
+ static VALUE
278
+ dec_initialize(VALUE self, VALUE arg)
279
+ {
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;
284
+ }
285
+ DATA_PTR(self) = d;
286
+ return self;
287
+ }
288
+
289
+ #ifdef DEBUG
290
+ static VALUE
291
+ dec_scale(VALUE self)
292
+ {
293
+ Decimal *d;
294
+
295
+ GetDecimal(self, d);
296
+ if (!DEC_IMMEDIATE_P(d)) return LONG2NUM(d->scale);
297
+ return Qnil;
298
+ }
299
+
300
+ static VALUE
301
+ dec_unscaled_value(VALUE self)
302
+ {
303
+ Decimal *d;
304
+
305
+ GetDecimal(self, d);
306
+ if (!DEC_IMMEDIATE_P(d)) {
307
+ return INUM_SPZERO_P(d->inum) ? INT2FIX(0) : d->inum;
308
+ }
309
+ return Qnil;
310
+ }
311
+ #endif
312
+
313
+ static VALUE
314
+ dec_strip_trailing_zeros(VALUE self)
315
+ {
316
+ Decimal *d, *d2;
317
+
318
+ GetDecimal(self, d);
319
+ if (DEC_IMMEDIATE_P(d))
320
+ return self;
321
+ if (INUM_SPZERO_P(d->inum)) { /* XXX: negative scale? */
322
+ if (d->scale <= 0) return self;
323
+ d2 = finite_dup(d);
324
+ d2->scale = 0;
325
+ return WrapDecimal(d2);
326
+ }
327
+ d2 = ALLOC(Decimal);
328
+ *d2 = *d;
329
+ /* TODO: can be optimized with dividing each part
330
+ * for Bignums and Fixnums */
331
+ while (INUM_BOTTOMDIG(d2->inum) == 0) {
332
+ d2->inum = INUM_DIV(d2->inum, INT2FIX(10));
333
+ d2->scale--;
334
+ }
335
+ return WrapDecimal(d2);
336
+ }
337
+
338
+ /* FIXME: should return "%g" format string */
339
+ static VALUE
340
+ finite_to_s(Decimal *d)
341
+ {
342
+ const VALUE str = INUM2STR(d->inum);
343
+ const char *s = RSTRING(str)->ptr;
344
+ const long slen = RSTRING(str)->len;
345
+ const long scale = d->scale;
346
+ long snumlen, sslen, diff;
347
+ int negative;
348
+ char *ss; /* source of newstr */
349
+ VALUE newstr; /* to be returned */
350
+
351
+ if (scale == 0) return str;
352
+ if (scale < 0) { /* "xx00" */
353
+ sslen = slen - scale;
354
+ ss = ALLOC_N(char, sslen);
355
+ memcpy(ss, s, slen);
356
+ memset(ss+slen, '0', -scale);
357
+ goto coda;
358
+ }
359
+ negative = (*s == '-');
360
+ snumlen = negative ? slen-1 : slen;
361
+ if (scale < snumlen) { /* "xx.xx" */
362
+ diff = slen - scale;
363
+ sslen = slen + 1;
364
+ ss = ALLOC_N(char, sslen);
365
+ memcpy(ss, s, diff);
366
+ ss[diff] = '.';
367
+ memcpy(ss+diff+1, s+diff, scale);
368
+ }
369
+ else { /* "0.00xx" */
370
+ char *ss2; /* alias of ss */
371
+
372
+ diff = scale - snumlen;
373
+ /* "0." + "00..." + "-?xx" */
374
+ sslen = 2 + diff + slen;
375
+ ss = ss2 = ALLOC_N(char, sslen);
376
+ if (negative) *ss2++ = '-', s++;
377
+ memcpy(ss2, "0.", 2);
378
+ ss2 += 2;
379
+ if (diff) memset(ss2, '0', diff);
380
+ memcpy(ss2+diff, s, snumlen);
381
+ }
382
+ coda:
383
+ newstr = rb_str_new(ss, sslen);
384
+ xfree(ss);
385
+ return newstr;
386
+ }
387
+
388
+ static VALUE
389
+ dec_to_s(VALUE self)
390
+ {
391
+ Decimal *d;
392
+
393
+ 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");
399
+ return finite_to_s(d);
400
+ }
401
+
402
+ static VALUE
403
+ dec_inspect(VALUE self)
404
+ {
405
+ char *s;
406
+ VALUE str, newstr;
407
+ long len;
408
+
409
+ str = dec_to_s(self);
410
+ len = 9 + RSTRING(str)->len; /* 9 == strlen("Decimal()") */
411
+ s = ALLOC_N(char, len + 1); /* +1 for NUL */
412
+ sprintf(s, "Decimal(%s)", RSTRING(str)->ptr);
413
+ newstr = rb_str_new(s, len);
414
+ xfree(s);
415
+ return newstr;
416
+ }
417
+
418
+ static VALUE
419
+ dec_coerce(VALUE x, VALUE y)
420
+ {
421
+ VALUE yy;
422
+
423
+ switch (TYPE(y)) {
424
+ case T_FIXNUM:
425
+ case T_BIGNUM:
426
+ yy = WrapDecimal(inum_to_dec(y));
427
+ return rb_assoc_new(yy, x);
428
+ case T_FLOAT:
429
+ rb_raise(rb_eTypeError, "can't coerce Float to Decimal; "
430
+ "use Decimal#to_f explicitly if needed");
431
+ break;
432
+ case T_DATA:
433
+ if (DECIMAL_P(y)) return rb_assoc_new(y, x);
434
+ /* fall through */
435
+ default:
436
+ rb_raise(rb_eTypeError, "can't coerce %s to Decimal",
437
+ rb_obj_classname(y));
438
+ break;
439
+ }
440
+ return Qnil; /* not reached */
441
+ }
442
+
443
+ static VALUE
444
+ dec_uminus(VALUE num)
445
+ {
446
+ Decimal *d, *d2;
447
+
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;
452
+
453
+ d2 = ALLOC(Decimal);
454
+ d2->scale = d->scale;
455
+ if (d->inum == DEC_PZERO)
456
+ d2->inum = DEC_NZERO;
457
+ else if (d->inum == DEC_NZERO)
458
+ d2->inum = DEC_PZERO;
459
+ else
460
+ d2->inum = INUM_UMINUS(d->inum);
461
+ return WrapDecimal(d2);
462
+ }
463
+
464
+ /* returns x * (10 ** n) */
465
+ static VALUE
466
+ inum_lshift(VALUE x, long n)
467
+ {
468
+ VALUE y;
469
+
470
+ if (n <= 0) rb_bug("inum_lshift(): not reached");
471
+ y = fix_pow(INT2FIX(10), LONG2NUM(n));
472
+ return INUM_MUL(x, y);
473
+ }
474
+
475
+ /* the "normal" number means "finite and nonzero." */
476
+ static Decimal *
477
+ normal_plus(Decimal *x, Decimal *y, const int add)
478
+ {
479
+ Decimal *z;
480
+ VALUE inum;
481
+ long scale;
482
+
483
+ if (x->scale == y->scale) {
484
+ inum = add ? INUM_PLUS(x->inum, y->inum)
485
+ : INUM_MINUS(x->inum, y->inum);
486
+ scale = x->scale;
487
+ }
488
+ else {
489
+ Decimal *max, *min;
490
+ VALUE min_inum;
491
+
492
+ if (x->scale > y->scale) max = x, min = y;
493
+ else max = y, min = x;
494
+ scale = max->scale;
495
+ 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 */
499
+ }
500
+ if (INUM_ZERO_P(inum)) inum = DEC_PZERO;
501
+ z = ALLOC(Decimal);
502
+ z->inum = inum;
503
+ z->scale = scale;
504
+ return z;
505
+ }
506
+
507
+ static VALUE
508
+ dec_plus(VALUE x, VALUE y)
509
+ {
510
+ Decimal *a, *b;
511
+
512
+ switch (TYPE(y)) {
513
+ case T_FIXNUM:
514
+ case T_BIGNUM:
515
+ b = inum_to_dec(y);
516
+ break;
517
+ case T_FLOAT:
518
+ rb_raise(rb_eTypeError, "can't operate with Float");
519
+ break;
520
+ case T_DATA:
521
+ if (DECIMAL_P(y)) {
522
+ GetDecimal(y, b);
523
+ if (b == DEC_NaN) return VALUE_NaN;
524
+ break;
525
+ }
526
+ /* fall through */
527
+ default:
528
+ return rb_num_coerce_bin(x, y);
529
+ }
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;
536
+ return x;
537
+ }
538
+ if (INUM_SPZERO_P(a->inum)) {
539
+ if (!DEC_IMMEDIATE_P(b) && DEC_ZERO_P(b)) { /* XXX */
540
+ if (a->inum == DEC_NZERO && b->inum == DEC_NZERO)
541
+ return dec_nzero(); /* FIXME: scale policy for 0? */
542
+ return dec_pzero(); /* FIXME: ditto */
543
+ }
544
+ return y;
545
+ }
546
+ if (DEC_ISINF(b)) return y;
547
+ if (INUM_SPZERO_P(b->inum)) return x; /* FIXME: ditto */
548
+ /* "true" means addition */
549
+ return WrapDecimal(normal_plus(a, b, Qtrue));
550
+ }
551
+
552
+ static VALUE
553
+ dec_minus(VALUE x, VALUE y)
554
+ {
555
+ Decimal *a, *b;
556
+
557
+ switch (TYPE(y)) {
558
+ case T_FIXNUM:
559
+ case T_BIGNUM:
560
+ b = inum_to_dec(y);
561
+ break;
562
+ case T_FLOAT:
563
+ rb_raise(rb_eTypeError, "can't operate with Float");
564
+ break;
565
+ case T_DATA:
566
+ if (DECIMAL_P(y)) {
567
+ GetDecimal(y, b);
568
+ if (b == DEC_NaN) return VALUE_NaN;
569
+ break;
570
+ }
571
+ /* fall through */
572
+ default:
573
+ return rb_num_coerce_bin(x, y);
574
+ }
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;
580
+ return x;
581
+ }
582
+ if (INUM_SPZERO_P(a->inum)) { /* FIXME: need to refactor */
583
+ if (!DEC_ISINF(b) && DEC_ZERO_P(b) && a->inum == b->inum) {
584
+ return dec_pzero(); /* FIXME: for scaling */
585
+ }
586
+ return dec_uminus(y);
587
+ }
588
+ if (DEC_ISINF(b)) return dec_uminus(y);
589
+ if (DEC_ZERO_P(b)) return x;
590
+ /* "false" means subtraction */
591
+ return WrapDecimal(normal_plus(a, b, Qfalse));
592
+ }
593
+
594
+ static Decimal *
595
+ normal_mul(Decimal *x, Decimal *y)
596
+ {
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;
602
+ }
603
+
604
+ static VALUE
605
+ dec_mul(VALUE x, VALUE y)
606
+ {
607
+ Decimal *a, *b;
608
+
609
+ switch (TYPE(y)) {
610
+ case T_FIXNUM:
611
+ /* TODO: can be optimized if y = 0, 1 or -1 */
612
+ case T_BIGNUM:
613
+ b = inum_to_dec(y);
614
+ break;
615
+ case T_FLOAT:
616
+ rb_raise(rb_eTypeError, "can't operate with Float");
617
+ break;
618
+ case T_DATA:
619
+ if (DECIMAL_P(y)) {
620
+ GetDecimal(y, b);
621
+ if (b == DEC_NaN) return VALUE_NaN;
622
+ break;
623
+ }
624
+ /* fall through */
625
+ default:
626
+ return rb_num_coerce_bin(x, y);
627
+ }
628
+ GetDecimal(x, a);
629
+ if (a == DEC_NaN) return VALUE_NaN;
630
+
631
+ if (DEC_ISINF(a)) {
632
+ if (DEC_ISINF(b)) return a == DEC_PINF ? y : dec_uminus(y);
633
+ if (DEC_ZERO_P(b)) return VALUE_NaN;
634
+ if (!INUM_NEGATIVE_P(b->inum)) return x;
635
+ return dec_uminus(x);
636
+ }
637
+ if (DEC_ZERO_P(a)) {
638
+ if (DEC_ISINF(b)) return VALUE_NaN;
639
+ if (INUM_SPZERO_P(b->inum)) {
640
+ return a->inum == DEC_PZERO ? y : dec_uminus(y);
641
+ }
642
+ if (INUM_NEGATIVE_P(b->inum)) return dec_uminus(x);
643
+ return x;
644
+ }
645
+ if (DEC_IMMEDIATE_P(b) || INUM_SPZERO_P(b->inum)) {
646
+ if (INUM_NEGATIVE_P(a->inum)) return dec_uminus(y);
647
+ return y;
648
+ }
649
+ return WrapDecimal(normal_mul(a, b));
650
+ }
651
+
652
+ static Decimal *
653
+ do_round(Decimal *d, long scale, VALUE mode, VALUE *inump)
654
+ {
655
+ Decimal *d2;
656
+ long diff;
657
+ int lower;
658
+ int trailing_nonzero, negative;
659
+ VALUE inum, inumabs, shift, tmp, ary;
660
+
661
+ if (d == DEC_PINF) rb_raise(eDomainError, "Infinity");
662
+ if (d == DEC_NINF) rb_raise(eDomainError, "-Infinity");
663
+ if (d == DEC_NaN) rb_raise(eDomainError, "NaN");
664
+ if (INUM_SPZERO_P(d->inum)) {
665
+ if (inump) {
666
+ if (scale != 0) rb_bug("do_round(): "
667
+ "scale != 0 with Integer request");
668
+ *inump = INT2FIX(0);
669
+ return NULL;
670
+ }
671
+ d2 = finite_dup(d);
672
+ if (d->scale > scale) d2->scale = scale;
673
+ return d2;
674
+ }
675
+ if (d->scale <= scale) { /* no need to round */
676
+ /* return Decimal */
677
+ if (scale) return finite_dup(d);
678
+ /* return Integer */
679
+ if (!inump) /* XXX: may be reached when Decimal(1)/1 */
680
+ rb_bug("do_round(): not reached[2]");
681
+ if (d->scale == 0) *inump = d->inum;
682
+ else *inump = inum_lshift(d->inum, -d->scale);
683
+ return NULL;
684
+ }
685
+ negative = INUM_NEGATIVE_P(d->inum);
686
+ diff = d->scale - scale;
687
+ inumabs = negative ? INUM_UMINUS(d->inum) : d->inum;
688
+ if (mode == ROUND_CEILING ||
689
+ mode == ROUND_DOWN ||
690
+ mode == ROUND_FLOOR ||
691
+ mode == ROUND_UP ||
692
+ mode == ROUND_UNNECESSARY) {
693
+ shift = inum_lshift(INT2FIX(1), diff);
694
+ ary = INUM_DIVMOD(inumabs, shift);
695
+ inum = RARRAY(ary)->ptr[0];
696
+ if (mode == ROUND_DOWN) goto coda;
697
+ trailing_nonzero = !INUM_ZERO_P(RARRAY(ary)->ptr[1]);
698
+ if (mode == ROUND_CEILING) {
699
+ if (!negative && trailing_nonzero) INUM_INC(inum);
700
+ }
701
+ else if (mode == ROUND_FLOOR) {
702
+ if (negative && trailing_nonzero) INUM_INC(inum);
703
+ }
704
+ else if (mode == ROUND_UP) {
705
+ if (trailing_nonzero) INUM_INC(inum);
706
+ }
707
+ else { /* mode == ROUND_UNNECESSARY */
708
+ if (trailing_nonzero) {
709
+ rb_raise(eArithmeticError, "rounding necessary");
710
+ }
711
+ }
712
+ }
713
+ else if (mode == ROUND_HALF_DOWN || /* needs lower digit */
714
+ mode == ROUND_HALF_UP ||
715
+ mode == ROUND_HALF_EVEN) {
716
+ if (diff != 1)
717
+ 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]);
726
+ if (mode == ROUND_HALF_DOWN) {
727
+ if (lower > 5) INUM_INC(inum);
728
+ }
729
+ else if (mode == ROUND_HALF_UP) {
730
+ if (lower >= 5) INUM_INC(inum);
731
+ }
732
+ else { /* mode == ROUND_HALF_EVEN */
733
+ if (INUM_ODD_P(inum)) {
734
+ if (lower >= 5) INUM_INC(inum);
735
+ }
736
+ else {
737
+ if (lower > 5) INUM_INC(inum);
738
+ }
739
+ }
740
+ }
741
+ coda:
742
+ if (negative) inum = INUM_UMINUS(inum);
743
+ if (scale == 0 && inump) { /* return Integer */
744
+ *inump = inum;
745
+ return NULL;
746
+ }
747
+ /* return Decimal */
748
+ d2 = ALLOC(Decimal);
749
+ if (INUM_ZERO_P(inum)) {
750
+ d2->inum = negative ? DEC_NZERO : DEC_PZERO;
751
+ d2->scale = 0;
752
+ }
753
+ else {
754
+ d2->inum = inum;
755
+ d2->scale = scale;
756
+ }
757
+ return d2;
758
+ }
759
+
760
+ static Decimal *
761
+ normal_divide(Decimal *x, Decimal *y, long scale, VALUE mode)
762
+ {
763
+ long diff;
764
+ VALUE xx;
765
+ Decimal *z = ALLOC(Decimal);
766
+
767
+ diff = x->scale - y->scale;
768
+ if (diff <= scale) {
769
+ xx = inum_lshift(x->inum, scale-diff+1); /* +1 for rounding */
770
+ z->scale = scale + 1;
771
+ }
772
+ else {
773
+ /* FIXME: may be a bug...? */
774
+ xx = x->inum;
775
+ z->scale = diff;
776
+ }
777
+ z->inum = INUM_DIV(xx, y->inum);
778
+ return do_round(z, scale, mode, 0);
779
+ }
780
+
781
+ static int
782
+ valid_rounding_mode(VALUE sym)
783
+ {
784
+ if (sym == ROUND_CEILING ||
785
+ sym == ROUND_DOWN ||
786
+ sym == ROUND_FLOOR ||
787
+ sym == ROUND_HALF_DOWN ||
788
+ sym == ROUND_HALF_EVEN ||
789
+ sym == ROUND_HALF_UP ||
790
+ sym == ROUND_UP ||
791
+ sym == ROUND_UNNECESSARY) {
792
+ return Qtrue;
793
+ }
794
+ return Qfalse;
795
+ }
796
+
797
+ static VALUE
798
+ dec_divide(int argc, VALUE *argv, VALUE x)
799
+ {
800
+ VALUE y;
801
+ Decimal *a, *b;
802
+ VALUE mode = ROUND_UNNECESSARY;
803
+ long scale, l;
804
+ VALUE vscale, vmode;
805
+
806
+ GetDecimal(x, a);
807
+ if (a == DEC_NaN) return VALUE_NaN; /* no need to check b */
808
+
809
+ rb_scan_args(argc, argv, "12", &y, &vscale, &vmode);
810
+ switch (argc) {
811
+ case 3:
812
+ Check_Type(vmode, T_SYMBOL);
813
+ if (!valid_rounding_mode(vmode)) {
814
+ rb_raise(rb_eArgError, "invalid rounding mode %s",
815
+ RSTRING(rb_inspect(mode))->ptr);
816
+ }
817
+ mode = vmode;
818
+ /* fall through */
819
+ case 2:
820
+ scale = NUM2LONG(vscale);
821
+ break;
822
+ case 1:
823
+ if (mode != ROUND_UNNECESSARY) {
824
+ rb_raise(rb_eArgError, "scale number argument needed");
825
+ }
826
+ scale = 0; /* FIXME: dummy */
827
+ }
828
+
829
+ switch (TYPE(y)) {
830
+ case T_FIXNUM:
831
+ l = FIX2LONG(y);
832
+ if (l == 0) {
833
+ if (DEC_ZERO_P(a)) return VALUE_NaN;
834
+ if (DEC_ISINF(a)) return x;
835
+ return INUM_NEGATIVE_P(a->inum) ? VALUE_NINF : VALUE_PINF;
836
+ }
837
+ else if (l == 1) return x;
838
+ else if (l == -1) return dec_uminus(x);
839
+ /* fall through */
840
+ case T_BIGNUM:
841
+ b = inum_to_dec(y);
842
+ break;
843
+ case T_FLOAT:
844
+ rb_raise(rb_eTypeError, "can't operate with Float");
845
+ return Qnil; /* not reached */
846
+ case T_DATA:
847
+ if (DECIMAL_P(y)) {
848
+ GetDecimal(y, b);
849
+ if (b == DEC_NaN) return VALUE_NaN;
850
+ break;
851
+ }
852
+ /* fall through */
853
+ default:
854
+ return rb_num_coerce_bin(x, y);
855
+ }
856
+ /* TODO: can be optimized if b == 0, 1 or -1 */
857
+ if (DEC_ISINF(a)) {
858
+ if (DEC_ISINF(b)) return VALUE_NaN;
859
+ 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;
862
+ }
863
+ if (DEC_ZERO_P(a)) {
864
+ if (b == DEC_PINF) return x;
865
+ if (b == DEC_NINF) return dec_uminus(x);
866
+ if (INUM_SPZERO_P(b->inum)) return VALUE_NaN;
867
+ return INUM_NEGATIVE_P(b->inum) ? dec_uminus(x) : x;
868
+ }
869
+ if (DEC_ISINF(b)) {
870
+ if (INUM_NEGATIVE_P(a->inum) == (b == DEC_NINF)) {
871
+ return dec_pzero();
872
+ }
873
+ return dec_nzero();
874
+ }
875
+ if (DEC_ZERO_P(b)) {
876
+ if (INUM_NEGATIVE_P(a->inum) == (b->inum == DEC_NZERO)) {
877
+ return VALUE_PINF;
878
+ }
879
+ return VALUE_NINF;
880
+ }
881
+ return WrapDecimal(normal_divide(a, b, scale, mode));
882
+ }
883
+
884
+ #ifdef DEBUG
885
+ static VALUE
886
+ dec_div(VALUE x, VALUE y)
887
+ {
888
+ return dec_divide(1, &y, x);
889
+ }
890
+ #endif
891
+
892
+ /*
893
+ * FIXME: test needed!
894
+ */
895
+ static void
896
+ divmod(Decimal *a, Decimal *b, VALUE *divp, VALUE *modp)
897
+ {
898
+ Decimal *div, *mod;
899
+ Decimal *tmp;
900
+
901
+ if (a == DEC_NaN || DEC_ISINF(a) || b == DEC_NaN ||
902
+ (!DEC_ISINF(b) && DEC_ZERO_P(b))) {
903
+ div = mod = DEC_NaN;
904
+ }
905
+ 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
+ }
914
+ mod = finite_dup(a);
915
+ }
916
+ else if (DEC_ISINF(b)) {
917
+ const int a_negative = INUM_NEGATIVE_P(a->inum);
918
+
919
+ div = ALLOC(Decimal);
920
+ div->scale = 0;
921
+ 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);
928
+ }
929
+ }
930
+ else {
931
+ /* 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;
935
+ mod = finite_dup(a);
936
+ }
937
+ else {
938
+ tmp = normal_mul(div, b);
939
+ mod = normal_plus(a, tmp, 0); /* mod = x - div*y; */
940
+ xfree(tmp);
941
+ }
942
+ /* 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; */
947
+ }
948
+ }
949
+ if (divp) *divp = WrapDecimal(div);
950
+ else if (!DEC_IMMEDIATE_P(div)) xfree(div);
951
+ if (modp) *modp = WrapDecimal(mod);
952
+ else if (!DEC_IMMEDIATE_P(mod)) xfree(mod);
953
+ }
954
+
955
+ static VALUE
956
+ dec_idiv(VALUE x, VALUE y)
957
+ {
958
+ Decimal *a, *b;
959
+ VALUE div;
960
+
961
+ switch (TYPE(y)) {
962
+ case T_FIXNUM:
963
+ case T_BIGNUM:
964
+ b = inum_to_dec(y);
965
+ break;
966
+ case T_FLOAT:
967
+ rb_raise(rb_eTypeError, "can't operate with Float");
968
+ case T_DATA:
969
+ if (DECIMAL_P(y)) {
970
+ GetDecimal(y, b);
971
+ break;
972
+ }
973
+ /* fall through */
974
+ default:
975
+ return rb_num_coerce_bin(x, y);
976
+ }
977
+ GetDecimal(x, a);
978
+ divmod(a, b, &div, NULL);
979
+ return div;
980
+ }
981
+
982
+ static VALUE
983
+ dec_mod(VALUE x, VALUE y)
984
+ {
985
+ Decimal *a, *b;
986
+ VALUE mod;
987
+
988
+ switch (TYPE(y)) {
989
+ case T_FIXNUM:
990
+ case T_BIGNUM:
991
+ b = inum_to_dec(y);
992
+ break;
993
+ case T_FLOAT:
994
+ rb_raise(rb_eTypeError, "can't operate with Float");
995
+ case T_DATA:
996
+ if (DECIMAL_P(y)) {
997
+ GetDecimal(y, b);
998
+ break;
999
+ }
1000
+ /* fall through */
1001
+ default:
1002
+ return rb_num_coerce_bin(x, y);
1003
+ }
1004
+ GetDecimal(x, a);
1005
+ divmod(a, b, NULL, &mod);
1006
+ return mod;
1007
+ }
1008
+
1009
+ static VALUE
1010
+ dec_divmod(VALUE x, VALUE y)
1011
+ {
1012
+ Decimal *a, *b;
1013
+ VALUE div, mod;
1014
+
1015
+ switch (TYPE(y)) {
1016
+ case T_FIXNUM:
1017
+ case T_BIGNUM:
1018
+ b = inum_to_dec(y);
1019
+ break;
1020
+ case T_FLOAT:
1021
+ rb_raise(rb_eTypeError, "can't operate with Float");
1022
+ case T_DATA:
1023
+ if (DECIMAL_P(y)) {
1024
+ GetDecimal(y, b);
1025
+ break;
1026
+ }
1027
+ /* fall through */
1028
+ default:
1029
+ return rb_num_coerce_bin(x, y);
1030
+ }
1031
+ GetDecimal(x, a);
1032
+ divmod(a, b, &div, &mod);
1033
+ return rb_assoc_new(div, mod);
1034
+ }
1035
+
1036
+ /* XXX: may have bugs; try "GC.stress = true" to reproduce */
1037
+ /* TODO: can be optimized with removing sign "flip flap?" */
1038
+ static VALUE
1039
+ power_with_long(Decimal *x, long y) /* requires y > 1 */
1040
+ {
1041
+ Decimal *z = x, *const orig_x = x, *tmp;
1042
+
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);
1058
+ }
1059
+
1060
+ static VALUE
1061
+ dec_pow(VALUE x, VALUE y)
1062
+ {
1063
+ Decimal *a;
1064
+ long l;
1065
+
1066
+ GetDecimal(x, a);
1067
+ Check_Type(y, T_FIXNUM);
1068
+ l = FIX2LONG(y);
1069
+ 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;
1084
+ }
1085
+ return power_with_long(a, l);
1086
+ }
1087
+
1088
+ static int
1089
+ normal_cmp(Decimal *x, Decimal *y)
1090
+ {
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;
1098
+ }
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
+ }
1108
+
1109
+ /* never accepts NaN for x and y */
1110
+ static int
1111
+ cmp(Decimal *x, Decimal *y)
1112
+ {
1113
+ if (x == y) return 0;
1114
+ if (x == DEC_PINF || y == DEC_NINF) return 1;
1115
+ if (x == DEC_NINF || y == DEC_PINF) return -1;
1116
+ if (INUM_SPZERO_P(x->inum)) {
1117
+ if (INUM_SPZERO_P(y->inum)) return 0;
1118
+ return INUM_NEGATIVE_P(y->inum) ? -1 : 1;
1119
+ }
1120
+ if (INUM_SPZERO_P(y->inum)) {
1121
+ return INUM_NEGATIVE_P(x->inum) ? -1 : 1;
1122
+ }
1123
+ return normal_cmp(x, y);
1124
+ }
1125
+
1126
+ static VALUE
1127
+ dec_eq(VALUE x, VALUE y)
1128
+ {
1129
+ Decimal *a, *b;
1130
+
1131
+ GetDecimal(x, a);
1132
+ if (a == DEC_NaN) return Qfalse;
1133
+ switch (TYPE(y)) {
1134
+ case T_FIXNUM:
1135
+ case T_BIGNUM:
1136
+ b = inum_to_dec(y);
1137
+ break;
1138
+ case T_FLOAT:
1139
+ return Qnil;
1140
+ case T_DATA:
1141
+ if (DECIMAL_P(y)) {
1142
+ GetDecimal(y, b);
1143
+ if (b == DEC_NaN) return Qfalse;
1144
+ break;
1145
+ }
1146
+ /* fall through */
1147
+ default:
1148
+ return rb_num_coerce_cmp(x, y);
1149
+ }
1150
+ return cmp(a, b) == 0 ? Qtrue : Qfalse;
1151
+ }
1152
+
1153
+ static VALUE
1154
+ dec_cmp(VALUE x, VALUE y)
1155
+ {
1156
+ Decimal *a, *b;
1157
+
1158
+ GetDecimal(x, a);
1159
+ if (a == DEC_NaN) return Qnil;
1160
+ switch (TYPE(y)) {
1161
+ case T_FIXNUM:
1162
+ case T_BIGNUM:
1163
+ b = inum_to_dec(y);
1164
+ break;
1165
+ case T_FLOAT:
1166
+ return Qnil;
1167
+ case T_DATA:
1168
+ if (DECIMAL_P(y)) {
1169
+ GetDecimal(y, b);
1170
+ if (b == DEC_NaN) return Qnil;
1171
+ break;
1172
+ }
1173
+ /* fall through */
1174
+ default:
1175
+ return rb_num_coerce_cmp(x, y);
1176
+ }
1177
+ return INT2FIX(cmp(a, b));
1178
+ }
1179
+
1180
+ static VALUE
1181
+ dec_gt(VALUE x, VALUE y)
1182
+ {
1183
+ Decimal *a, *b;
1184
+
1185
+ GetDecimal(x, a);
1186
+ if (a == DEC_NaN) return Qfalse;
1187
+ switch (TYPE(y)) {
1188
+ case T_FIXNUM:
1189
+ case T_BIGNUM:
1190
+ b = inum_to_dec(y);
1191
+ break;
1192
+ case T_FLOAT:
1193
+ rb_cmperr(x, y);
1194
+ return Qnil; /* not reached */
1195
+ case T_DATA:
1196
+ if (DECIMAL_P(y)) {
1197
+ GetDecimal(y, b);
1198
+ if (b == DEC_NaN) return Qfalse;
1199
+ break;
1200
+ }
1201
+ /* fall through */
1202
+ default:
1203
+ return rb_num_coerce_relop(x, y);
1204
+ }
1205
+ return cmp(a, b) > 0 ? Qtrue : Qfalse;
1206
+ }
1207
+
1208
+ static VALUE
1209
+ dec_ge(VALUE x, VALUE y)
1210
+ {
1211
+ Decimal *a, *b;
1212
+
1213
+ GetDecimal(x, a);
1214
+ if (a == DEC_NaN) return Qfalse;
1215
+ switch (TYPE(y)) {
1216
+ case T_FIXNUM:
1217
+ case T_BIGNUM:
1218
+ b = inum_to_dec(y);
1219
+ break;
1220
+ case T_FLOAT:
1221
+ rb_cmperr(x, y);
1222
+ return Qnil; /* not reached */
1223
+ case T_DATA:
1224
+ if (DECIMAL_P(y)) {
1225
+ GetDecimal(y, b);
1226
+ if (b == DEC_NaN) return Qfalse;
1227
+ break;
1228
+ }
1229
+ /* fall through */
1230
+ default:
1231
+ return rb_num_coerce_relop(x, y);
1232
+ }
1233
+ return cmp(a, b) >= 0 ? Qtrue : Qfalse;
1234
+ }
1235
+
1236
+ static VALUE
1237
+ dec_lt(VALUE x, VALUE y)
1238
+ {
1239
+ Decimal *a, *b;
1240
+
1241
+ GetDecimal(x, a);
1242
+ if (a == DEC_NaN) return Qfalse;
1243
+ switch (TYPE(y)) {
1244
+ case T_FIXNUM:
1245
+ case T_BIGNUM:
1246
+ b = inum_to_dec(y);
1247
+ break;
1248
+ case T_FLOAT:
1249
+ rb_cmperr(x, y);
1250
+ return Qnil; /* not reached */
1251
+ case T_DATA:
1252
+ if (DECIMAL_P(y)) {
1253
+ GetDecimal(y, b);
1254
+ if (b == DEC_NaN) return Qfalse;
1255
+ break;
1256
+ }
1257
+ /* fall through */
1258
+ default:
1259
+ return rb_num_coerce_relop(x, y);
1260
+ }
1261
+ return cmp(a, b) < 0 ? Qtrue : Qfalse;
1262
+ }
1263
+
1264
+ static VALUE
1265
+ dec_le(VALUE x, VALUE y)
1266
+ {
1267
+ Decimal *a, *b;
1268
+
1269
+ GetDecimal(x, a);
1270
+ if (a == DEC_NaN) return Qfalse;
1271
+ switch (TYPE(y)) {
1272
+ case T_FIXNUM:
1273
+ case T_BIGNUM:
1274
+ b = inum_to_dec(y);
1275
+ break;
1276
+ case T_FLOAT:
1277
+ rb_cmperr(x, y);
1278
+ return Qnil; /* not reached */
1279
+ case T_DATA:
1280
+ if (DECIMAL_P(y)) {
1281
+ GetDecimal(y, b);
1282
+ if (b == DEC_NaN) return Qfalse;
1283
+ break;
1284
+ }
1285
+ /* fall through */
1286
+ default:
1287
+ return rb_num_coerce_relop(x, y);
1288
+ }
1289
+ return cmp(a, b) <= 0 ? Qtrue : Qfalse;
1290
+ }
1291
+
1292
+ static VALUE
1293
+ dec_eql(VALUE x, VALUE y)
1294
+ {
1295
+ Decimal *a, *b;
1296
+
1297
+ if (TYPE(y) != T_DATA || !DECIMAL_P(y))
1298
+ return Qfalse;
1299
+
1300
+ GetDecimal(x, a);
1301
+ 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
+ if (a->scale != b->scale)
1307
+ return Qfalse;
1308
+ if (a->inum == b->inum)
1309
+ return Qtrue;
1310
+ if (INUM_SPZERO_P(a->inum) || INUM_SPZERO_P(b->inum))
1311
+ return Qfalse;
1312
+ if (INUM_EQ(a->inum, b->inum))
1313
+ return Qtrue;
1314
+ return Qfalse;
1315
+ }
1316
+
1317
+ static VALUE
1318
+ dec_hash(VALUE x)
1319
+ {
1320
+ Decimal *d;
1321
+ long hash;
1322
+
1323
+ GetDecimal(x, d);
1324
+ if (!DEC_IMMEDIATE_P(d)) {
1325
+ hash = NUM2LONG(INUM_HASH(d->inum));
1326
+ hash ^= d->scale;
1327
+ }
1328
+ else hash = (long)d;
1329
+ return LONG2NUM(hash);
1330
+ }
1331
+
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)
1341
+
1342
+ static double
1343
+ normal_to_f(Decimal *d)
1344
+ {
1345
+ double f;
1346
+
1347
+ if (d->scale == 0) QUIET(f = NUM2DBL(d->inum));
1348
+ else if (d->scale < 0) {
1349
+ VALUE n;
1350
+
1351
+ n = inum_lshift(d->inum, -d->scale);
1352
+ QUIET(f = NUM2DBL(n));
1353
+ }
1354
+ else {
1355
+ /* FIXME: more strict handling needed for huge value */
1356
+ double divf;
1357
+ VALUE div;
1358
+
1359
+ QUIET(f = NUM2DBL(d->inum));
1360
+ div = inum_lshift(INT2FIX(1), d->scale);
1361
+ QUIET(divf = NUM2DBL(div));
1362
+ f /= divf;
1363
+ }
1364
+ if (isinf(f)) {
1365
+ rb_warn("Decimal out of Float range");
1366
+ f = HUGE_VAL;
1367
+ }
1368
+ return f;
1369
+ }
1370
+
1371
+ static VALUE
1372
+ dec_to_f(VALUE num)
1373
+ {
1374
+ Decimal *d;
1375
+ double f;
1376
+
1377
+ 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)
1385
+ f = 0.0;
1386
+ else if (d->inum == DEC_NZERO)
1387
+ f = -0.0;
1388
+ else
1389
+ f = normal_to_f(d);
1390
+
1391
+ return rb_float_new(f);
1392
+ }
1393
+
1394
+ static VALUE
1395
+ dec_abs(VALUE num)
1396
+ {
1397
+ Decimal *d, *d2;
1398
+
1399
+ GetDecimal(num, d);
1400
+ if (d == DEC_NINF)
1401
+ return VALUE_PINF;
1402
+ if (d == DEC_PINF || d == DEC_NaN ||
1403
+ d->inum == DEC_PZERO || !INUM_NEGATIVE_P(d->inum)) {
1404
+ return num;
1405
+ }
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);
1410
+ }
1411
+
1412
+ static VALUE
1413
+ dec_zero_p(VALUE num)
1414
+ {
1415
+ Decimal *d;
1416
+
1417
+ GetDecimal(num, d);
1418
+ if (!DEC_IMMEDIATE_P(d) && DEC_ZERO_P(d)) {
1419
+ return Qtrue;
1420
+ }
1421
+ return Qfalse;
1422
+ }
1423
+
1424
+ static VALUE
1425
+ dec_to_i(VALUE num)
1426
+ {
1427
+ Decimal *d;
1428
+ VALUE inum;
1429
+
1430
+ GetDecimal(num, d);
1431
+ do_round(d, 0, ROUND_DOWN, &inum); /* identical to "d.round(0, :down)" */
1432
+ return inum;
1433
+ }
1434
+
1435
+ static VALUE
1436
+ rounding_method(int argc, VALUE *argv, VALUE x, VALUE mode)
1437
+ {
1438
+ Decimal *d;
1439
+ VALUE scale, inum;
1440
+
1441
+ rb_scan_args(argc, argv, "01", &scale);
1442
+ GetDecimal(x, d);
1443
+ if (argc == 0) {
1444
+ do_round(d, 0, mode, &inum);
1445
+ return inum;
1446
+ }
1447
+ return WrapDecimal(do_round(d, NUM2LONG(scale), mode, 0));
1448
+ }
1449
+
1450
+ static VALUE
1451
+ dec_truncate(int argc, VALUE *argv, VALUE x)
1452
+ {
1453
+ return rounding_method(argc, argv, x, ROUND_DOWN);
1454
+ }
1455
+
1456
+ static VALUE
1457
+ dec_floor(int argc, VALUE *argv, VALUE x)
1458
+ {
1459
+ return rounding_method(argc, argv, x, ROUND_FLOOR);
1460
+ }
1461
+
1462
+ static VALUE
1463
+ dec_ceil(int argc, VALUE *argv, VALUE x)
1464
+ {
1465
+ return rounding_method(argc, argv, x, ROUND_CEILING);
1466
+ }
1467
+
1468
+ static VALUE
1469
+ dec_round(int argc, VALUE *argv, VALUE x)
1470
+ {
1471
+ Decimal *d;
1472
+ VALUE vscale;
1473
+ long scale = 0;
1474
+ VALUE mode = ROUND_HALF_UP, tmpmode;
1475
+
1476
+ rb_scan_args(argc, argv, "02", &vscale, &tmpmode);
1477
+ switch (argc) {
1478
+ case 2:
1479
+ Check_Type(mode, T_SYMBOL);
1480
+ if (!valid_rounding_mode(mode)) {
1481
+ rb_raise(rb_eArgError, "invalid rounding mode %s",
1482
+ RSTRING(rb_inspect(mode))->ptr);
1483
+ }
1484
+ mode = tmpmode;
1485
+ /* fall through */
1486
+ case 1:
1487
+ scale = NUM2LONG(vscale);
1488
+ /* fall through */
1489
+ default:
1490
+ break;
1491
+ }
1492
+ GetDecimal(x, d);
1493
+ if (scale == 0) {
1494
+ VALUE inum;
1495
+
1496
+ do_round(d, scale, mode, &inum);
1497
+ return inum;
1498
+ }
1499
+ return WrapDecimal(do_round(d, scale, mode, 0));
1500
+ }
1501
+
1502
+
1503
+ static VALUE
1504
+ dec_nan_p(VALUE num)
1505
+ {
1506
+ Decimal *d;
1507
+
1508
+ GetDecimal(num, d);
1509
+ return d == DEC_NaN ? Qtrue : Qfalse;
1510
+ }
1511
+
1512
+ static VALUE
1513
+ dec_finite_p(VALUE num)
1514
+ {
1515
+ Decimal *d;
1516
+
1517
+ GetDecimal(num, d);
1518
+ return !DEC_IMMEDIATE_P(d) ? Qtrue : Qfalse;
1519
+ }
1520
+
1521
+ static VALUE
1522
+ dec_infinite_p(VALUE num)
1523
+ {
1524
+ Decimal *d;
1525
+
1526
+ GetDecimal(num, d);
1527
+ if (d == DEC_PINF) return INT2FIX(1);
1528
+ if (d == DEC_NINF) return INT2FIX(-1);
1529
+ return Qnil;
1530
+ }
1531
+
1532
+ void
1533
+ Init_decimal(void)
1534
+ {
1535
+ cDecimal = rb_define_class("Decimal", rb_cNumeric);
1536
+ eDomainError = rb_define_class_under(cDecimal, "DomainError",
1537
+ rb_eRangeError);
1538
+ eArithmeticError = rb_define_class_under(cDecimal, "ArithmeticError",
1539
+ rb_eStandardError);
1540
+
1541
+ rb_define_global_function("Decimal", f_decimal, 1);
1542
+
1543
+ rb_define_alloc_func(cDecimal, dec_s_allocate);
1544
+ rb_define_method(cDecimal, "initialize", dec_initialize, 1);
1545
+
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);
1551
+ rb_global_variable(&VALUE_PINF);
1552
+ rb_global_variable(&VALUE_NINF);
1553
+ 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);
1567
+
1568
+ #ifdef DEBUG
1569
+ rb_define_method(cDecimal, "scale", dec_scale, 0);
1570
+ rb_define_method(cDecimal, "unscaled_value", dec_unscaled_value, 0);
1571
+ #endif
1572
+ rb_define_method(cDecimal, "strip_trailing_zeros",
1573
+ dec_strip_trailing_zeros, 0);
1574
+ rb_define_method(cDecimal, "strip", dec_strip_trailing_zeros, 0);
1575
+
1576
+ rb_define_method(cDecimal, "to_s", dec_to_s, 0);
1577
+ rb_define_method(cDecimal, "inspect", dec_inspect, 0);
1578
+ rb_define_method(cDecimal, "coerce", dec_coerce, 1);
1579
+ rb_define_method(cDecimal, "-@", dec_uminus, 0);
1580
+ rb_define_method(cDecimal, "+", dec_plus, 1);
1581
+ rb_define_method(cDecimal, "-", dec_minus, 1);
1582
+ rb_define_method(cDecimal, "*", dec_mul, 1);
1583
+ rb_define_method(cDecimal, "divide", dec_divide, -1);
1584
+ #ifdef DEBUG
1585
+ rb_define_method(cDecimal, "/", dec_div, 1);
1586
+ #endif
1587
+ rb_define_method(cDecimal, "div", dec_idiv, 1);
1588
+ rb_define_method(cDecimal, "%", dec_mod, 1);
1589
+ rb_define_method(cDecimal, "modulo", dec_mod, 1);
1590
+ rb_define_method(cDecimal, "divmod", dec_divmod, 1);
1591
+ rb_define_method(cDecimal, "**", dec_pow, 1);
1592
+ rb_define_method(cDecimal, "==", dec_eq, 1);
1593
+ rb_define_method(cDecimal, "<=>", dec_cmp, 1);
1594
+ rb_define_method(cDecimal, ">", dec_gt, 1);
1595
+ rb_define_method(cDecimal, ">=", dec_ge, 1);
1596
+ rb_define_method(cDecimal, "<", dec_lt, 1);
1597
+ rb_define_method(cDecimal, "<=", dec_le, 1);
1598
+ rb_define_method(cDecimal, "eql?", dec_eql, 1);
1599
+ rb_define_method(cDecimal, "hash", dec_hash, 0);
1600
+ rb_define_method(cDecimal, "to_f", dec_to_f, 0);
1601
+ rb_define_method(cDecimal, "abs", dec_abs, 0);
1602
+ rb_define_method(cDecimal, "zero?", dec_zero_p, 0);
1603
+
1604
+ rb_define_method(cDecimal, "to_i", dec_to_i, 0);
1605
+ rb_define_method(cDecimal, "to_int", dec_to_i, 0);
1606
+ rb_define_method(cDecimal, "truncate", dec_truncate, -1);
1607
+ rb_define_method(cDecimal, "floor", dec_floor, -1);
1608
+ rb_define_method(cDecimal, "ceil", dec_ceil, -1);
1609
+ rb_define_method(cDecimal, "round", dec_round, -1);
1610
+
1611
+ rb_define_method(cDecimal, "nan?", dec_nan_p, 0);
1612
+ rb_define_method(cDecimal, "finite?", dec_finite_p, 0);
1613
+ rb_define_method(cDecimal, "infinite?", dec_infinite_p, 0);
1614
+ }