bigdecimal 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ # -*- ruby -*-
2
+ _VERSION = "1.1.0"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "bigdecimal"
6
+ s.version = _VERSION
7
+ s.date = "2011-07-30"
8
+ s.summary = "Arbitrary-precision decimal floating-point number library."
9
+ s.homepage = "http://www.ruby-lang.org"
10
+ s.email = "mrkn@mrkn.jp"
11
+ s.description = "This library provides arbitrary-precision decimal floating-point number class."
12
+ s.authors = ["Kenta Murata", "Shigeo Kobayashi"]
13
+ s.require_path = %[.]
14
+ s.files = %w[
15
+ bigdecimal.gemspec
16
+ bigdecimal.c
17
+ bigdecimal.h
18
+ README
19
+ depend extconf.rb
20
+ lib/bigdecimal/jacobian.rb
21
+ lib/bigdecimal/ludcmp.rb
22
+ lib/bigdecimal/math.rb
23
+ lib/bigdecimal/newton.rb
24
+ lib/bigdecimal/util.rb
25
+ sample/linear.rb
26
+ sample/nlsolve.rb
27
+ sample/pi.rb
28
+ ]
29
+ s.extensions = %w[extconf.rb]
30
+ end
data/bigdecimal.h ADDED
@@ -0,0 +1,291 @@
1
+ /*
2
+ *
3
+ * Ruby BigDecimal(Variable decimal precision) extension library.
4
+ *
5
+ * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)
6
+ *
7
+ * You may distribute under the terms of either the GNU General Public
8
+ * License or the Artistic License, as specified in the README file
9
+ * of this BigDecimal distribution.
10
+ *
11
+ * NOTES:
12
+ * 2003-03-28 V1.0 checked in.
13
+ *
14
+ */
15
+
16
+ #ifndef RUBY_BIG_DECIMAL_H
17
+ #define RUBY_BIG_DECIMAL_H 1
18
+
19
+ #include "ruby/ruby.h"
20
+ #include <float.h>
21
+
22
+ #if defined(__cplusplus)
23
+ extern "C" {
24
+ #if 0
25
+ } /* satisfy cc-mode */
26
+ #endif
27
+ #endif
28
+
29
+ #ifndef HAVE_LABS
30
+ static inline long
31
+ labs(long const x)
32
+ {
33
+ if (x < 0) return -x;
34
+ return x;
35
+ }
36
+ #endif
37
+
38
+ #ifndef HAVE_LLABS
39
+ static inline LONG_LONG
40
+ llabs(LONG_LONG const x)
41
+ {
42
+ if (x < 0) return -x;
43
+ return x;
44
+ }
45
+ #endif
46
+
47
+ #ifdef vabs
48
+ # undef vabs
49
+ #endif
50
+ #if SIZEOF_VALUE <= SIZEOF_INT
51
+ # define vabs abs
52
+ #elif SIZEOF_VALUE <= SIZEOF_LONG
53
+ # define vabs labs
54
+ #elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
55
+ # define vabs llabs
56
+ #endif
57
+
58
+ extern VALUE rb_cBigDecimal;
59
+
60
+ #if 0 || SIZEOF_BDIGITS >= 16
61
+ # define RMPD_COMPONENT_FIGURES 38
62
+ # define RMPD_BASE ((BDIGIT)100000000000000000000000000000000000000U)
63
+ #elif SIZEOF_BDIGITS >= 8
64
+ # define RMPD_COMPONENT_FIGURES 19
65
+ # define RMPD_BASE ((BDIGIT)10000000000000000000U)
66
+ #elif SIZEOF_BDIGITS >= 4
67
+ # define RMPD_COMPONENT_FIGURES 9
68
+ # define RMPD_BASE ((BDIGIT)1000000000U)
69
+ #elif SIZEOF_BDIGITS >= 2
70
+ # define RMPD_COMPONENT_FIGURES 4
71
+ # define RMPD_BASE ((BDIGIT)10000U)
72
+ #else
73
+ # define RMPD_COMPONENT_FIGURES 2
74
+ # define RMPD_BASE ((BDIGIT)100U)
75
+ #endif
76
+
77
+
78
+ /*
79
+ * NaN & Infinity
80
+ */
81
+ #define SZ_NaN "NaN"
82
+ #define SZ_INF "Infinity"
83
+ #define SZ_PINF "+Infinity"
84
+ #define SZ_NINF "-Infinity"
85
+
86
+ /*
87
+ * #define VP_EXPORT other than static to let VP_ routines
88
+ * be called from outside of this module.
89
+ */
90
+ #define VP_EXPORT static
91
+
92
+ /* Exception codes */
93
+ #define VP_EXCEPTION_ALL ((unsigned short)0x00FF)
94
+ #define VP_EXCEPTION_INFINITY ((unsigned short)0x0001)
95
+ #define VP_EXCEPTION_NaN ((unsigned short)0x0002)
96
+ #define VP_EXCEPTION_UNDERFLOW ((unsigned short)0x0004)
97
+ #define VP_EXCEPTION_OVERFLOW ((unsigned short)0x0001) /* 0x0008) */
98
+ #define VP_EXCEPTION_ZERODIVIDE ((unsigned short)0x0010)
99
+
100
+ /* Following 2 exceptions cann't controlled by user */
101
+ #define VP_EXCEPTION_OP ((unsigned short)0x0020)
102
+ #define VP_EXCEPTION_MEMORY ((unsigned short)0x0040)
103
+
104
+ #define RMPD_EXCEPTION_MODE_DEFAULT 0U
105
+
106
+ /* Computation mode */
107
+ #define VP_ROUND_MODE ((unsigned short)0x0100)
108
+ #define VP_ROUND_UP 1
109
+ #define VP_ROUND_DOWN 2
110
+ #define VP_ROUND_HALF_UP 3
111
+ #define VP_ROUND_HALF_DOWN 4
112
+ #define VP_ROUND_CEIL 5
113
+ #define VP_ROUND_FLOOR 6
114
+ #define VP_ROUND_HALF_EVEN 7
115
+
116
+ #define RMPD_ROUNDING_MODE_DEFAULT VP_ROUND_HALF_UP
117
+
118
+ #define VP_SIGN_NaN 0 /* NaN */
119
+ #define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */
120
+ #define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */
121
+ #define VP_SIGN_POSITIVE_FINITE 2 /* Positive finite number */
122
+ #define VP_SIGN_NEGATIVE_FINITE -2 /* Negative finite number */
123
+ #define VP_SIGN_POSITIVE_INFINITE 3 /* Positive infinite number */
124
+ #define VP_SIGN_NEGATIVE_INFINITE -3 /* Negative infinite number */
125
+
126
+ #ifdef __GNUC__
127
+ #define FLEXIBLE_ARRAY_SIZE 0
128
+ #else
129
+ #define FLEXIBLE_ARRAY_SIZE 1
130
+ #endif
131
+
132
+ /*
133
+ * VP representation
134
+ * r = 0.xxxxxxxxx *BASE**exponent
135
+ */
136
+ typedef struct {
137
+ VALUE obj; /* Back pointer(VALUE) for Ruby object. */
138
+ size_t MaxPrec; /* Maximum precision size */
139
+ /* This is the actual size of pfrac[] */
140
+ /*(frac[0] to frac[MaxPrec] are available). */
141
+ size_t Prec; /* Current precision size. */
142
+ /* This indicates how much the. */
143
+ /* the array frac[] is actually used. */
144
+ SIGNED_VALUE exponent; /* Exponent part. */
145
+ short sign; /* Attributes of the value. */
146
+ /*
147
+ * ==0 : NaN
148
+ * 1 : Positive zero
149
+ * -1 : Negative zero
150
+ * 2 : Positive number
151
+ * -2 : Negative number
152
+ * 3 : Positive infinite number
153
+ * -3 : Negative infinite number
154
+ */
155
+ short flag; /* Not used in vp_routines,space for user. */
156
+ BDIGIT frac[FLEXIBLE_ARRAY_SIZE]; /* Array of fraction part. */
157
+ } Real;
158
+
159
+ /*
160
+ * ------------------
161
+ * EXPORTables.
162
+ * ------------------
163
+ */
164
+
165
+ VP_EXPORT Real *
166
+ VpNewRbClass(size_t mx, char const *str, VALUE klass);
167
+
168
+ VP_EXPORT Real *VpCreateRbObject(size_t mx,const char *str);
169
+
170
+ static inline BDIGIT
171
+ rmpd_base_value(void) { return RMPD_BASE; }
172
+ static inline size_t
173
+ rmpd_component_figures(void) { return RMPD_COMPONENT_FIGURES; }
174
+ static inline size_t
175
+ rmpd_double_figures(void) { return 1+DBL_DIG; }
176
+
177
+ #define VpBaseFig() rmpd_component_figures()
178
+ #define VpDblFig() rmpd_double_figures()
179
+ #define VpBaseVal() rmpd_base_value()
180
+
181
+ /* Zero,Inf,NaN (isinf(),isnan() used to check) */
182
+ VP_EXPORT double VpGetDoubleNaN(void);
183
+ VP_EXPORT double VpGetDoublePosInf(void);
184
+ VP_EXPORT double VpGetDoubleNegInf(void);
185
+ VP_EXPORT double VpGetDoubleNegZero(void);
186
+
187
+ /* These 2 functions added at v1.1.7 */
188
+ VP_EXPORT size_t VpGetPrecLimit(void);
189
+ VP_EXPORT size_t VpSetPrecLimit(size_t n);
190
+
191
+ /* Round mode */
192
+ VP_EXPORT int VpIsRoundMode(unsigned short n);
193
+ VP_EXPORT unsigned short VpGetRoundMode(void);
194
+ VP_EXPORT unsigned short VpSetRoundMode(unsigned short n);
195
+
196
+ VP_EXPORT int VpException(unsigned short f,const char *str,int always);
197
+ #if 0 /* unused */
198
+ VP_EXPORT int VpIsNegDoubleZero(double v);
199
+ #endif
200
+ VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt);
201
+ VP_EXPORT size_t VpInit(BDIGIT BaseVal);
202
+ VP_EXPORT void *VpMemAlloc(size_t mb);
203
+ VP_EXPORT void *VpMemRealloc(void *ptr, size_t mb);
204
+ VP_EXPORT void VpFree(Real *pv);
205
+ VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal);
206
+ VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw);
207
+ VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation);
208
+ VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b);
209
+ VP_EXPORT size_t VpDivd(Real *c,Real *r,Real *a,Real *b);
210
+ VP_EXPORT int VpComp(Real *a,Real *b);
211
+ VP_EXPORT ssize_t VpExponent10(Real *a);
212
+ VP_EXPORT void VpSzMantissa(Real *a,char *psz);
213
+ VP_EXPORT int VpToSpecialString(Real *a,char *psz,int fPlus);
214
+ VP_EXPORT void VpToString(Real *a, char *psz, size_t fFmt, int fPlus);
215
+ VP_EXPORT void VpToFString(Real *a, char *psz, size_t fFmt, int fPlus);
216
+ VP_EXPORT int VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne);
217
+ VP_EXPORT int VpVtoD(double *d, SIGNED_VALUE *e, Real *m);
218
+ VP_EXPORT void VpDtoV(Real *m,double d);
219
+ #if 0 /* unused */
220
+ VP_EXPORT void VpItoV(Real *m,S_INT ival);
221
+ #endif
222
+ VP_EXPORT int VpSqrt(Real *y,Real *x);
223
+ VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t il);
224
+ VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf);
225
+ VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf);
226
+ VP_EXPORT void VpFrac(Real *y, Real *x);
227
+ VP_EXPORT int VpPower(Real *y, Real *x, SIGNED_VALUE n);
228
+
229
+ /* VP constants */
230
+ VP_EXPORT Real *VpOne(void);
231
+
232
+ /*
233
+ * ------------------
234
+ * MACRO definitions.
235
+ * ------------------
236
+ */
237
+ #define Abs(a) (((a)>= 0)?(a):(-(a)))
238
+ #define Max(a, b) (((a)>(b))?(a):(b))
239
+ #define Min(a, b) (((a)>(b))?(b):(a))
240
+
241
+ #define VpMaxPrec(a) ((a)->MaxPrec)
242
+ #define VpPrec(a) ((a)->Prec)
243
+ #define VpGetFlag(a) ((a)->flag)
244
+
245
+ /* Sign */
246
+
247
+ /* VpGetSign(a) returns 1,-1 if a>0,a<0 respectively */
248
+ #define VpGetSign(a) (((a)->sign>0)?1:(-1))
249
+ /* Change sign of a to a>0,a<0 if s = 1,-1 respectively */
250
+ #define VpChangeSign(a,s) {if((s)>0) (a)->sign=(short)Abs((ssize_t)(a)->sign);else (a)->sign=-(short)Abs((ssize_t)(a)->sign);}
251
+ /* Sets sign of a to a>0,a<0 if s = 1,-1 respectively */
252
+ #define VpSetSign(a,s) {if((s)>0) (a)->sign=(short)VP_SIGN_POSITIVE_FINITE;else (a)->sign=(short)VP_SIGN_NEGATIVE_FINITE;}
253
+
254
+ /* 1 */
255
+ #define VpSetOne(a) {(a)->Prec=(a)->exponent=(a)->frac[0]=1;(a)->sign=VP_SIGN_POSITIVE_FINITE;}
256
+
257
+ /* ZEROs */
258
+ #define VpIsPosZero(a) ((a)->sign==VP_SIGN_POSITIVE_ZERO)
259
+ #define VpIsNegZero(a) ((a)->sign==VP_SIGN_NEGATIVE_ZERO)
260
+ #define VpIsZero(a) (VpIsPosZero(a) || VpIsNegZero(a))
261
+ #define VpSetPosZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_ZERO)
262
+ #define VpSetNegZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_ZERO)
263
+ #define VpSetZero(a,s) ( ((s)>0)?VpSetPosZero(a):VpSetNegZero(a) )
264
+
265
+ /* NaN */
266
+ #define VpIsNaN(a) ((a)->sign==VP_SIGN_NaN)
267
+ #define VpSetNaN(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NaN)
268
+
269
+ /* Infinity */
270
+ #define VpIsPosInf(a) ((a)->sign==VP_SIGN_POSITIVE_INFINITE)
271
+ #define VpIsNegInf(a) ((a)->sign==VP_SIGN_NEGATIVE_INFINITE)
272
+ #define VpIsInf(a) (VpIsPosInf(a) || VpIsNegInf(a))
273
+ #define VpIsDef(a) ( !(VpIsNaN(a)||VpIsInf(a)) )
274
+ #define VpSetPosInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_INFINITE)
275
+ #define VpSetNegInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_INFINITE)
276
+ #define VpSetInf(a,s) ( ((s)>0)?VpSetPosInf(a):VpSetNegInf(a) )
277
+ #define VpHasVal(a) (a->frac[0])
278
+ #define VpIsOne(a) ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1))
279
+ #define VpExponent(a) (a->exponent)
280
+ #ifdef BIGDECIMAL_DEBUG
281
+ int VpVarCheck(Real * v);
282
+ VP_EXPORT int VPrint(FILE *fp,const char *cntl_chr,Real *a);
283
+ #endif /* BIGDECIMAL_DEBUG */
284
+
285
+ #if defined(__cplusplus)
286
+ #if 0
287
+ { /* satisfy cc-mode */
288
+ #endif
289
+ } /* extern "C" { */
290
+ #endif
291
+ #endif /* RUBY_BIG_DECIMAL_H */
data/depend ADDED
@@ -0,0 +1 @@
1
+ bigdecimal.o: bigdecimal.c bigdecimal.h $(hdrdir)/ruby.h
data/extconf.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ have_func("labs", "stdlib.h")
4
+ have_func("llabs", "stdlib.h")
5
+
6
+ create_makefile('bigdecimal')
@@ -0,0 +1,87 @@
1
+ #
2
+ # require 'bigdecimal/jacobian'
3
+ #
4
+ # Provides methods to compute the Jacobian matrix of a set of equations at a
5
+ # point x. In the methods below:
6
+ #
7
+ # f is an Object which is used to compute the Jacobian matrix of the equations.
8
+ # It must provide the following methods:
9
+ #
10
+ # f.values(x):: returns the values of all functions at x
11
+ #
12
+ # f.zero:: returns 0.0
13
+ # f.one:: returns 1.0
14
+ # f.two:: returns 1.0
15
+ # f.ten:: returns 10.0
16
+ #
17
+ # 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.
18
+ #
19
+ # x is the point at which to compute the Jacobian.
20
+ #
21
+ # fx is f.values(x).
22
+ #
23
+ module Jacobian
24
+ module_function
25
+
26
+ # Determines the equality of two numbers by comparing to zero, or using the epsilon value
27
+ def isEqual(a,b,zero=0.0,e=1.0e-8)
28
+ aa = a.abs
29
+ bb = b.abs
30
+ if aa == zero && bb == zero then
31
+ true
32
+ else
33
+ if ((a-b)/(aa+bb)).abs < e then
34
+ true
35
+ else
36
+ false
37
+ end
38
+ end
39
+ end
40
+
41
+
42
+ # Computes the derivative of f[i] at x[i].
43
+ # fx is the value of f at x.
44
+ def dfdxi(f,fx,x,i)
45
+ nRetry = 0
46
+ n = x.size
47
+ xSave = x[i]
48
+ ok = 0
49
+ ratio = f.ten*f.ten*f.ten
50
+ dx = x[i].abs/ratio
51
+ dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps)
52
+ dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps)
53
+ until ok>0 do
54
+ s = f.zero
55
+ deriv = []
56
+ if(nRetry>100) then
57
+ raise "Singular Jacobian matrix. No change at x[" + i.to_s + "]"
58
+ end
59
+ dx = dx*f.two
60
+ x[i] += dx
61
+ fxNew = f.values(x)
62
+ for j in 0...n do
63
+ if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then
64
+ ok += 1
65
+ deriv <<= (fxNew[j]-fx[j])/dx
66
+ else
67
+ deriv <<= f.zero
68
+ end
69
+ end
70
+ x[i] = xSave
71
+ end
72
+ deriv
73
+ end
74
+
75
+ # Computes the Jacobian of f at x. fx is the value of f at x.
76
+ def jacobian(f,fx,x)
77
+ n = x.size
78
+ dfdx = Array::new(n*n)
79
+ for i in 0...n do
80
+ df = dfdxi(f,fx,x,i)
81
+ for j in 0...n do
82
+ dfdx[j*n+i] = df[j]
83
+ end
84
+ end
85
+ dfdx
86
+ end
87
+ end
@@ -0,0 +1,88 @@
1
+ require 'bigdecimal'
2
+
3
+ #
4
+ # Solves a*x = b for x, using LU decomposition.
5
+ #
6
+ module LUSolve
7
+ module_function
8
+
9
+ # Performs LU decomposition of the n by n matrix a.
10
+ def ludecomp(a,n,zero=0,one=1)
11
+ prec = BigDecimal.limit(nil)
12
+ ps = []
13
+ scales = []
14
+ for i in 0...n do # pick up largest(abs. val.) element in each row.
15
+ ps <<= i
16
+ nrmrow = zero
17
+ ixn = i*n
18
+ for j in 0...n do
19
+ biggst = a[ixn+j].abs
20
+ nrmrow = biggst if biggst>nrmrow
21
+ end
22
+ if nrmrow>zero then
23
+ scales <<= one.div(nrmrow,prec)
24
+ else
25
+ raise "Singular matrix"
26
+ end
27
+ end
28
+ n1 = n - 1
29
+ for k in 0...n1 do # Gaussian elimination with partial pivoting.
30
+ biggst = zero;
31
+ for i in k...n do
32
+ size = a[ps[i]*n+k].abs*scales[ps[i]]
33
+ if size>biggst then
34
+ biggst = size
35
+ pividx = i
36
+ end
37
+ end
38
+ raise "Singular matrix" if biggst<=zero
39
+ if pividx!=k then
40
+ j = ps[k]
41
+ ps[k] = ps[pividx]
42
+ ps[pividx] = j
43
+ end
44
+ pivot = a[ps[k]*n+k]
45
+ for i in (k+1)...n do
46
+ psin = ps[i]*n
47
+ a[psin+k] = mult = a[psin+k].div(pivot,prec)
48
+ if mult!=zero then
49
+ pskn = ps[k]*n
50
+ for j in (k+1)...n do
51
+ a[psin+j] -= mult.mult(a[pskn+j],prec)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ raise "Singular matrix" if a[ps[n1]*n+n1] == zero
57
+ ps
58
+ end
59
+
60
+ # Solves a*x = b for x, using LU decomposition.
61
+ #
62
+ # a is a matrix, b is a constant vector, x is the solution vector.
63
+ #
64
+ # ps is the pivot, a vector which indicates the permutation of rows performed
65
+ # during LU decomposition.
66
+ def lusolve(a,b,ps,zero=0.0)
67
+ prec = BigDecimal.limit(nil)
68
+ n = ps.size
69
+ x = []
70
+ for i in 0...n do
71
+ dot = zero
72
+ psin = ps[i]*n
73
+ for j in 0...i do
74
+ dot = a[psin+j].mult(x[j],prec) + dot
75
+ end
76
+ x <<= b[ps[i]] - dot
77
+ end
78
+ (n-1).downto(0) do |i|
79
+ dot = zero
80
+ psin = ps[i]*n
81
+ for j in (i+1)...n do
82
+ dot = a[psin+j].mult(x[j],prec) + dot
83
+ end
84
+ x[i] = (x[i]-dot).div(a[psin+i],prec)
85
+ end
86
+ x
87
+ end
88
+ end