-
Notifications
You must be signed in to change notification settings - Fork 0
/
bigdecimal.html
548 lines (509 loc) · 30.3 KB
/
bigdecimal.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
<!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang=en>
<head>
<title>Bigdecimal: Variable precision decimal arithmetic C/C++ API library</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="keywords" content="Bigdecimal: Variable precision decimal arithmetic C/C++ library">
<meta name="description" content="Bigdecimal: Variable precision decimal arithmetic C/C++ library v1.1">
<style type=text/css>
body {color: #3f0f0f; background: #efefef; margin-left: 4em; margin-right: 4em;}
h1 {color: #f0f0f0; background-color: #30A0FF; border-color: #FF00FF; width: 100%;
border-style: solid; border-top-width: 0.1em; border-bottom-width: 0.1em; border-right: none;
border-left: none; padding: 0.1em; font-weight: bold; font-size: 160%;text-align: center;
}
h2 {color: #00007f; background-color: #e7e7ff; border-color: #949494;
width: 100%; border-style: solid;
border-left: 0.6em solid #30A0FF;
border-right: none; border-top-width: 0.1em;
border-bottom-width: 0.1em; padding: 0.1em; font-weight: bold; font-size: 110%;
}
h3 {color: #00007f; padding: 0.2em; font-size: 110%;
border-style: solid;
border-left: none; border-right: none; border-top-width: 0.05em;
border-bottom-width: 0.05em;
}
h4, h5 { color: #000000; padding: 0.2em; font-size: 100%;}
table {
margin-top: 1em; margin-bottom: 1em; margin-left: 2em; margin-right: 1em;
background-color: #000000;
border-spacing: 1px;
}
th {background: #e7e7ff;}
td {background: #f3f7ff;}
dt {margin-top: 0.2em;}
caption { color: #7f0000;font-weight: bold;}
pre { margin-top: 1px;}
code { margin-top: 1px; color: #0000ff;}
kbd { color: #ffffbf;font-weight: bold;}
blockquote { margin-left: 15px;margin-top: 1px;}
.console {background: #8f8f8f;color: #ffffff}
</style>
</head>
<body>
<h1>Bigdecimal: Variable precision decimal arithmetic C/C++ library</h1>
<div align="right">
This software can be redistributed under <a href="https://www.gnu.org/licenses/lgpl-3.0.en.html" target="_new">GNU Lesser General Public License</a>.<br/>
<a href="https://github.com/ShigeoKobayashi/bigdecimal/" target="_new">Every source code of this software can be obtained through GitHub</a><br/>
Copylight (c) 2018 Shigeo Kobayashi. All rights reserved.
</div>
<hr/>
<b>The Bigdecimal is a variable precision decimal arithmetic C/C++ library.</b><br/>
Using Bigdecimal, you can obtain any number of significant digits in your computation.<p/>
This software has been tested on Windows-10(32-bit&64-bit) and Linux(32-bit CentOS-5 & 64-bit CentOS-7).<br/>
To build this software,include "bigdecimal.h" in your program and
<ul>
<li>Linux ... see makefile bundled.</li>
<li>Windows ... follow Visual studio instructions.</li>
</ul>
<ul>
<li><a href="http://www.tinyforest.jp/oss/bigdecimal.zip">Windows binary files(32-bit:vpc.exe,bigdecimal.dll,bigdecimal.lib) can be downloaded here.</a></li>
<li><a name="VPC"/></a>
<a href="./vpc_en.html" target="_new">VPC(Variable Precision Calculator V2) for Bigdecimal API testing</a>
is a simple but usefull programmable calculator using Bigdecimal API(VPC v2 is completely reorganized from v1. For detail of the VPC V2, see the VPC document).
</li>
</ul>
<H2>Introduction</H2>
To use Bigdecimal,"bigdecimal.h" should be included in your C/C++ source program.<br/>
And,Bigdecimal variable must be declared before it is used.<br/>
To declare Bigdecimal variable, use VP_HANDLE which is defined in the bigdecimal.h.<br/>
Bigdecimal variable(VP_HANDLE) is simply a pointer to the structure Real(see bigdecimal.h) which is allocated somewhere and consists of an array of digits and other informations.<br/>
On API interface explanation of this documentation,<u><b>a,b,c,and r are Bigdecimal</b> variables(VP_HANDLE)</u> and <u><b>i,f,m,n are integers</b></u>(signed or unsigned depending on the context) unless otherwise noted.
<a name="ALLOC"/>
<h3>Allocation & Free</h3>
Unlike double or float in C/C++,it is noted that Bigdecimal variable(VP_HANDLE) is a container of digits with certain size.<br/>
Any Bigdecimal variable must be allocated by <b>VpAlloc()</b> or <b>VpMemAlloc()</b> before it is used,and freed(by <b>VpFree()</b>) when it is no more used as following example.
<pre><code>
#include <stdio.h>
#include "bigdecimal.h"
int main(int argc, char* argv[])
{
VP_HANDLE a = <b>VpAlloc("+1234567890.1234567890 123456789000000E0",100)</b>;
VpPrintF (stdout,a); /* ===> 1234567890.1234567890 123456789 */
<b>VpFree(&a)</b>;
return 0;
}
</code></pre>
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td> c = VpAlloc(szVal,m)</td><td>Allocates Bigdecimal variable and sets it's value to szVal.<br/>
szVal is a character string representing any numerical value.<br/>
m is the maximum number of digits c can hold.</td></tr>
<tr><td> c = VpMemAlloc(m)</td><td>Allocates Bigdecimal variable(the value is 0).<br/>
m is the maximum number of digits c can hold.</td></tr>
<tr><td> c = VpClone(a)</td><td>Creates a copy of a.</td></tr>
<tr><td> c = VpLoad(c,szVal)</td><td>
Load the value represented by szVal(which is 'const char *') to existing vp-variable c.<br/>
And returns c,if normally processed,otherwise ERROR code.<br/>
c must have enough length to keep value given by szVal without any rounding operation, otherwise this function fails.
</td></tr>
<tr><td> VpFree(&c)</td><td>Frees memories allocated to c.</td></tr>
</table>
The first argument(st) of VpAlloc() is the string representing numeric number(initial value:+1234567890...),and the second argument is the maximum number of digits the variable 'a' can store(m).<br/>
<b>The length of initial value has priority if the second argument's value is too small to represent it.</b><br/>
Bigdecimal offers <b>VpClone(a)</b> to clone(to create a new copy of a) the specified Bigdecimal variable.<br/>
Bigdecimal also offers <b>VpAllocCount()</b> which is the number of Bigdecimal variables not yet freed.<p/>
As the Bigdecimal variable is the container of digits,Bigdecimal offers two functions:
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td>m = VpMaxLength(c)</td><td>m is the maximum number of digits c can store.<br/>
m is slightly bigger than the value specified by VpAlloc() or VpMemAlloc() due to internal logic.</td></tr>
<tr><td>n = VpCurLength(c)</td><td>n is the number of digits currently stored in c.</td></tr>
</table>
VpMaxLength(c) and VpCurLength(c) return the sizes that may be slightly bigger than the actual values in it due to internal logic.<br/>
It is noted that <b>VpMaxLength(c) >=VpCurLength(c) > 0</b>.<p/>
<h3>Computation</h3>
Once allocated,Bigdecimal variables can be used in computation like the following program.
<pre><code>
int main(int argc, char* argv[])
{
VP_HANDLE a = VpAlloc("+1234567890.1234567890 123456789000000E0",100);
VP_HANDLE b = VpAlloc("20",10);
VP_HANDLE c = VpMemAlloc(150);
VpPrintE(stdout,VpMul(c,a,b)); /* c=a*b ===> 0.2469135780 2469135780 246913578E11 */
VpFree(&a);
VpFree(&b);
VpFree(&c);
return 0;
}
</code></pre>
Bigdecimal offers functions for arithmetic operations(most function returns resulting 'c' for convenience of the programming).<br/>
Only 3 functions(VpAlloc(),VpMemAlloc() and VpClone()) create new Bigdecimal variable(Other functions never do that).<br/>
It should strongly be noted that,many function(except 3 functions above) return Bigdecimal variables but they are never new ones. </b><br/>
For instance, <b>VpAdd(c,a,b)</b> computes a+b first,saves the result to c,and returns c itself.<br/>
It must be noted that <u>the total number of digits obtained by the computation depends on the capacity of the left hand side variable</u>.<br/>
Computation like c = a op b(op is any arithmetic operator such as +,-,*,/..),
the resulting digits are being saved to c while the computation is going on.<br/>
<b>Storing the resulting digits to c stops when the computation finishes or the capacity of c(=VpMaxLength(c)) is exhausted.</b><br/>
<table width="100%">
<col width="20%"><col width="40%"><col width="40%">
<tr><th>Bigdecimal functions</th><th>meaning</th><th>notes</th></tr>
<tr><td><b>c = VpAsgn(c,a,op)</b></td><td> c = a (op=1) or c = -a (op=-1)</td><td>the final digit of c is rounded if VpMaxLength(c)<VpCurLength(b)</td></tr>
<tr><td><b>c = VpAdd(c,a,b)</b></td><td> c = a+b</td></td><td>the final digit of c is rounded if VpMaxLength(c)<VpCurLength(a+b)</td></tr>
<tr><td><b>c = VpSub(c,a,b)</b></td><td> c = a-b</td></td><td>the final digit of c is rounded if VpMaxLength(c)<VpCurLength(a-b)</td></tr>
<tr><td><b>c = VpMul(c,a,b)</b></td><td> c = a*b</td></td><td><b>VpMaxLength(c)>VpCurLength(a)+VpCurLength(b)<sup>*</sup></b></td></tr>
<tr><td><b>c = VpDiv(c,r,a,b)</b></td><td> c = a/b (r is a remainder)</td><td><b>VpMaxLength(r)>Max(VpCurLength(a),VpMaxLength(c)+VpCurLength(b))<sup>*</sup></b></td></tr>
<tr><td><b>f = VpCmp(a,b)</b></td><td> 1(if a>b),0(if a==b),-1(if a<b),VP_ERROR_NON_NUMERIC(if uncomparable).</td><td>return value is an integer. </td></tr>
<tr><td><b>c = VpFrac(c,a)</b></td><td> copies all digits after the decimal point of a to c(|c|<1 or c=0)</td><td> </td></tr>
<tr><td><b>c = VpFix(c,a)<br />c = VpInt(c,a)</b></td><td> copies all digits before the decimal point of a to c(|c|>=1 or c=0)</td><td> </td></tr>
<tr><td><b>c = VpAbs(c)</b></td><td> c = |c|</td><td> </td></tr>
<tr><td><b>n = VpExponent(c)</b></td><td> returns n,where c=0.xxxxxxx10**n</td><td>n is an integer.</td></tr>
<tr><td><b>n = VpEffectiveDigits(c)</b></td><td>returns n,where n is the number of effective digits.
</td><td>n is an integer for which leading and trailing 0's are not counted. </td></tr>
<tr><td><b>c = VpRevertSign(c)<br />c = VpNegate(c)</b></td><td> c = -c</td><td> </td></tr>
<tr><td><b>f = VpGetSign(c)</b></td>
<td>returns one of the values defined in bigdecimal.h as listed bellow :
<table>
<tr><th>value returned (f)</th><th> c is a </th></tr>
<tr><td> VP_SIGN_NaN( 0) </td><td> NaN </td></tr>
<tr><td> VP_SIGN_POSITIVE_ZERO( 1) </td><td> positive zero </td></tr>
<tr><td> VP_SIGN_NEGATIVE_ZERO(-1) </td><td> negative zero </td></tr>
<tr><td> VP_SIGN_POSITIVE_FINITE( 2) </td><td> positive finite number</td></tr>
<tr><td> VP_SIGN_NEGATIVE_FINITE(-2) </td><td> negative finite number</td></tr>
<tr><td> VP_SIGN_POSITIVE_INFINITE( 3)</td><td> positive infinite number</td></tr>
<tr><td> VP_SIGN_NEGATIVE_INFINITE(-3)</td><td> negative infinite number</td></tr>
</table>
</td><td>return value is an integer.</td></tr>
<tr><td><b>c = VpSetSign(c,f)</b></td><td>sets c=|c|(if f>0),c=-|c|(if f<0)</td><td>f is an integer.</td></tr>
</table>
* <b><u>VpMul() or VpDiv() may return NaN</u>,if VpMaxLength(c) or VpMaxLength(r) does not satisfy above size limit.</b><br/>
* VpDiv() returns Infinity,if the denominator b is zero.<br/>
* VpDiv() returns NaN,if 0/0 is done.<p/>
Bigdecimal also offers some mathematical functions(most functions return resulting 'c').
<table width="100%">
<col width="20%"><col width="60%"><col width="20%">
<tr><th>Bigdecimal functions</th><th>meaning</th><th>notes</th></tr>
<tr><td><b>c = VpSqrt(c,a)</b></td><td> c = a<sup>1/2</sup></td><td>computed by Newton's method.</td></tr>
<tr><td><b>c = VpPI(c)</b></td><td> c = 3.141592....</td></td><td>computed by Matine's formula.</td></tr>
<tr><td><b>c = VpSin(c,a)</b></td><td> c = sin(a)</td></td><td> see Note<sup>*</sup> </td></tr>
<tr><td><b>c = VpCos(c,a)</b></td><td> c = cos(a)</td></td><td> see Note<sup>*</sup> </td></tr>
<tr><td><b>c = VpAtan(c,a)</b></td><td> c = tan<sup>-1</sup>(a)</td></td><td> |a|<=1, see Note<sup>*</sup> </td></tr>
<tr><td><b>c = VpExp(c,a)</b></td><td> c = e<sup>a</sup></td><td> see Note<sup>*</sup> </td></tr>
<tr><td><b>c = VpLog(c,a)</b></td><td> c = log<sub>e</sub>a</td><td> 0<a<= 2, see Note<sup>*</sup> </td></tr>
<tr><td><b>c = VpPower(c,a,n)</b></td><td> c = a<sup>n</sup></td><td> n must be an ingteger.</td></tr>
</table>
* In most functions,VpMaxLength(c) digits are stored to resulting c.<p/>
Note<sup>*</sup>: <ul>
<li>sin,cos,atan,exp and log are computed by series expansion,and have some experimental aspect.</li>
<li>The argument for each function(a) must have small value to obtain convergence.</li>
<li>The numerical operation such as: If a>3.141592....,then a = a-3.141592....,is not done internally,so this should be done before calling.<br/>
This is also applies to log(ab)=log(a)+log(b),where a and b must be in range 0<(a,b)<=2.
</li>
</ul>
<u><b>Example:</b></u>
<pre><code>
#define F(H,V) printf(H);VpPrintF(stdout,V);printf("\n");
#define E(H,V) printf(H);VpPrintE(stdout,V);printf("\n");
VP_HANDLE sqrt2 = VpMemAlloc(100);
VP_HANDLE pi = VpMemAlloc(100);
VP_HANDLE pi2 = VpMemAlloc(100);
VP_HANDLE one = VpMemAlloc(100);
VP_HANDLE two = VpAlloc("2",1);
VP_HANDLE r;
VP_UINT m;
F("Sqrt(2) =",VpSqrt(sqrt2,two)); /* sqrt2 = sqrt(2) */
VpFree(&two);two = VpAlloc("0",VpCurLength(sqrt2)*2+1);
F("Sqrt(2)**2=",VpMul(two,sqrt2,sqrt2)); /* two = sqrt(2)**2 ==> 2.0 */
F("pi =",VpPI(pi)); /* pi = 3.141592... */
m = VpCurLength(pi)+VpCurLength(two)+1;
if(m<VpMaxLength(pi2)) m = VpMaxLength(pi2)+1;
r = VpAlloc("0",m);
F("pi2 =",VpDiv(pi2,r,pi,two)); /* pi2 = pi/2 */
E("sin(pi2) =",VpSin(one,pi2)); /* one = sin(pi/2) ==> 1.0 */
VpFree(&r);
.........
</code></pre>
<u><b>Results:</b></u><p/>
<pre class=console>
Sqrt(2) = 1.4142135623 7309504880 1688724209 6980785696 7187537694 8073176679 7379907324 7846210703 8850387534 3276415727
Sqrt(2)**2= 1.9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 0096588757 8795506493 0439931247 0016809150 7199370597 5256343471 3223747479 7111963099 3958184437 6132938529
pi = 3.1415926535 8979323846 2643383279 5028841971 6939937510 5820974944 5923078164 0628620899 8628034825 3421170676
pi2 = 1.5707963267 9489661923 1321691639 7514420985 8469968755 2910487472 2961539082 0314310449 9314017412 671058
sin(pi2) = 0.9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 9999999999 9999999991 0017E0
</pre>
As series expansion is adopted for math functions,maximum iteration count can be set by the user.
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td>m = VpGetMaxIterationCount()</td><td>returns maximum iteration count(default=10000) </td></tr>
<tr><td>m = VpSetMaxIterationCount(m)</td><td>sets maximum iteration count to m. </td></tr>
<tr><td>n = VpGetIterationCount()</td><td>returns iteration count spent by the most recent computation.</td></tr>
</table>
<a name="PRINT"/>
<h2>Display/Print</h2>
The computation results must be converted into human readable form.<br/>
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td>n = VpPrintE(fp,c)</td><td> print c to fp in E-format.</td></tr>
<tr><td>n = VpPrintF(fp,c)</td><td> print c to fp in F-format.</td></tr>
</table>
where fp is a stream to which the output is sent,and n is a number of characters printed.<p/>
Bigdecimal value is printed like:<blockquote>
E-format ==> 0.xxxxxxxxxx....Eeee<br/>
F-format ==> xxxxxxxx.yyyyyyyyyyy<br/>
</blockquote>
where x,y and e are digits('0'-'9').<p/>
Bigdecimal value can be converted to string(character array).<br>
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td>char *szE = VpToStringE(c,szE)</td><td>szE <== E-format of c.</td></tr>
<tr><td>char *szF = VpToStringF(c,szF)</td><td>szF <== F-format of c.</td></tr>
</table>
The array size of szE and szF must be equal to or greater than the value returned by<br/>
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td>m = VpStringLengthE(c)</td><td>m is a maximum character array size to represent c in E-format.</td></tr>
<tr><td>m = VpStringLengthF(c)</td><td>m is a maximum character array size to represent c in F-format.</td></tr>
</table>
respectively.<p/>
<b><u>DigitSeparationCount</u></b><br/>
Because the output string length of the Bigdecimal can be very long,you can insert a character(DigitSeparator) in every DigitSeparationCount in output string for readablity.<br/>
This can be zero which means the string is not separated.
<pre><b>
VP_UINT VpGetDigitSeparationCount(); /* default = 10 */
VP_UINT VpSetDigitSeparationCount(VP_UINT m);
</b></pre>
<p/>
<b><u>DigitSeparator</u></b><br/>
The character to insert to output string.<br/>
This can not be '+','-', or any digit character.<br/>
This character can also be inserted to input string at any place except for exponent part for VpAlloc(),
<pre><b>
char VpGetDigitSeparator(); /* default = ' ' */
char VpSetDigitSeparator(char c);
</b></pre>
<b><u>DigitLeader</u></b><br/>
This can be one of '\0','+' or ' '.<br/>
This character applies for positive number.<br/>
<ul>
<li> '+' ... '+' is always put on positive number.</li>
<li> ' ' ... ' ' is always put on positive number.</li>
<li> '\0' ... Nothing is put on positive number.</li>
</ul>
<pre><b>
char VpGetDigitLeader(); /* default = ' ' */
char VpSetDigitLeader(char c);
</b></pre>
<p/>
The results of these options can be easily confirmed by using <a href="#VPC"/>VPC</a>.
<pre class="console">
VPC(Variable Precision Calculator) of Bigdecimal(V1)
Copyright (c) 2018 by Shigeo Kobayashi. Allrights reserved.
Enter command
? PI a
a= 0.3141592653 5897932384 6264338327 9502884197 1693993751 0582097494 4592307816 4062862089 9862803482 5342117063 2E1
? dc?
10
? dc= 5
5
? a
a= 0.31415 92653 58979 32384 62643 38327 95028 84197 16939 93751 05820 97494 45923 07816 40628 62089 98628 03482 53421 17063 2E1
? ds?
' '
? ds= ,
','
? a
a= 0.31415,92653,58979,32384,62643,38327,95028,84197,16939,93751,05820,97494,45923,07816,40628,62089,98628,03482,53421,17063,2E1
? dl?
' '
? dl= +
'+'
? a
a=+0.31415,92653,58979,32384,62643,38327,95028,84197,16939,93751,05820,97494,45923,07816,40628,62089,98628,03482,53421,17063,2E1
?
</pre>
<a name="ROUND"/>
<h2>Rounding operation</h2>
Suppose C and A are Bigdecimal variables. The value assignment from A to C(C=A) is done by <b>VpAsgn(C,A,1)</b>.<br>If VpMaxLength(C) < VpCurLength(A),then all digits of A can not be copied to C and the default rounding operation will be done. <br/>
The default round operation is done in other cases such as addition or subtraction(internal rounding).<br/>
To set or get the default rounding operation use:<p/>
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td>f = VpGetRoundMode()</td><td> f is a rounding mode listed bellow.</td></tr>
<tr><td>f = VpSetRoundMode(f)</td><td> f is a rounding mode listed bellow.</td></tr>
</table>
where f is the one of default rouding modes listed bellow.
<table width="100%">
<col width="25%"><col width="60%"><col width="15%">
<TBODY>
<tr><th>Round mode</th><th>Meaning</th><th>Value</th></tr>
<TR><TD>VP_ROUND_UP</TD><TD>round away from zero.</TD><td>1</td></TR>
<TR><TD>VP_ROUND_DOWN</TD><TD>round towards zero(truncate).</TD><td>2</td></TR>
<TR><TD>VP_ROUND_HALF_UP</TD><TD>round up if the digit >= 5 otherwise truncated(default).</TD><td>3</td></TR>
<TR><TD>VP_ROUND_HALF_DOWN</TD><TD>round up if the digit >= 6 otherwise truncated.</TD><td>4</td></TR>
<TR><TD>VP_ROUND_CEILING</TD><TD>round towards positive infinity(ceil).</TD><td>5</td></TR>
<TR><TD>VP_ROUND_FLOOR</TD><TD>round towards negative infinity(floor).</TD><td>6</td></TR>
<TR><TD>VP_ROUND_HALF_EVEN</TD><TD>round towards the even neighbor(Banker's rounding). </td><td>7</td></tr>
</TBODY>
</table>
The position of round operation can explicitly specified by following 2 functions.<br/>
Both function return resulting c.
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td>c = VpScaleRound(c,i)</td><td>
i is the position of round operation mesured from decimal point.<br/>
If <b>i>=0</b>,then the (i+1)th digit counted from the decimal point to right direction is processed(resulting number of digits after decimal point is less than or equal to i).<br/>
If <b>i<0</b>,then the i-th digit counted from the decimal point to left direction is processed(at least i 0s are placed from the decimal point to left).
</td></tr>
<tr><td> c = VpLengthRound(c,i)</td><td>
Round operation is done at the i-th position counted from the left side of the number.
</td></tr>
</table>
<u><b>Example:</b></u>
<pre><code>
VP_HANDLE c = VpAlloc("5555555555.5555555555",1);
VP_HANDLE a = VpMemAlloc(VpMaxLength(c));
VpAsgn(a,c,1); F("ScaleRound ( 0)= ",VpScaleRound (c, 0));
VpAsgn(c,a,1); F("ScaleRound ( 2)= ",VpScaleRound (c, 2));
VpAsgn(c,a,1); F("ScaleRound (-2)= ",VpScaleRound (c,-2));
VpAsgn(c,a,1); F("LengthRound(12)= ",VpLengthRound(c,12));
VpAsgn(c,a,1); F("LengthRound( 8)= ",VpLengthRound(c, 8));
</code></pre>
<u><b>Results:</b></u><p/>
<pre class=console>
ScaleRound ( 0)= 5555555556
ScaleRound ( 2)= 5555555555.56
ScaleRound (-2)= 5555555600
LengthRound(12)= 5555555555.56
LengthRound( 8)= 5555555600
</pre>
In above examples,the rounding operation is done by default rounding mode(VP_ROUND_HALF_UP).<br/>
You can explicitly specify rounding mode(mode) by following functions.
<pre><b>
VP_EXPORT(VP_HANDLE) VpAsgn2(VP_HANDLE c, VP_HANDLE a, int isw,int mode)
VP_EXPORT(VP_HANDLE) VpScaleRound2(VP_HANDLE a, int ixRound,int mode)
VP_EXPORT(VP_HANDLE) VpLengthRound2(VP_HANDLE a, int ixRound,int mode)
</b></pre>
<H2>Infinity,NaN(Not a Number),Zero</H2>
Bigdecimal supports Infinity,Zero,and NaN as defined in IEEE 754.<br/>
Infinity,Zero,and NaN are specially handled in Bigdecimal.<p/>
<b><u>Creation</u></b>
<ul>
<li><b>Infinity</b><br/>
Allocation:VpAlloc("Infinity",1),VpAlloc("+Infinity",1),VpAlloc("-Infinity",1)<br/>
Computation: 1/0,-1/0 ...
</li>
<li><b>NaN</b><br/>
Allocation:VpAlloc("NaN",1)<br/>
Computation: 0/0,Infinity/Infinity,NaN*1,NaN+1 ...
</li>
<li><b>Zero</b><br/>
Allocation:VpAlloc("0",1),VpAlloc("+0",1),VpAlloc("-0",1)<br/>
Computation: 1*0,-1*0 ...
</li>
</ul>
NaN(Not a number) can be obtained by undefined computation like 0.0/0.0 or Infinity-Infinity.<br/>
Any computation including NaN results to NaN.<br/>
<u>Comparisons with NaN never become true,including comparison with NaN itself</u>. <p/>
Zero has two different variations as +0.0 and -0.0. But,still, +0.0==-0.0 is true.
<H2>Error handling</H2>
VpAlloc() may return non VP_HANDLE value(error code) if the first argument contains bad character or memory allocation fails.<br/>
VpMemAlloc() may also return non VP_HANDLE value if it fails to allocate memories.<br/>
Because VpAlloc() or VpMemAlloc() may return an error code,it is very important to examine the returned value or the program may crash.<p/>
To check if the returned value is valid VP_HANDLE,use VpValid() or VpInvalid() as:
<pre><code>
VP_HANDLE h = VpAlloc("12345+123",2); /* ==> ERROR: + is placed at illegal position. */
if(VpInvalid(h)) {
printf("ERROR returned by VpAlloc()\n");
exit(0);
}
......
</code></pre>
Checking on the return value is always valid.<br/>
To check the VP_HANDLE, use following macros.
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>macros</th><th>meaning</th></tr>
<tr><td>VpIsInvalid(c)</td><td> 1 if c is invalid,0 if c is valid VP_HANDLE.</td></tr>
<tr><td>VpIsValid(h)</td><td> 0 if h is invalid,1 if h is valid VP_HANDLE.</td></tr>
<tr><td>VpIsNumeric(h)</td><td> 1 if h is valid and is not NaN nor Infinity,0 of h is invalid,h is NaN or Infinity.</td></tr>
</table>
<u>To set exception handler is also quite usefull(strongly recommended)</u>.
<H2>Exception handler</H2>
If memory allocation fails or any other error occures,Bigdecimal always calls exception handler if it is set by the user through <b>VpSetExceptionHandler()</b>.<br/>
Refer to the following example.
<pre><code>
<b>void MyException(VP_HANDLE h,const char *msg)</b>
{
printf("MyException(%s)\n",msg);
}
void main(int argc, char* argv[])
{
<b>VpSetExceptionHandler(MyException)</b>;
E("Err =",VpAlloc("-0..123",1)); /* ERROR => this causes MyException() is called within VpAlloc() */
}
</code></pre>
<b><u>Results:</u></b>
<pre class=console>
MyException(Bad numeric string for VpAlloc())
VpPrintF():Invalid handle(1)
</pre>
<H2>miscellaneous</H2>
On the following table,VpIsxxxx(c) returns 1 if the VP_HANDLE c is xxxx otherwise returns 0
where xxxx is One(1),Positive Zero(+0),Negative Zero(-0),Zero(0),NaN,Positive infinity(+Infinity),
Negative infinity(-Infinity) or Infinity respectively.<br/>
And VpSetxxxx(c,[f]) set c to xxxx as same as above where f is a sign to set if there.
<table width="100%">
<col width="30%"><col width="70%">
<tr><th>Bigdecimal functions</th><th>meaning</th></tr>
<tr><td>f = VpIsOne(c)<br/>c = VpSetOne(c)</td><td> 1 if c==1<br/>c=1 </td></tr>
<tr><td>f = VpIsPosZero(c)<br/>c = VpSetPosZero(c)</td><td>1 if c==+0<br/> c=+0 </td></tr>
<tr><td>f = VpIsNegZero(c)<br/>c = VpSetNegZero(c)</td><td>1 if c==-0<br/> c=-0 </td></tr>
<tr><td>f = VpIsZero(c)<br/>c = VpSetZero(c,f)</td><td> 1 if c==0<br/>c=0 (+0 if f>0, -0 if f<0)) </td></tr>
<tr><td>f = VpIsNaN(c)<br/>c = VpSetNaN(c)</td><td> 1 if c== NaN<br/>c=NaN </td></tr>
<tr><td>f = VpIsPosInf(c)<br/>c = VpSetPosInf(c)</td><td>1 if c==+Infinity <br/>c=+Infinity </td></tr>
<tr><td>f = VpIsNegInf(c)<br/>c = VpSetNegInf(c)</td><td>1 if c==-Infinity <br/>c=-Infinity </td></tr>
<tr><td>f = VpIsInf(c)<br/>c = VpSetInf(c,f)</td><td>1 if c==Infinity<br/>c=Infinity (+Infinity if f>0,-Infinity if f<0) </td></tr>
</table>
<H2>Bigdecimal structure</H2>
Bigdecimal variable structure defined in bigdecimal.h.
<pre><code>
/*
* VP representation
* r = 0.xxxxxxxxx *BASE**exponent
*/
typedef struct {
VP_UINT Size; /* all byte size of this structure(used in realloc() case). */
VP_UINT MaxPrec; /* Maximum precision size */
/* This is the actual size of frac[] */
/*(frac[0] to frac[MaxPrec-1] are available). */
VP_UINT Prec; /* Current precision size. */
/* This indicates how much the. */
/* the array frac[] is actually used. */
VP_UINT Tag; /* Space for the user(Bigdecimal never touch this) */
/* Use VpSetTag() or VpGetTab() to access. */
int exponent;/* Exponent part. */
int sign; /* Attributes of the value. */
/* See VP_SIGN_xxxxxxx defined.
* ==0 : NaN
* 1 : Positive zero
* -1 : Negative zero
* 2 : Positive number
* -2 : Negative number
* 3 : Positive infinite number
* -3 : Negative infinite number
*/
VP_DIGIT frac[1]; /* Array of fraction part. */
} Real;
#define VP_SIGN_NaN 0 /* NaN */
#define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */
#define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */
#define VP_SIGN_POSITIVE_FINITE 2 /* Positive finite number */
#define VP_SIGN_NEGATIVE_FINITE -2 /* Negative finite number */
#define VP_SIGN_POSITIVE_INFINITE 3 /* Positive infinite number */
#define VP_SIGN_NEGATIVE_INFINITE -3 /* Negative infinite number */
</code></pre>
VP_DIGIT can be 32-bit or 64-bit unsigned integer(see bigdecimal.h).<br/>
On 64-bit machine with 64-bit OS,better performance can be obtained by setting VP_DIGIT as 'unsigned long long'(64-bit).<br/>
On 32-bit OS,VP_DIGIT can also be set to be 64-bit(unsigned long long) which may cause bad performance due to 64-bit emulation.
<div align="right">
Shigeo Kobayashi 2024-3-21
</div>
<hr/>
</body>
</html>