decimal 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a8097ff905177fba0cb30a72729889f1f0e8c2a5
4
+ data.tar.gz: ca7f019d9016491724ced8f63dc8014a9b36f336
5
+ SHA512:
6
+ metadata.gz: 9aae38f7a8bff309748cd1c61279323411c39bcf5238c95539d27e5d98b4ede7a6e7b3ed2f712b01490e386ce03d669c493ca5e75aff600ab4246f45d0d4901e
7
+ data.tar.gz: 475772f7f6cc6e888743d1b0b66696fe90a98f5a46022b023049ac5c554ce59f3d3fbc3bd4ac205c31435ec8123513f34c6eea1d395d86f50caae9e2ba07bc69
data/.document CHANGED
@@ -1,3 +1,2 @@
1
1
  decimal.c
2
- README
3
-
2
+ README.rdoc
data/BSDL ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2014 Tadashi Saito. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
data/COPYING CHANGED
@@ -1,7 +1,7 @@
1
1
  Decimal is copyrighted free software by Tadashi Saito <tad.a.diggier[at]
2
2
  gmail.com>.
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:
3
+ You can redistribute it and/or modify it under either the terms of the
4
+ 2-clause BSDL (see the file BSDL), or the conditions below:
5
5
 
6
6
  1. You may make and give away verbatim copies of the source form of the
7
7
  software without restriction, provided that you duplicate all of the
@@ -7,13 +7,14 @@ precise, stable and easy-to-use solution.
7
7
  == Webpages
8
8
 
9
9
  * {Home}[http://decimal.rubyforge.org/]
10
+ * {GitHub}[https://github.com/tadd/decimal]
10
11
  * {Latest API Documents}[http://decimal.rubyforge.org/rdoc/]
11
12
  * {Project Page at RubyForge}[http://rubyforge.org/projects/decimal/]
12
13
  * {Mailing Lists}[http://rubyforge.org/mail/?group_id=1994]
13
14
 
14
15
  == Requirements
15
16
 
16
- Ruby 1.8.6 / 1.8.7 / 1.9.1 / 1.9.2dev (experimental)
17
+ Ruby 1.9.3 / 2.0.0 / 2.1.x / 2.2.x
17
18
 
18
19
  == Install
19
20
 
@@ -50,7 +51,7 @@ Use like Float with few exceptions including Decimal#divide.
50
51
 
51
52
  == License
52
53
 
53
- Ruby's. See COPYING and GPL for more details.
54
+ Ruby's. See COPYING and BSDL for more details.
54
55
 
55
56
  == Author
56
57
 
data/TODO CHANGED
@@ -1,7 +1,5 @@
1
1
  * Preserve scale of zeros
2
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
3
  * Be a good friend with other Numeric classes (using Kernel.autoload?)
6
4
  - OtherNumerics#to_decimal, Decimal#to_*
7
5
  * Define `marshal_dump' and `marshal_load'
@@ -13,6 +11,7 @@
13
11
  * Static value for well-used value like 0, 1 or 10 ?
14
12
 
15
13
  done:
14
+ - Implement decimal ** otherdecimal and decimal ** -integer
16
15
  - Implement Math functions
17
16
  - Implement webpages
18
17
  - Support RubyGems
data/decimal.c CHANGED
@@ -23,9 +23,6 @@
23
23
  #include <util.h>
24
24
  #endif
25
25
 
26
- /* we need support both of 1.8/1.9 with the same source! */
27
- #include "ruby18compat.h"
28
-
29
26
  /*
30
27
  * unfortunately, few copies of Integer functions
31
28
  * are needed from original Ruby
@@ -772,7 +769,7 @@ do_round(const Decimal *d, long scale, VALUE mode, VALUE *inump)
772
769
  long diff;
773
770
  int lower;
774
771
  int trailing_nonzero, negative;
775
- VALUE inum, inumabs, shift, ary;
772
+ VALUE inum = Qundef, inumabs, shift, ary;
776
773
 
777
774
  if (d == DEC_PINF) rb_raise(eDomainError, "Infinity");
778
775
  if (d == DEC_NINF) rb_raise(eDomainError, "-Infinity");
@@ -1027,7 +1024,6 @@ divmod(const Decimal *a, const Decimal *b, VALUE *divp, VALUE *modp)
1027
1024
  }
1028
1025
  else if (DEC_ISINF(b)) {
1029
1026
  const int a_negative = INUM_NEGATIVE_P(a->inum);
1030
- VALUE div_inum;
1031
1027
 
1032
1028
  if (a_negative != (b == DEC_NINF)) { /* signs differ */
1033
1029
  if (divp) *divp = INT2FIX(-1);
@@ -1177,19 +1173,173 @@ dec_divmod(VALUE x, VALUE y)
1177
1173
  return rb_assoc_new(div, mod);
1178
1174
  }
1179
1175
 
1176
+ static VALUE math_ln(VALUE x, VALUE scale, VALUE mode);
1177
+ static VALUE math_exp(int argc, VALUE *argv, VALUE module UNUSED);
1178
+
1180
1179
  static VALUE
1181
- power_with_fixnum(const Decimal *x, VALUE y)
1180
+ power_with_math_exp(VALUE x, VALUE y, VALUE scale, VALUE mode)
1181
+ {
1182
+ VALUE x_ln;
1183
+ VALUE argv[3];
1184
+
1185
+ x_ln = math_ln(x, LONG2NUM(FIX2LONG(scale)+1), ROUND_DOWN);
1186
+ argv[0] = dec_mul(y, x_ln);
1187
+ argv[1] = scale;
1188
+ argv[2] = mode;
1189
+ return math_exp(3, argv, Qnil);
1190
+ }
1191
+
1192
+ static VALUE
1193
+ power_with_positive_fixnum(VALUE x, VALUE y)
1182
1194
  {
1183
1195
  VALUE inum;
1196
+ Decimal *a;
1184
1197
 
1198
+ GetDecimal(x, a);
1185
1199
  /* XXX: valid to rb_warn() out of here by rb_big_pow()? */
1186
- inum = INUM_POW(x->inum, y);
1200
+ inum = INUM_POW(a->inum, y);
1187
1201
  if (TYPE(inum) == T_FLOAT) /* got Infinity with warning, by too-big y */
1188
1202
  return VALUE_PINF;
1189
- return WrapDecimal(dec_raw_new(inum, x->scale * FIX2LONG(y)));
1203
+ return WrapDecimal(dec_raw_new(inum, a->scale * FIX2LONG(y)));
1204
+ }
1205
+
1206
+ static VALUE dec_eq(VALUE x, VALUE y);
1207
+ static VALUE dec_lt(VALUE x, VALUE y);
1208
+ static VALUE dec_gt(VALUE x, VALUE y);
1209
+ static VALUE dec_abs(VALUE x);
1210
+ static VALUE dec_zero_p(VALUE x);
1211
+ static VALUE dec_finite_p(VALUE x);
1212
+
1213
+ static VALUE
1214
+ power_body(VALUE x, VALUE y, VALUE scale, VALUE mode)
1215
+ {
1216
+ int y_negative_p, y_finite_p, y_integer_p, y_zero_p, y_positive_p,
1217
+ y_odd_p, y_pinf_p, y_ninf_p, y_nan_p, y_one_p;
1218
+ int x_finite_p, x_negative_p, x_nan_p, x_pone_p, x_none_p, x_zero_p,
1219
+ x_abs, x_abs_lt_1, x_abs_gt_1, x_ninf_p, x_pinf_p;
1220
+ long l = 0; /* dummy value */
1221
+
1222
+ if (FIXNUM_P(y)) {
1223
+ l = FIX2LONG(y);
1224
+ y_integer_p = y_finite_p = Qtrue;
1225
+ y_zero_p = (l == 0);
1226
+ y_one_p = (l == 1);
1227
+ y_positive_p = (l > 0);
1228
+ y_negative_p = (l < 0);
1229
+ y_odd_p = (l % 2 != 0);
1230
+ y_pinf_p = y_ninf_p = y_nan_p = Qfalse;
1231
+ } else { /* it's a Decimal */
1232
+ y_finite_p = dec_finite_p(y);
1233
+ y_integer_p = (y_finite_p && !dec_zero_p(dec_mod(y, INT2FIX(1))));
1234
+ y_zero_p = dec_zero_p(y);
1235
+ y_one_p = dec_eq(y, INT2FIX(1));
1236
+ y_positive_p = dec_gt(y, INT2FIX(0));
1237
+ y_negative_p = dec_lt(y, INT2FIX(0));
1238
+ y_odd_p = (y_finite_p && !dec_zero_p(dec_mod(y, INT2FIX(2))));
1239
+ y_pinf_p = (y == VALUE_PINF);
1240
+ y_ninf_p = (y == VALUE_NINF);
1241
+ y_nan_p = (y == VALUE_NaN);
1242
+ }
1243
+ x_finite_p = dec_finite_p(x);
1244
+ x_negative_p = dec_lt(x, INT2FIX(0));
1245
+ x_nan_p = (x == VALUE_NaN);
1246
+ x_pone_p = dec_eq(x, INT2FIX(1));
1247
+ x_none_p = dec_eq(x, INT2FIX(-1));
1248
+ x_zero_p = dec_zero_p(x);
1249
+ x_abs = dec_abs(x);
1250
+ x_abs_lt_1 = dec_lt(x_abs, INT2FIX(1));
1251
+ x_abs_gt_1 = dec_gt(x_abs, INT2FIX(1));
1252
+ x_ninf_p = (x == VALUE_NINF);
1253
+ x_pinf_p = (x == VALUE_PINF);
1254
+
1255
+ if (x_negative_p && x_finite_p && !y_integer_p && y_finite_p) {
1256
+ rb_raise(rb_eArgError, "in a**b, a is negative and b is not integer");
1257
+ }
1258
+ if (x_pone_p || y_zero_p) {
1259
+ return WrapDecimal(dec_raw_new(INT2FIX(1), 0));
1260
+ }
1261
+ if (x_zero_p && y_positive_p) {
1262
+ return WrapDecimal(dec_raw_new(DEC_PZERO, 0));
1263
+ }
1264
+ if (x_none_p && (y_pinf_p || y_ninf_p)) {
1265
+ return WrapDecimal(dec_raw_new(INT2FIX(1), 0));
1266
+ }
1267
+ if (x_abs_lt_1 && y_ninf_p) {
1268
+ return VALUE_PINF;
1269
+ }
1270
+ if ((x_abs_gt_1 && y_ninf_p) || (x_abs_lt_1 && y_pinf_p)) {
1271
+ return WrapDecimal(dec_raw_new(DEC_PZERO, 0));
1272
+ }
1273
+ if (x_abs_gt_1 && y_pinf_p) {
1274
+ return VALUE_PINF;
1275
+ }
1276
+ if (x_ninf_p) {
1277
+ if (y_negative_p) {
1278
+ return WrapDecimal(dec_raw_new(DEC_PZERO, 0));
1279
+ }
1280
+ if (y_positive_p) {
1281
+ return y_odd_p ? VALUE_NINF : VALUE_PINF;
1282
+ }
1283
+ }
1284
+ if (x_pinf_p) {
1285
+ if (y_negative_p) {
1286
+ return WrapDecimal(dec_raw_new(DEC_PZERO, 0));
1287
+ }
1288
+ if (y_positive_p) {
1289
+ return VALUE_PINF;
1290
+ }
1291
+ }
1292
+ if (x_zero_p && y_negative_p) {
1293
+ /* FIXME; pole error? */
1294
+ rb_raise(rb_eArgError, "in a**b, a is 0 and y is negative");
1295
+ }
1296
+ if (x_nan_p || y_nan_p) {
1297
+ return VALUE_NaN;
1298
+ }
1299
+ if (y_one_p) return x;
1300
+ if (FIXNUM_P(y)) {
1301
+ if (l > 0) return power_with_positive_fixnum(x, y);
1302
+ y = WrapDecimal(inum_to_dec(y));
1303
+ }
1304
+ return power_with_math_exp(x, y, scale, mode);
1305
+ }
1306
+
1307
+ /*
1308
+ * dec.power(otherdec, scale=(), rounding=:unnecessary)
1309
+ */
1310
+ /* :nodoc: */
1311
+ static VALUE
1312
+ dec_power(int argc, VALUE *argv, VALUE x)
1313
+ {
1314
+ VALUE mode = ROUND_UNNECESSARY;
1315
+ VALUE y, scale, vmode;
1316
+
1317
+ rb_scan_args(argc, argv, "12", &y, &scale, &vmode);
1318
+ switch (argc) {
1319
+ case 3:
1320
+ Check_Type(vmode, T_SYMBOL);
1321
+ if (!valid_rounding_mode_p(vmode)) {
1322
+ rb_raise(rb_eArgError, "invalid rounding mode %s",
1323
+ RSTRING_PTR(rb_inspect(vmode)));
1324
+ }
1325
+ mode = vmode;
1326
+ /* fall through */
1327
+ case 2:
1328
+ Check_Type(scale, T_FIXNUM);
1329
+ break;
1330
+ case 1:
1331
+ if (mode != ROUND_UNNECESSARY) {
1332
+ rb_raise(rb_eArgError, "scale number argument needed");
1333
+ }
1334
+ }
1335
+
1336
+ if (!FIXNUM_P(y) && !DECIMAL_P(y)) {
1337
+ rb_raise(rb_eTypeError, "2nd argument %s must be Fixnum or Decimal",
1338
+ RSTRING_PTR(rb_inspect(y)));
1339
+ }
1340
+ return power_body(x, y, scale, mode);
1190
1341
  }
1191
1342
 
1192
- /* TODO: implement dec ** otherdec */
1193
1343
  /*
1194
1344
  * call-seq:
1195
1345
  * dec ** fix => decimal
@@ -1201,26 +1351,7 @@ power_with_fixnum(const Decimal *x, VALUE y)
1201
1351
  static VALUE
1202
1352
  dec_pow(VALUE x, VALUE y)
1203
1353
  {
1204
- Decimal *a;
1205
- long l;
1206
-
1207
- CHECK_NAN(x);
1208
- Check_Type(y, T_FIXNUM);
1209
- l = FIX2LONG(y);
1210
- if (l < 0) rb_raise(rb_eArgError, "in a**b, b should be positive integer");
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;
1222
- }
1223
- return power_with_fixnum(a, y);
1354
+ return dec_power(1, &y, x);
1224
1355
  }
1225
1356
 
1226
1357
  static int
@@ -1890,7 +2021,7 @@ math_ldexp10(VALUE module UNUSED, VALUE x, VALUE exp)
1890
2021
  if (DEC_VALUE_ISINF(x))
1891
2022
  return x;
1892
2023
 
1893
- if (TYPE(x) == T_FIXNUM || TYPE(x) == T_BIGNUM) {
2024
+ if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM) {
1894
2025
  integer = Qtrue;
1895
2026
  d = inum_to_dec(x);
1896
2027
  }
@@ -1922,7 +2053,7 @@ math_frexp10(VALUE module UNUSED, VALUE x)
1922
2053
  if (DEC_VALUE_ISINF(x))
1923
2054
  return rb_assoc_new(x, INT2FIX(0));
1924
2055
 
1925
- if (TYPE(x) == T_FIXNUM || TYPE(x) == T_BIGNUM) {
2056
+ if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM) {
1926
2057
  integer = Qtrue;
1927
2058
  d = inum_to_dec(x);
1928
2059
  }
@@ -1971,6 +2102,100 @@ math_frexp10(VALUE module UNUSED, VALUE x)
1971
2102
  return rb_assoc_new(WrapDecimal(mant), LONG2NUM(exp));
1972
2103
  }
1973
2104
 
2105
+ /* :nodoc: */
2106
+ static VALUE
2107
+ math_exp(int argc, VALUE *argv, VALUE module UNUSED) /* (x, scale, rounding=:down) */
2108
+ {
2109
+ VALUE x, scale, mode;
2110
+ int negative;
2111
+ VALUE z, x1, y, i, d;
2112
+ VALUE argv2[3]; /* for divide / round */
2113
+
2114
+ rb_scan_args(argc, argv, "21", &x, &scale, &mode);
2115
+ switch (argc) {
2116
+ case 3:
2117
+ Check_Type(mode, T_SYMBOL);
2118
+ if (!valid_rounding_mode_p(mode)) {
2119
+ rb_raise(rb_eArgError, "invalid rounding mode %s",
2120
+ RSTRING_PTR(rb_inspect(mode)));
2121
+ }
2122
+ /* fall through */
2123
+ default:
2124
+ Check_Type(scale, T_FIXNUM);
2125
+ if (NIL_P(mode)) mode = ROUND_DOWN;
2126
+ break;
2127
+ }
2128
+ if (FIXNUM_P(x) || TYPE(x) == T_BIGNUM) x = WrapDecimal(inum_to_dec(x));
2129
+ if (dec_nan_p(x)) return VALUE_NaN;
2130
+ if (dec_zero_p(x)) return WrapDecimal(dec_raw_new(INT2FIX(1), 0));
2131
+ if (dec_infinite_p(x) != Qnil) {
2132
+ if (x == VALUE_PINF)
2133
+ return VALUE_PINF;
2134
+ return WrapDecimal(dec_raw_new(DEC_PZERO, 0));
2135
+ }
2136
+ negative = dec_lt(x, INT2FIX(0));
2137
+ if (negative) x = dec_uminus(x);
2138
+
2139
+ y = WrapDecimal(dec_raw_new(INT2FIX(1), 0));
2140
+ x1 = WrapDecimal(dec_raw_new(INT2FIX(1), 0));
2141
+ z = INT2FIX(1);
2142
+ i = INT2FIX(0);
2143
+ argv2[1] = INUM_PLUS(scale, INT2FIX(1));
2144
+ argv2[2] = ROUND_DOWN;
2145
+ for (;;) {
2146
+ x1 = dec_mul(x1, x);
2147
+ INUM_INC(i);
2148
+ z = INUM_MUL(z, i);
2149
+ argv2[0] = z;
2150
+ d = dec_divide(3, argv2, x1);
2151
+ if (dec_zero_p(d)) break;
2152
+ y = dec_plus(y, d);
2153
+ }
2154
+ if (negative) {
2155
+ argv2[0] = y;
2156
+ argv2[1] = scale;
2157
+ argv2[2] = mode;
2158
+ y = dec_divide(3, argv2, WrapDecimal(dec_raw_new(INT2FIX(1), 0)));
2159
+ } else {
2160
+ argv2[0] = scale;
2161
+ argv2[1] = mode;
2162
+ y = dec_round(2, argv2, y);
2163
+ }
2164
+ return y;
2165
+ }
2166
+
2167
+ /* internal use only */
2168
+ static VALUE
2169
+ math_ln(VALUE x, VALUE scale, VALUE mode)
2170
+ {
2171
+ VALUE u, u2, i, d, y;
2172
+ VALUE argv[3], scale_more;
2173
+
2174
+ if (dec_eq(x, INT2FIX(1))) return WrapDecimal(dec_raw_new(DEC_PZERO, 0));
2175
+
2176
+ scale_more = LONG2FIX(FIX2LONG(scale) + 1);
2177
+ argv[0] = dec_plus(x, INT2FIX(1));
2178
+ argv[1] = scale_more;
2179
+ argv[2] = ROUND_DOWN;
2180
+ u = dec_divide(3, argv, dec_minus(x, INT2FIX(1)));
2181
+
2182
+ u2 = dec_mul(u, u);
2183
+ y = u;
2184
+ i = INT2FIX(1);
2185
+ for (;;) {
2186
+ u = dec_floor(1, &scale_more, dec_mul(u, u2));
2187
+ i = INUM_PLUS(i, INT2FIX(2));
2188
+ argv[0] = i;
2189
+ d = dec_divide(3, argv, u);
2190
+ if (dec_zero_p(d)) break;
2191
+ y = dec_plus(y, d);
2192
+ }
2193
+ y = dec_mul(y, INT2FIX(2));
2194
+ argv[0] = scale;
2195
+ argv[1] = mode;
2196
+ return dec_round(2, argv, y);
2197
+ }
2198
+
1974
2199
  /* initialize minimum Math functions in C */
1975
2200
  /* not documented yet. */
1976
2201
  static void
@@ -1979,6 +2204,7 @@ init_math(void)
1979
2204
  mMath = rb_define_module_under(cDecimal, "Math");
1980
2205
  rb_define_module_function(mMath, "ldexp10", math_ldexp10, 2);
1981
2206
  rb_define_module_function(mMath, "frexp10", math_frexp10, 1);
2207
+ rb_define_module_function(mMath, "exp", math_exp, -1);
1982
2208
  }
1983
2209
 
1984
2210
 
@@ -2071,6 +2297,7 @@ Init_decimal(void)
2071
2297
  rb_define_method(cDecimal, "%", dec_mod, 1);
2072
2298
  rb_define_method(cDecimal, "modulo", dec_mod, 1);
2073
2299
  rb_define_method(cDecimal, "divmod", dec_divmod, 1);
2300
+ rb_define_method(cDecimal, "power", dec_power, -1);
2074
2301
  rb_define_method(cDecimal, "**", dec_pow, 1);
2075
2302
  rb_define_method(cDecimal, "==", dec_eq, 1);
2076
2303
  rb_define_method(cDecimal, "<=>", dec_cmp, 1);