From 04b3280a4137fa1e62c9b40a4c83dc527877c8d2 Mon Sep 17 00:00:00 2001 From: matz Date: Thu, 29 Jun 2006 09:09:33 +0000 Subject: * ext/bigdecimal/bigdecimal.c: add RDoc document. a patch from mathew . [ruby-core:07050] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@10428 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/bigdecimal/bigdecimal.c | 601 +++++++++++++++++++++++++++++- ext/bigdecimal/lib/bigdecimal/jacobian.rb | 26 +- ext/bigdecimal/lib/bigdecimal/ludcmp.rb | 9 +- ext/bigdecimal/lib/bigdecimal/math.rb | 45 ++- ext/bigdecimal/lib/bigdecimal/newton.rb | 30 +- ext/bigdecimal/lib/bigdecimal/util.rb | 26 +- 6 files changed, 699 insertions(+), 38 deletions(-) (limited to 'ext/bigdecimal') diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 7f3f1520ee..9b31c969dd 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -41,8 +41,125 @@ VALUE rb_cBigDecimal; */ #define DoSomeOne(x,y) rb_num_coerce_bin(x,y) +#if 0 +/* BigDecimal provides arbitrary-precision floating point decimal arithmetic. + * + * Copyright (C) 2002 by Shigeo Kobayashi . + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file + * of the BigDecimal distribution. + * + * Documented by mathew . + * + * = Introduction + * + * Ruby provides built-in support for arbitrary precision integer arithmetic. + * For example: + * + * 42**13 -> 1265437718438866624512 + * + * BigDecimal provides similar support for very large or very accurate floating + * point numbers. + * + * Decimal arithmetic is also useful for general calculation, because it + * provides the correct answers people expect--whereas normal binary floating + * point arithmetic often introduces subtle errors because of the conversion + * between base 10 and base 2. For example, try: + * + * sum = 0 + * for i in (1..10000) + * sum = sum + 0.0001 + * end + * print sum + * + * and contrast with the output from: + * + * require 'bigdecimal' + * + * sum = BigDecimal.new("0") + * for i in (1..10000) + * sum = sum + BigDecimal.new("0.0001") + * end + * print sum + * + * Similarly: + * + * (BigDecimal.new("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") -> true + * + * (1.2 - 1.0) == 0.2 -> false + * + * = Special features of accurate decimal arithmetic + * + * Because BigDecimal is more accurate than normal binary floating point + * arithmetic, it requires some special values. + * + * == Infinity + * + * BigDecimal sometimes needs to return infinity, for example if you divide + * a value by zero. + * + * BigDecimal.new("1.0") / BigDecimal.new("0.0") -> infinity + * + * BigDecimal.new("-1.0") / BigDecimal.new("0.0") -> -infinity + * + * You can represent infinite numbers to BigDecimal using the strings + * 'Infinity', '+Infinity' and '-Infinity' (case-sensitive) + * + * == Not a Number + * + * When a computation results in an undefined value, the special value NaN + * (for 'not a number') is returned. + * + * Example: + * + * BigDecimal.new("0.0") / BigDecimal.new("0.0") -> NaN + * + * You can also create undefined values. NaN is never considered to be the + * same as any other value, even NaN itself: + * + * n = BigDecimal.new('NaN') + * + * n == 0.0 -> nil + * + * n == n -> nil + * + * == Positive and negative zero + * + * If a computation results in a value which is too small to be represented as + * a BigDecimal within the currently specified limits of precision, zero must + * be returned. + * + * If the value which is too small to be represented is negative, a BigDecimal + * value of negative zero is returned. If the value is positive, a value of + * positive zero is returned. + * + * BigDecimal.new("1.0") / BigDecimal.new("-Infinity") -> -0.0 + * + * BigDecimal.new("1.0") / BigDecimal.new("Infinity") -> 0.0 + * + * (See BigDecimal.mode for how to specify limits of precision.) + * + * Note that -0.0 and 0.0 are considered to be the same for the purposes of + * comparison. + * + * Note also that in mathematics, there is no particular concept of negative + * or positive zero; true mathematical zero has no sign. + */ +void +Init_BigDecimal() +{ + /* This is a #if-ed out function to fool Rdoc into documenting the class. */ + /* The real init function is Init_bigdecimal() further down. */ +} +#endif + +void + /* - * **** BigDecimal version **** + * Returns the BigDecimal version number. + * + * Ruby 1.8.0 returns 1.0.0. + * Ruby 1.8.1 thru 1.8.3 return 1.0.1. */ static VALUE BigDecimal_version(VALUE self) @@ -132,12 +249,28 @@ SomeOneMayDoIt: return NULL; /* NULL means to coerce */ } +/* call-seq: + * BigDecimal.double_fig + * + * The BigDecimal.double_fig class method returns the number of digits a + * Float number is allowed to have. The result depends upon the CPU and OS + * in use. + */ static VALUE BigDecimal_double_fig(VALUE self) { return INT2FIX(VpDblFig()); } +/* call-seq: + * precs + * + * Returns an Array of two Integer values. + * + * The first value is the current number of significant digits in the + * BigDecimal. The second value is the maximum number of significant digits + * for the BigDecimal. + */ static VALUE BigDecimal_prec(VALUE self) { @@ -188,6 +321,9 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self) return rb_str_new2(psz); } +/* + * Internal method used to provide marshalling support. See the Marshal module. + */ static VALUE BigDecimal_load(VALUE self, VALUE str) { @@ -213,6 +349,44 @@ BigDecimal_load(VALUE self, VALUE str) return ToValue(pv); } + /* call-seq: + * BigDecimal.mode(mode, value) + * + * Controls handling of arithmetic exceptions and rounding. If no value + * is supplied, the current value is returned. + * + * Six values of the mode parameter control the handling of arithmetic + * exceptions: + * + * BigDecimal::EXCEPTION_NaN + * BigDecimal::EXCEPTION_INFINITY + * BigDecimal::EXCEPTION_UNDERFLOW + * BigDecimal::EXCEPTION_OVERFLOW + * BigDecimal::EXCEPTION_ZERODIVIDE + * BigDecimal::EXCEPTION_ALL + * + * For each mode parameter above, if the value set is false, computation + * continues after an arithmetic exception of the appropriate type. + * When computation continues, results are as follows: + * + * EXCEPTION_NaN:: NaN + * EXCEPTION_INFINITY:: +infinity or -infinity + * EXCEPTION_UNDERFLOW:: 0 + * EXCEPTION_OVERFLOW:: +infinity or -infinity + * EXCEPTION_ZERODIVIDE:: +infinity or -infinity + * + * One value of the mode parameter controls the rounding of numeric values: + * BigDecimal::ROUND_MODE. The values it can take are: + * + * ROUND_UP:: round away from zero + * ROUND_DOWN:: round towards zero (truncate) + * ROUND_HALF_UP:: round up if the appropriate digit >= 5, otherwise truncate (default) + * ROUND_HALF_DOWN:: round up if the appropriate digit >= 6, otherwise truncate + * ROUND_HALF_EVEN:: round towards the even neighbor (Banker's rounding) + * ROUND_CEILING:: round towards positive infinity (ceil) + * ROUND_FLOOR:: round towards negative infinity (floor) + * + */ static VALUE BigDecimal_mode(int argc, VALUE *argv, VALUE self) { @@ -309,7 +483,7 @@ VpCreateRbObject(U_LONG mx, char *str) return pv; } - +/* Returns True if the value is Not a Number */ static VALUE BigDecimal_IsNaN(VALUE self) { @@ -318,6 +492,7 @@ BigDecimal_IsNaN(VALUE self) return Qfalse; } +/* Returns True if the value is infinite */ static VALUE BigDecimal_IsInfinite(VALUE self) { @@ -327,6 +502,7 @@ BigDecimal_IsInfinite(VALUE self) return Qnil; } +/* Returns True if the value is finite (not NaN or infinite) */ static VALUE BigDecimal_IsFinite(VALUE self) { @@ -336,6 +512,10 @@ BigDecimal_IsFinite(VALUE self) return Qtrue; } +/* Returns the value as an integer (Fixnum or Bignum). + * + * If the BigNumber is infinity or NaN, returns nil. + */ static VALUE BigDecimal_to_i(VALUE self) { @@ -399,6 +579,10 @@ BigDecimal_induced_from(VALUE self, VALUE x) return p->obj; } +/* Returns a new Float object having approximately the same value as the + * BigDecimal number. Normal accuracy limits and built-in errors of binary + * Float arithmetic apply. + */ static VALUE BigDecimal_to_f(VALUE self) { @@ -419,6 +603,20 @@ BigDecimal_to_f(VALUE self) return rb_float_new(d*d2); } +/* The coerce method provides support for Ruby type coercion. It is not + * enabled by default. + * + * This means that binary operations like + * / or - can often be performed + * on a BigDecimal and an object of another type, if the other object can + * be coerced into a BigDecimal value. + * + * e.g. + * a = BigDecimal.new("1.0") + * b = a / 2.0 -> 0.5 + * + * Note that coercing a String to a BigDecimal is not supported by default; + * it requires a special compile-time option when building Ruby. + */ static VALUE BigDecimal_coerce(VALUE self, VALUE other) { @@ -440,6 +638,17 @@ BigDecimal_uplus(VALUE self) return self; } + /* call-seq: + * add(value, digits) + * + * Add the specified value. + * + * e.g. + * c = a.add(b,n) + * c = a + b + * + * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode. + */ static VALUE BigDecimal_add(VALUE self, VALUE r) { @@ -467,6 +676,17 @@ BigDecimal_add(VALUE self, VALUE r) return ToValue(c); } + /* call-seq: + * sub(value, digits) + * + * Subtract the specified value. + * + * e.g. + * c = a.sub(b,n) + * c = a - b + * + * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode. + */ static VALUE BigDecimal_sub(VALUE self, VALUE r) { @@ -522,6 +742,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op) rb_bug("Undefined operation in BigDecimalCmp()"); } +/* Returns True if the value is zero. */ static VALUE BigDecimal_zero(VALUE self) { @@ -529,6 +750,7 @@ BigDecimal_zero(VALUE self) return VpIsZero(a) ? Qtrue : Qfalse; } +/* Returns True if the value is non-zero. */ static VALUE BigDecimal_nonzero(VALUE self) { @@ -536,42 +758,84 @@ BigDecimal_nonzero(VALUE self) return VpIsZero(a) ? Qnil : self; } +/* The comparison operator. + * a <=> b is 0 if a == b, 1 if a > b, -1 if a < b. + */ static VALUE BigDecimal_comp(VALUE self, VALUE r) { return BigDecimalCmp(self, r, '*'); } +/* + * Tests for value equality; returns true if the values are equal. + * + * The == and === operators and the eql? method have the same implementation + * for BigDecimal. + * + * Values may be coerced to perform the comparison: + * + * BigDecimal.new('1.0') == 1.0 -> true + */ static VALUE BigDecimal_eq(VALUE self, VALUE r) { return BigDecimalCmp(self, r, '='); } +/* Returns true if the values are not equal in value. Values may be coerced + * to perform the comparison: + * + * BigDecimal.new('1.0') != 1.0 -> false + */ static VALUE BigDecimal_ne(VALUE self, VALUE r) { return BigDecimalCmp(self, r, '!'); } +/* call-seq: + * a < b + * + * Returns true if a is less than b. Values may be coerced to perform the + * comparison (see ==, coerce). + */ static VALUE BigDecimal_lt(VALUE self, VALUE r) { return BigDecimalCmp(self, r, '<'); } +/* call-seq: + * a <= b + * + * Returns true if a is less than or equal to b. Values may be coerced to + * perform the comparison (see ==, coerce). + */ static VALUE BigDecimal_le(VALUE self, VALUE r) { return BigDecimalCmp(self, r, 'L'); } +/* call-seq: + * a > b + * + * Returns true if a is greater than b. Values may be coerced to + * perform the comparison (see ==, coerce). + */ static VALUE BigDecimal_gt(VALUE self, VALUE r) { return BigDecimalCmp(self, r, '>'); } +/* call-seq: + * a >= b + * + * Returns true if a is greater than or equal to b. Values may be coerced to + * perform the comparison (see ==, coerce) + */ static VALUE BigDecimal_ge(VALUE self, VALUE r) { @@ -589,6 +853,17 @@ BigDecimal_neg(VALUE self) return ToValue(c); } + /* call-seq: + * mult(value, digits) + * + * Multiply by the specified value. + * + * e.g. + * c = a.mult(b,n) + * c = a * b + * + * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode. + */ static VALUE BigDecimal_mult(VALUE self, VALUE r) { @@ -627,6 +902,23 @@ BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r) return (VALUE)0; } + /* call-seq: + * div(value, digits) + * quo(value) + * + * Divide by the specified value. + * + * e.g. + * c = a.div(b,n) + * + * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode. + * + * If digits is 0, the result is the same as the / operator. If not, the + * result is an integer BigDecimal, by analogy with Float#div. + * + * The alias quo is provided since div(value, 0) is the same as computing + * the quotient; see divmod. + */ static VALUE BigDecimal_div(VALUE self, VALUE r) /* For c = self/r: with round operation */ @@ -705,6 +997,12 @@ NaN: return (VALUE)0; } +/* call-seq: + * a % b + * a.modulo(b) + * + * Returns the modulus from dividing by b. See divmod. + */ static VALUE BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */ { @@ -755,6 +1053,13 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv) return (VALUE)0; } +/* Returns the remainder from dividing by the value. + * + * If the values divided are of the same sign, the remainder is the same as + * the modulus (see divmod). + * + * Otherwise, the remainder is the modulus minus the value divided by. + */ static VALUE BigDecimal_remainder(VALUE self, VALUE r) /* remainder */ { @@ -765,6 +1070,25 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */ return ToValue(rv); } +/* Divides by the specified value, and returns the quotient and modulus + * as BigDecimal numbers. The quotient is rounded towards negative infinity. + * + * For example: + * + * require 'bigdecimal' + * + * a = BigDecimal.new("42") + * b = BigDecimal.new("9") + * + * q,m = a.divmod(b) + * + * c = q * b + m + * + * a == c -> true + * + * The quotient q is (a/b).floor, and the modulus is the amount that must be + * added to q * b to get a. + */ static VALUE BigDecimal_divmod(VALUE self, VALUE r) { @@ -866,6 +1190,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n) } } +/* Returns the absolute value. + * + * BigDecimal('5').abs -> 5 + * + * BigDecimal('-3').abs -> 3 + */ static VALUE BigDecimal_abs(VALUE self) { @@ -881,6 +1211,13 @@ BigDecimal_abs(VALUE self) return ToValue(c); } +/* call-seq: + * sqrt(n) + * + * Returns the square root of the value. + * + * If n is specified, returns at least that many significant digits. + */ static VALUE BigDecimal_sqrt(VALUE self, VALUE nFig) { @@ -898,6 +1235,8 @@ BigDecimal_sqrt(VALUE self, VALUE nFig) return ToValue(c); } +/* Return the integer part of the number. + */ static VALUE BigDecimal_fix(VALUE self) { @@ -912,6 +1251,28 @@ BigDecimal_fix(VALUE self) return ToValue(c); } +/* call-seq: + * round(n,mode) + * + * Round to the nearest 1 (by default), returning the result as a BigDecimal. + * + * BigDecimal('3.14159').round -> 3 + * + * BigDecimal('8.7').round -> 9 + * + * If n is specified and positive, the fractional part of the result has no + * more than that many digits. + * + * If n is specified and negative, at least that many digits to the left of the + * decimal point will be 0 in the result. + * + * BigDecimal('3.14159').round(3) -> 3.142 + * + * BigDecimal('13345.234').round(-2) -> 13300.0 + * + * The value of the optional mode argument can be used to determine how + * rounding is performed; see BigDecimal.mode. + */ static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self) { @@ -955,6 +1316,25 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) return ToValue(c); } +/* call-seq: + * truncate(n) + * + * Truncate to the nearest 1, returning the result as a BigDecimal. + * + * BigDecimal('3.14159').truncate -> 3 + * + * BigDecimal('8.7').truncate -> 8 + * + * If n is specified and positive, the fractional part of the result has no + * more than that many digits. + * + * If n is specified and negative, at least that many digits to the left of the + * decimal point will be 0 in the result. + * + * BigDecimal('3.14159').truncate(3) -> 3.141 + * + * BigDecimal('13345.234').truncate(-2) -> 13300.0 + */ static VALUE BigDecimal_truncate(int argc, VALUE *argv, VALUE self) { @@ -980,6 +1360,8 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self) return ToValue(c); } +/* Return the fractional part of the number. + */ static VALUE BigDecimal_frac(VALUE self) { @@ -994,6 +1376,25 @@ BigDecimal_frac(VALUE self) return ToValue(c); } +/* call-seq: + * floor(n) + * + * Return the largest integer less than or equal to the value, as a BigDecimal. + * + * BigDecimal('3.14159').floor -> 3 + * + * BigDecimal('-9.1').floor -> -10 + * + * If n is specified and positive, the fractional part of the result has no + * more than that many digits. + * + * If n is specified and negative, at least that + * many digits to the left of the decimal point will be 0 in the result. + * + * BigDecimal('3.14159').floor(3) -> 3.141 + * + * BigDecimal('13345.234').floor(-2) -> 13300.0 + */ static VALUE BigDecimal_floor(int argc, VALUE *argv, VALUE self) { @@ -1019,6 +1420,25 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self) return ToValue(c); } +/* call-seq: + * ceil(n) + * + * Return the smallest integer greater than or equal to the value, as a BigDecimal. + * + * BigDecimal('3.14159').ceil -> 4 + * + * BigDecimal('-9.1').ceil -> -9 + * + * If n is specified and positive, the fractional part of the result has no + * more than that many digits. + * + * If n is specified and negative, at least that + * many digits to the left of the decimal point will be 0 in the result. + * + * BigDecimal('3.14159').ceil(3) -> 3.142 + * + * BigDecimal('13345.234').ceil(-2) -> 13400.0 + */ static VALUE BigDecimal_ceil(int argc, VALUE *argv, VALUE self) { @@ -1044,6 +1464,36 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self) return ToValue(c); } +/* call-seq: + * to_s(s) + * + * Converts the value to a string. + * + * The default format looks like 0.xxxxEnn. + * + * The optional parameter s consists of either an integer; or an optional '+' + * or ' ', followed by an optional number, followed by an optional 'E' or 'F'. + * + * If there is a '+' at the start of s, positive values are returned with + * a leading '+'. + * + * A space at the start of s returns positive values with a leading space. + * + * If s contains a number, a space is inserted after each group of that many + * fractional digits. + * + * If s ends with an 'E', engineering notation (0.xxxxEnn) is used. + * + * If s ends with an 'F', conventional floating point notation is used. + * + * Examples: + * + * BigDecimal.new('-123.45678901234567890').to_s('5F') -> '-123.45678 90123 45678 9' + * + * BigDecimal.new('123.45678901234567890').to_s('+8F') -> '+123.45678901 23456789' + * + * BigDecimal.new('123.45678901234567890').to_s(' F') -> ' 123.4567890123456789' + */ static VALUE BigDecimal_to_s(int argc, VALUE *argv, VALUE self) { @@ -1097,6 +1547,30 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self) return rb_str_new2(psz); } +/* Splits a BigDecimal number into four parts, returned as an array of values. + * + * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0 + * if the BigDecimal is Not a Number. + * + * The second value is a string representing the significant digits of the + * BigDecimal, with no leading zeros. + * + * The third value is the base used for arithmetic (currently always 10) as an + * Integer. + * + * The fourth value is an Integer exponent. + * + * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the + * string of significant digits with no leading zeros, and n is the exponent. + * + * From these values, you can translate a BigDecimal to a float as follows: + * + * sign, significant_digits, base, exponent = a.split + * f = sign * "0.#{significant_digits}".to_f * (base ** exponent) + * + * (Note that the to_f method is provided as a more convenient way to translate + * a BigDecimal to a Float.) + */ static VALUE BigDecimal_split(VALUE self) { @@ -1125,6 +1599,11 @@ BigDecimal_split(VALUE self) return obj; } +/* Returns the exponent of the BigDecimal number, as an Integer. + * + * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string + * of digits with no leading zeros, then n is the exponent. + */ static VALUE BigDecimal_exponent(VALUE self) { @@ -1132,6 +1611,16 @@ BigDecimal_exponent(VALUE self) return INT2NUM(e); } +/* Returns debugging information about the value as a string of comma-separated + * values in angle brackets with a leading #: + * + * BigDecimal.new("1234.5678").inspect -> + * "#" + * + * The first part is the address, the second is the value as a string, and + * the final part ss(mm) is the current number of significant digits and the + * maximum number of significant digits, respectively. + */ static VALUE BigDecimal_inspect(VALUE self) { @@ -1154,6 +1643,13 @@ BigDecimal_inspect(VALUE self) return obj; } +/* call-seq: + * power(n) + * + * Returns the value raised to the power of n. Note that n must be an Integer. + * + * Also available as the operator ** + */ static VALUE BigDecimal_power(VALUE self, VALUE p) { @@ -1197,6 +1693,18 @@ BigDecimal_global_new(int argc, VALUE *argv, VALUE self) return ToValue(pv); } + /* call-seq: + * new(initial, digits) + * + * Create a new BigDecimal object. + * + * initial:: The initial value, as a String. Spaces are ignored, unrecognized characters terminate the value. + * + * digits:: The number of significant digits, as a Fixnum. If omitted or 0, the number of significant digits is determined from the initial value. + * + * The actual number of significant digits used in computation is usually + * larger than the specified number. + */ static VALUE BigDecimal_new(int argc, VALUE *argv, VALUE self) { @@ -1216,6 +1724,18 @@ BigDecimal_new(int argc, VALUE *argv, VALUE self) return ToValue(pv); } + /* call-seq: + * BigDecimal.limit(digits) + * + * Limit the number of significant digits in newly created BigDecimal + * numbers to the specified value. Rounding is performed as necessary, + * as specified by BigDecimal.mode. + * + * A limit of 0, the default, means no upper limit. + * + * The limit specified by this method takes priority over any limit + * specified to instance methods such as ceil, floor, truncate, or round. + */ static VALUE BigDecimal_limit(int argc, VALUE *argv, VALUE self) { @@ -1235,6 +1755,22 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self) return nCur; } +/* Returns the sign of the value. + * + * Returns a positive value if > 0, a negative value if < 0, and a + * zero if == 0. + * + * The specific value returned indicates the type and sign of the BigDecimal, + * as follows: + * + * BigDecimal::SIGN_NaN:: value is Not a Number + * BigDecimal::SIGN_POSITIVE_ZERO:: value is +0 + * BigDecimal::SIGN_NEGATIVE_ZERO:: value is -0 + * BigDecimal::SIGN_POSITIVE_INFINITE:: value is +infinity + * BigDecimal::SIGN_NEGATIVE_INFINITE:: value is -infinity + * BigDecimal::SIGN_POSITIVE_FINITE:: value is positive + * BigDecimal::SIGN_NEGATIVE_FINITE:: value is negative + */ static VALUE BigDecimal_sign(VALUE self) { /* sign */ @@ -1264,37 +1800,94 @@ Init_bigdecimal(void) rb_define_singleton_method(rb_cBigDecimal, "ver", BigDecimal_version, 0); /* Constants definition */ + + /* + * Base value used in internal calculations. On a 32 bit system, BASE + * is 10000, indicating that calculation is done in groups of 4 digits. + * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't + * guarantee that two groups could always be multiplied together without + * overflow.) + */ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((S_INT)VpBaseVal())); /* Exceptions */ + + /* + * Determines whether overflow, underflow or zero divide result in + * an exception being thrown. See BigDecimal.mode. + */ rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL",INT2FIX(VP_EXCEPTION_ALL)); + + /* + * Determines what happens when the result of a computation is not a + * number (NaN). See BigDecimal.mode. + */ rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN)); + + /* + * Determines what happens when the result of a computation is infinity. + * See BigDecimal.mode. + */ rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY",INT2FIX(VP_EXCEPTION_INFINITY)); + + /* + * Determines what happens when the result of a computation is an underflow + * (a result too small to be represented). See BigDecimal.mode. + */ rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW",INT2FIX(VP_EXCEPTION_UNDERFLOW)); + + /* + * Determines what happens when the result of a computation is an underflow + * (a result too large to be represented). See BigDecimal.mode. + */ rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW)); + + /* + * Determines what happens when a division by zero is performed. + * See BigDecimal.mode. + */ rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE)); - /* Computation mode */ + /* + * Determines what happens when a result must be rounded in order to + * fit in the appropriate number of significant digits. See + * BigDecimal.mode. + */ rb_define_const(rb_cBigDecimal, "ROUND_MODE",INT2FIX(VP_ROUND_MODE)); + + /* Indicates that values should be rounded away from zero. See BigDecimal.mode. */ rb_define_const(rb_cBigDecimal, "ROUND_UP",INT2FIX(VP_ROUND_UP)); + /* Indicates that values should be rounded towards zero. See BigDecimal.mode. */ rb_define_const(rb_cBigDecimal, "ROUND_DOWN",INT2FIX(VP_ROUND_DOWN)); + /* Indicates that digits >= 5 should be rounded up, others rounded down. See BigDecimal.mode. */ rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP",INT2FIX(VP_ROUND_HALF_UP)); + /* Indicates that digits >= 6 should be rounded up, others rounded down. See BigDecimal.mode. */ rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN",INT2FIX(VP_ROUND_HALF_DOWN)); + /* Round towards +infinity. See BigDecimal.mode. */ rb_define_const(rb_cBigDecimal, "ROUND_CEILING",INT2FIX(VP_ROUND_CEIL)); + /* Round towards -infinity. See BigDecimal.mode. */ rb_define_const(rb_cBigDecimal, "ROUND_FLOOR",INT2FIX(VP_ROUND_FLOOR)); + /* Round towards the even neighbor. See BigDecimal.mode. */ rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN",INT2FIX(VP_ROUND_HALF_EVEN)); - /* Constants for sign value */ + /* Indicates that a value is not a number. See BigDecimal.sign. */ rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN)); + /* Indicates that a value is +0. See BigDecimal.sign. */ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO",INT2FIX(VP_SIGN_POSITIVE_ZERO)); + /* Indicates that a value is -0. See BigDecimal.sign. */ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO",INT2FIX(VP_SIGN_NEGATIVE_ZERO)); + /* Indicates that a value is positive and finite. See BigDecimal.sign. */ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE",INT2FIX(VP_SIGN_POSITIVE_FINITE)); + /* Indicates that a value is negative and finite. See BigDecimal.sign. */ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE",INT2FIX(VP_SIGN_NEGATIVE_FINITE)); + /* Indicates that a value is positive and infinite. See BigDecimal.sign. */ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE",INT2FIX(VP_SIGN_POSITIVE_INFINITE)); + /* Indicates that a value is negative and infinite. See BigDecimal.sign. */ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE",INT2FIX(VP_SIGN_NEGATIVE_INFINITE)); /* instance methods */ rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0); + rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2); rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2); rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2); diff --git a/ext/bigdecimal/lib/bigdecimal/jacobian.rb b/ext/bigdecimal/lib/bigdecimal/jacobian.rb index 34a60ae67a..d80eeab901 100644 --- a/ext/bigdecimal/lib/bigdecimal/jacobian.rb +++ b/ext/bigdecimal/lib/bigdecimal/jacobian.rb @@ -1,9 +1,27 @@ # -# jacobian.rb +# require 'bigdecimal/jacobian' # -# Computes Jacobian matrix of f at x +# Provides methods to compute the Jacobian matrix of a set of equations at a +# point x. In the methods below: +# +# f is an Object which is used to compute the Jacobian matrix of the equations. +# It must provide the following methods: +# +# f.values(x):: returns the values of all functions at x +# +# f.zero:: returns 0.0 +# f.one:: returns 1.0 +# f.two:: returns 1.0 +# f.ten:: returns 10.0 +# +# f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. +# +# x is the point at which to compute the Jacobian. +# +# fx is f.values(x). # module Jacobian + #-- def isEqual(a,b,zero=0.0,e=1.0e-8) aa = a.abs bb = b.abs @@ -17,7 +35,10 @@ module Jacobian end end end + #++ + # Computes the derivative of f[i] at x[i]. + # fx is the value of f at x. def dfdxi(f,fx,x,i) nRetry = 0 n = x.size @@ -49,6 +70,7 @@ module Jacobian deriv end + # Computes the Jacobian of f at x. fx is the value of f at x. def jacobian(f,fx,x) n = x.size dfdx = Array::new(n*n) diff --git a/ext/bigdecimal/lib/bigdecimal/ludcmp.rb b/ext/bigdecimal/lib/bigdecimal/ludcmp.rb index 1d5d3170cc..8f4888725e 100644 --- a/ext/bigdecimal/lib/bigdecimal/ludcmp.rb +++ b/ext/bigdecimal/lib/bigdecimal/ludcmp.rb @@ -1,7 +1,8 @@ # -# ludcmp.rb +# Solves a*x = b for x, using LU decomposition. # module LUSolve + # Performs LU decomposition of the n by n matrix a. def ludecomp(a,n,zero=0,one=1) prec = BigDecimal.limit(nil) ps = [] @@ -52,6 +53,12 @@ module LUSolve ps end + # Solves a*x = b for x, using LU decomposition. + # + # a is a matrix, b is a constant vector, x is the solution vector. + # + # ps is the pivot, a vector which indicates the permutation of rows performed + # during LU decomposition. def lusolve(a,b,ps,zero=0.0) prec = BigDecimal.limit(nil) n = ps.size diff --git a/ext/bigdecimal/lib/bigdecimal/math.rb b/ext/bigdecimal/lib/bigdecimal/math.rb index 7b3f46ed1a..f3248a3c5c 100644 --- a/ext/bigdecimal/lib/bigdecimal/math.rb +++ b/ext/bigdecimal/lib/bigdecimal/math.rb @@ -1,4 +1,5 @@ # +#-- # Contents: # sqrt(x, prec) # sin (x, prec) @@ -13,19 +14,35 @@ # x ... BigDecimal number to be computed. # |x| must be small enough to get convergence. # prec ... Number of digits to be obtained. +#++ +# +# Provides mathematical functions. +# +# Example: # -# Usage: # require "bigdecimal" -# require "bigdecimal/math.rb" +# require "bigdecimal/math" +# # include BigMath +# # a = BigDecimal((PI(100)/2).to_s) -# puts sin(a,100) # => 0.10000000000000000000......E1 +# puts sin(a,100) # -> 0.10000000000000000000......E1 # module BigMath + + # Computes the square root of x to the specified number of digits of + # precision. + # + # BigDecimal.new('2').sqrt(16).to_s + # -> "0.14142135623730950488016887242096975E1" + # def sqrt(x,prec) x.sqrt(prec) end + # Computes the sine of x to the specified number of digits of precision. + # + # If x is infinite or NaN, returns NaN. def sin(x, prec) raise ArgumentError, "Zero or negative precision for sin" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? @@ -51,6 +68,9 @@ module BigMath y end + # Computes the cosine of x to the specified number of digits of precision. + # + # If x is infinite or NaN, returns NaN. def cos(x, prec) raise ArgumentError, "Zero or negative precision for cos" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? @@ -76,6 +96,10 @@ module BigMath y end + # Computes the arctangent of x to the specified number of digits of precision. + # + # If x is infinite or NaN, returns NaN. + # Raises an argument error if x > 1. def atan(x, prec) raise ArgumentError, "Zero or negative precision for atan" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? @@ -96,6 +120,13 @@ module BigMath y end + # Computes the value of e (the base of natural logarithms) raised to the + # power of x, to the specified number of digits of precision. + # + # If x is infinite or NaN, returns NaN. + # + # BigMath::exp(BigDecimal.new('1'), 10).to_s + # -> "0.271828182845904523536028752390026306410273E1" def exp(x, prec) raise ArgumentError, "Zero or negative precision for exp" if prec <= 0 return BigDecimal("NaN") if x.infinite? || x.nan? @@ -117,6 +148,11 @@ module BigMath y end + # Computes the natural logarithm of x to the specified number of digits + # of precision. + # + # Returns x if x is infinite or NaN. + # def log(x, prec) raise ArgumentError, "Zero or negative argument for log" if x <= 0 || prec <= 0 return x if x.infinite? || x.nan? @@ -138,6 +174,7 @@ module BigMath y*two end + # Computes the value of pi to the specified number of digits of precision. def PI(prec) raise ArgumentError, "Zero or negative argument for PI" if prec <= 0 n = prec + BigDecimal.double_fig @@ -176,6 +213,8 @@ module BigMath pi end + # Computes e (the base of natural logarithms) to the specified number of + # digits of precision. def E(prec) raise ArgumentError, "Zero or negative precision for E" if prec <= 0 n = prec + BigDecimal.double_fig diff --git a/ext/bigdecimal/lib/bigdecimal/newton.rb b/ext/bigdecimal/lib/bigdecimal/newton.rb index f1a55da789..59ac0f7f04 100644 --- a/ext/bigdecimal/lib/bigdecimal/newton.rb +++ b/ext/bigdecimal/lib/bigdecimal/newton.rb @@ -1,24 +1,26 @@ # # newton.rb # -# Solves nonlinear algebraic equation system f = 0 by Newton's method. -# (This program is not dependent on BigDecimal) +# Solves the nonlinear algebraic equation system f = 0 by Newton's method. +# This program is not dependent on BigDecimal. # # To call: # n = nlsolve(f,x) -# where n is the number of iterations required. -# x is the solution vector. -# f is the object to be solved which must have following methods. +# where n is the number of iterations required, +# x is the initial value vector +# f is an Object which is used to compute the values of the equations to be solved. +# It must provide the following methods: # -# f ... Object to compute Jacobian matrix of the equation systems. -# [Methods required for f] -# f.values(x) returns values of all functions at x. -# f.zero returns 0.0 -# f.one returns 1.0 -# f.two returns 1.0 -# f.ten returns 10.0 -# f.eps convergence criterion -# x ... initial values +# f.values(x):: returns the values of all functions at x +# +# f.zero:: returns 0.0 +# f.one:: returns 1.0 +# f.two:: returns 1.0 +# f.ten:: returns 10.0 +# +# f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal. +# +# On exit, x is the solution vector. # require "bigdecimal/ludcmp" require "bigdecimal/jacobian" diff --git a/ext/bigdecimal/lib/bigdecimal/util.rb b/ext/bigdecimal/lib/bigdecimal/util.rb index 1f8d6c7a49..2c17aa6b8e 100644 --- a/ext/bigdecimal/lib/bigdecimal/util.rb +++ b/ext/bigdecimal/lib/bigdecimal/util.rb @@ -1,19 +1,17 @@ # # BigDecimal utility library. -# ---------------------------------------------------------------------- -# Contents: # -# String# -# to_d ... to BigDecimal +# To use these functions, require 'bigdecimal/util' +# +# The following methods are provided to convert other types to BigDecimals: # -# Float# -# to_d ... to BigDecimal +# String#to_d -> BigDecimal +# Float#to_d -> BigDecimal +# Rational#to_d -> BigDecimal # -# BigDecimal# -# to_r ... to Rational +# The following method is provided to convert BigDecimals to other types: # -# Rational# -# to_d ... to BigDecimal +# BigDecimal#to_r -> Rational # # ---------------------------------------------------------------------- # @@ -30,8 +28,8 @@ class String end class BigDecimal < Numeric - # to "nnnnnn.mmm" form digit string - # Use BigDecimal#to_s("F") instead. + # Converts a BigDecimal to a String of the form "nnnnnn.mmm". + # This method is deprecated; use BigDecimal#to_s("F") instead. def to_digits if self.nan? || self.infinite? || self.zero? self.to_s @@ -42,7 +40,7 @@ class BigDecimal < Numeric end end - # Convert BigDecimal to Rational + # Converts a BigDecimal to a Rational. def to_r sign,digits,base,power = self.split numerator = sign*digits.to_i @@ -57,7 +55,7 @@ class BigDecimal < Numeric end class Rational < Numeric - # Convert Rational to BigDecimal + # Converts a Rational to a BigDecimal def to_d(nFig=0) num = self.numerator.to_s if nFig<=0 -- cgit v1.2.3