decimal 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);