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)
23extern "C" {
24#if 0
25} /* satisfy cc-mode */
26#endif
27#endif
28
29#ifndef HAVE_LABS
30static inline long
31labs(long const x)
32{
33    if (x < 0) return -x;
34    return x;
35}
36#endif
37
38#ifndef HAVE_LLABS
39static inline LONG_LONG
40llabs(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
58extern 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 */
136typedef 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
165VP_EXPORT  Real *
166VpNewRbClass(size_t mx, char const *str, VALUE klass);
167
168VP_EXPORT  Real *VpCreateRbObject(size_t mx,const char *str);
169
170static inline BDIGIT
171rmpd_base_value(void) { return RMPD_BASE; }
172static inline size_t
173rmpd_component_figures(void) { return RMPD_COMPONENT_FIGURES; }
174static inline size_t
175rmpd_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) */
182VP_EXPORT double VpGetDoubleNaN(void);
183VP_EXPORT double VpGetDoublePosInf(void);
184VP_EXPORT double VpGetDoubleNegInf(void);
185VP_EXPORT double VpGetDoubleNegZero(void);
186
187/* These 2 functions added at v1.1.7 */
188VP_EXPORT size_t VpGetPrecLimit(void);
189VP_EXPORT size_t VpSetPrecLimit(size_t n);
190
191/* Round mode */
192VP_EXPORT int            VpIsRoundMode(unsigned short n);
193VP_EXPORT unsigned short VpGetRoundMode(void);
194VP_EXPORT unsigned short VpSetRoundMode(unsigned short n);
195
196VP_EXPORT int VpException(unsigned short f,const char *str,int always);
197#if 0  /* unused */
198VP_EXPORT int VpIsNegDoubleZero(double v);
199#endif
200VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt);
201VP_EXPORT size_t VpInit(BDIGIT BaseVal);
202VP_EXPORT void *VpMemAlloc(size_t mb);
203VP_EXPORT void *VpMemRealloc(void *ptr, size_t mb);
204VP_EXPORT void VpFree(Real *pv);
205VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal);
206VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw);
207VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation);
208VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b);
209VP_EXPORT size_t VpDivd(Real *c,Real *r,Real *a,Real *b);
210VP_EXPORT int VpComp(Real *a,Real *b);
211VP_EXPORT ssize_t VpExponent10(Real *a);
212VP_EXPORT void VpSzMantissa(Real *a,char *psz);
213VP_EXPORT int VpToSpecialString(Real *a,char *psz,int fPlus);
214VP_EXPORT void VpToString(Real *a, char *psz, size_t fFmt, int fPlus);
215VP_EXPORT void VpToFString(Real *a, char *psz, size_t fFmt, int fPlus);
216VP_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);
217VP_EXPORT int VpVtoD(double *d, SIGNED_VALUE *e, Real *m);
218VP_EXPORT void VpDtoV(Real *m,double d);
219#if 0  /* unused */
220VP_EXPORT void VpItoV(Real *m,S_INT ival);
221#endif
222VP_EXPORT int VpSqrt(Real *y,Real *x);
223VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t il);
224VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf);
225VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf);
226VP_EXPORT void VpFrac(Real *y, Real *x);
227VP_EXPORT int VpPower(Real *y, Real *x, SIGNED_VALUE n);
228
229/* VP constants */
230VP_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
281int VpVarCheck(Real * v);
282VP_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 */
292