~ubuntu-branches/ubuntu/hoary/gnucash/hoary

« back to all changes in this revision

Viewing changes to src/engine/gnc-numeric.c

  • Committer: Bazaar Package Importer
  • Author(s): James A. Treacy
  • Date: 2002-03-16 14:14:59 UTC
  • Revision ID: james.westby@ubuntu.com-20020316141459-wtkyyrpfovryhl1s
Tags: upstream-1.6.6
ImportĀ upstreamĀ versionĀ 1.6.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/********************************************************************
 
2
 * gnc-numeric.c -- an exact-number library for gnucash.            *
 
3
 * Copyright (C) 2000 Bill Gribble                                  *
 
4
 *                                                                  *
 
5
 * This program is free software; you can redistribute it and/or    *
 
6
 * modify it under the terms of the GNU General Public License as   *
 
7
 * published by the Free Software Foundation; either version 2 of   *
 
8
 * the License, or (at your option) any later version.              *
 
9
 *                                                                  *
 
10
 * This program is distributed in the hope that it will be useful,  *
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
 
13
 * GNU General Public License for more details.                     *
 
14
 *                                                                  *
 
15
 * You should have received a copy of the GNU General Public License*
 
16
 * along with this program; if not, contact:                        *
 
17
 *                                                                  *
 
18
 * Free Software Foundation           Voice:  +1-617-542-5942       *
 
19
 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
 
20
 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
 
21
 *                                                                  *
 
22
 *******************************************************************/
 
23
 
 
24
#define _GNU_SOURCE
 
25
 
 
26
#include <glib.h>
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <math.h>
 
30
#include <assert.h>
 
31
 
 
32
#include "gnc-engine-util.h"
 
33
#include "gnc-numeric.h"
 
34
 
 
35
/* TODO 
 
36
 * - use longer intermediate values to make operations
 
37
 *   64-bit-overflow-proof 
 
38
 */
 
39
 
 
40
/* static short module = MOD_ENGINE; */
 
41
 
 
42
static const char * _numeric_error_strings[] = 
 
43
{
 
44
  "No error",
 
45
  "Argument is not a valid number",
 
46
  "Intermediate result overflow",
 
47
  "Argument denominators differ in GNC_DENOM_FIXED operation",
 
48
  "Remainder part in GNC_RND_NEVER operation"
 
49
};
 
50
 
 
51
static gint64 gnc_numeric_lcd(gnc_numeric a, gnc_numeric b);
 
52
 
 
53
/********************************************************************
 
54
 *  gnc_numeric_zero_p
 
55
 ********************************************************************/
 
56
 
 
57
int
 
58
gnc_numeric_zero_p(gnc_numeric a) {
 
59
  if(gnc_numeric_check(a)) {
 
60
    return 0;
 
61
  }
 
62
  else {
 
63
    if((a.num == 0) && (a.denom != 0)) {
 
64
      return 1;
 
65
    }
 
66
    else {
 
67
      return 0;
 
68
    }
 
69
  }
 
70
}
 
71
 
 
72
/********************************************************************
 
73
 *  gnc_numeric_negative_p
 
74
 ********************************************************************/
 
75
 
 
76
int
 
77
gnc_numeric_negative_p(gnc_numeric a) {
 
78
  if(gnc_numeric_check(a)) {
 
79
    return 0;
 
80
  }
 
81
  else {
 
82
    if((a.num < 0) && (a.denom != 0)) {
 
83
      return 1;
 
84
    }
 
85
    else {
 
86
      return 0;
 
87
    }
 
88
  }
 
89
}
 
90
 
 
91
/********************************************************************
 
92
 *  gnc_numeric_positive_p
 
93
 ********************************************************************/
 
94
 
 
95
int
 
96
gnc_numeric_positive_p(gnc_numeric a) {
 
97
  if(gnc_numeric_check(a)) {
 
98
    return 0;
 
99
  }
 
100
  else {
 
101
    if((a.num > 0) && (a.denom != 0)) {
 
102
      return 1;
 
103
    }
 
104
    else {
 
105
      return 0;
 
106
    }
 
107
  }
 
108
}
 
109
 
 
110
 
 
111
/********************************************************************
 
112
 *  gnc_numeric_compare
 
113
 *  returns 1 if a>b, -1 if b>a, 0 if a == b 
 
114
 ********************************************************************/
 
115
 
 
116
int
 
117
gnc_numeric_compare(gnc_numeric a, gnc_numeric b) {
 
118
  gint64 ab, ba;
 
119
 
 
120
  if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
 
121
    return 0;
 
122
  }
 
123
  ab = a.num * b.denom;
 
124
  ba = b.num * a.denom;
 
125
 
 
126
  if(ab == ba) {
 
127
    return 0;
 
128
  }
 
129
  else if(ab > ba) {
 
130
    return 1;
 
131
  }
 
132
  else {
 
133
    return -1;
 
134
  }
 
135
}
 
136
 
 
137
 
 
138
/********************************************************************
 
139
 *  gnc_numeric_eq
 
140
 ********************************************************************/
 
141
 
 
142
int
 
143
gnc_numeric_eq(gnc_numeric a, gnc_numeric b) {
 
144
  return ((a.num == b.num) && (a.denom == b.denom));
 
145
}
 
146
 
 
147
 
 
148
/********************************************************************
 
149
 *  gnc_numeric_equal
 
150
 ********************************************************************/
 
151
 
 
152
int
 
153
gnc_numeric_equal(gnc_numeric a, gnc_numeric b) {
 
154
  if(((a.denom > 0) && (b.denom > 0)) ||
 
155
     ((a.denom < 0) && (b.denom < 0))) {    
 
156
    return ((a.num * b.denom) == (a.denom * b.num));
 
157
  }
 
158
  else {
 
159
    return 0;
 
160
  }
 
161
}
 
162
 
 
163
 
 
164
/********************************************************************
 
165
 *  gnc_numeric_same
 
166
 *  would a and b be equal() if they were both converted to the same 
 
167
 *  denominator? 
 
168
 ********************************************************************/
 
169
 
 
170
int
 
171
gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, 
 
172
                 gint how) {
 
173
  gnc_numeric aconv, bconv;
 
174
  
 
175
  aconv = gnc_numeric_convert(a, denom, how);
 
176
  bconv = gnc_numeric_convert(b, denom, how);
 
177
  
 
178
  return(gnc_numeric_equal(aconv, bconv));
 
179
}
 
180
 
 
181
 
 
182
 
 
183
/********************************************************************
 
184
 *  gnc_numeric_add
 
185
 ********************************************************************/
 
186
 
 
187
gnc_numeric
 
188
gnc_numeric_add(gnc_numeric a, gnc_numeric b, 
 
189
                gint64 denom, gint how) {
 
190
  gnc_numeric sum;
 
191
  
 
192
  if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
 
193
    return gnc_numeric_error(GNC_ERROR_ARG);
 
194
  }
 
195
 
 
196
  if((denom == GNC_DENOM_AUTO) && 
 
197
     (how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
 
198
    if(a.denom == b.denom) {
 
199
      denom = a.denom;
 
200
    }
 
201
    else if(b.num == 0) {
 
202
      denom = a.denom;
 
203
    }
 
204
    else if(a.num == 0) {
 
205
      denom = b.denom;
 
206
    }
 
207
    else {
 
208
      return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
 
209
    }
 
210
  }
 
211
  
 
212
  if(a.denom < 0) {
 
213
    a.num *= a.denom;
 
214
    a.denom = 1;
 
215
  }
 
216
 
 
217
  if(b.denom < 0) {
 
218
    b.num *= b.denom;
 
219
    b.denom = 1;
 
220
  }
 
221
 
 
222
  /* get an exact answer.. same denominator is the common case. */ 
 
223
  if(a.denom == b.denom) {
 
224
    sum.num = a.num + b.num;
 
225
    sum.denom = a.denom;
 
226
  }
 
227
  else {
 
228
    sum.num   = a.num*b.denom + b.num*a.denom;
 
229
    sum.denom = a.denom*b.denom;
 
230
  }
 
231
  
 
232
  if((denom == GNC_DENOM_AUTO) &&
 
233
     ((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD)) {
 
234
    denom = gnc_numeric_lcd(a, b);
 
235
    how   = how & GNC_NUMERIC_RND_MASK;
 
236
  }
 
237
  
 
238
  return gnc_numeric_convert(sum, denom, how);                             
 
239
}
 
240
 
 
241
 
 
242
/********************************************************************
 
243
 *  gnc_numeric_add_fixed
 
244
 ********************************************************************/
 
245
 
 
246
gnc_numeric
 
247
gnc_numeric_add_fixed(gnc_numeric a, gnc_numeric b) {
 
248
  return gnc_numeric_add(a, b, GNC_DENOM_AUTO, 
 
249
                         GNC_DENOM_FIXED | GNC_RND_NEVER);
 
250
}
 
251
 
 
252
 
 
253
/********************************************************************
 
254
 *  gnc_numeric_sub
 
255
 ********************************************************************/
 
256
 
 
257
gnc_numeric
 
258
gnc_numeric_sub(gnc_numeric a, gnc_numeric b, 
 
259
                gint64 denom, gint how) {
 
260
  gnc_numeric diff;
 
261
 
 
262
  if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
 
263
    return gnc_numeric_error(GNC_ERROR_ARG);
 
264
  }
 
265
 
 
266
  if((denom == GNC_DENOM_AUTO) && 
 
267
     (how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
 
268
    if(a.denom == b.denom) {
 
269
      denom = a.denom;
 
270
    }
 
271
    else if(b.num == 0) {
 
272
      denom = a.denom;
 
273
    }
 
274
    else if(a.num == 0) {
 
275
      denom = b.denom;
 
276
    }
 
277
    else {
 
278
      return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
 
279
    }
 
280
  }
 
281
 
 
282
  if(a.denom < 0) {
 
283
    a.num *= a.denom;
 
284
    a.denom = 1;
 
285
  }
 
286
 
 
287
  if(b.denom < 0) {
 
288
    b.num *= b.denom;
 
289
    b.denom = 1;
 
290
  }
 
291
 
 
292
  /* get an exact answer.. same denominator is the common case. */ 
 
293
  if(a.denom == b.denom) {
 
294
    diff.num = a.num - b.num;
 
295
    diff.denom = a.denom;
 
296
  }
 
297
  else {
 
298
    diff.num   = a.num*b.denom - b.num*a.denom;
 
299
    diff.denom = a.denom*b.denom;
 
300
  }
 
301
  
 
302
  if((denom == GNC_DENOM_AUTO) &&
 
303
     ((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD)) {
 
304
    denom = gnc_numeric_lcd(a, b);
 
305
    how   = how & GNC_NUMERIC_RND_MASK;
 
306
  }
 
307
  return gnc_numeric_convert(diff, denom, how);                             
 
308
}
 
309
 
 
310
 
 
311
/********************************************************************
 
312
 *  gnc_numeric_sub_fixed
 
313
 ********************************************************************/
 
314
 
 
315
gnc_numeric
 
316
gnc_numeric_sub_fixed(gnc_numeric a, gnc_numeric b) {
 
317
  return gnc_numeric_sub(a, b, GNC_DENOM_AUTO, 
 
318
                         GNC_DENOM_FIXED | GNC_RND_NEVER);
 
319
}
 
320
 
 
321
 
 
322
/********************************************************************
 
323
 *  gnc_numeric_mul
 
324
 ********************************************************************/
 
325
 
 
326
gnc_numeric
 
327
gnc_numeric_mul(gnc_numeric a, gnc_numeric b, 
 
328
                gint64 denom, gint how) {
 
329
  gnc_numeric product;
 
330
  
 
331
  if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
 
332
    return gnc_numeric_error(GNC_ERROR_ARG);
 
333
  }
 
334
 
 
335
  if((denom == GNC_DENOM_AUTO) && 
 
336
     (how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
 
337
    if(a.denom == b.denom) {
 
338
      denom = a.denom;
 
339
    }
 
340
    else if(b.num == 0) {
 
341
      denom = a.denom;
 
342
    }
 
343
    else if(a.num == 0) {
 
344
      denom = b.denom;
 
345
    }
 
346
    else {
 
347
      return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
 
348
    }
 
349
  }
 
350
 
 
351
  if(a.denom < 0) {
 
352
    a.num *= a.denom;
 
353
    a.denom = 1;
 
354
  }
 
355
 
 
356
  if(b.denom < 0) {
 
357
    b.num *= b.denom;
 
358
    b.denom = 1;
 
359
  }
 
360
 
 
361
  product.num   = a.num*b.num;
 
362
  product.denom = a.denom*b.denom;
 
363
  
 
364
  if(product.denom < 0) {
 
365
    product.num   = -product.num;
 
366
    product.denom = -product.denom;
 
367
  }
 
368
  
 
369
  if((denom == GNC_DENOM_AUTO) &&
 
370
     ((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD)) {
 
371
    denom = gnc_numeric_lcd(a, b);
 
372
    how   = how & GNC_NUMERIC_RND_MASK;
 
373
  }
 
374
 
 
375
  return gnc_numeric_convert(product, denom, how);                             
 
376
}
 
377
 
 
378
 
 
379
/********************************************************************
 
380
 *  gnc_numeric_div
 
381
 ********************************************************************/
 
382
 
 
383
gnc_numeric
 
384
gnc_numeric_div(gnc_numeric a, gnc_numeric b, 
 
385
                gint64 denom, gint how) {
 
386
  gnc_numeric quotient;
 
387
 
 
388
  if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
 
389
    return gnc_numeric_error(GNC_ERROR_ARG);
 
390
  }
 
391
 
 
392
  if((denom == GNC_DENOM_AUTO) && 
 
393
     (how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_FIXED) {
 
394
    if(a.denom == b.denom) {
 
395
      denom = a.denom;
 
396
    }
 
397
    else if(a.denom == 0) {
 
398
      denom = b.denom;
 
399
    }
 
400
    else {
 
401
      return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
 
402
    }
 
403
  }
 
404
  
 
405
 
 
406
  if(a.denom < 0) {
 
407
    a.num *= a.denom;
 
408
    a.denom = 1;
 
409
  }
 
410
 
 
411
  if(b.denom < 0) {
 
412
    b.num *= b.denom;
 
413
    b.denom = 1;
 
414
  }
 
415
 
 
416
  if(a.denom == b.denom) {
 
417
    quotient.num = a.num;
 
418
    quotient.denom = b.num;
 
419
  }
 
420
  else {
 
421
    quotient.num   = a.num*b.denom;
 
422
    quotient.denom = a.denom*b.num;
 
423
  }
 
424
  
 
425
  if(quotient.denom < 0) {
 
426
    quotient.num   = -quotient.num;
 
427
    quotient.denom = -quotient.denom;
 
428
  }
 
429
  
 
430
  if((denom == GNC_DENOM_AUTO) &&
 
431
     ((how & GNC_NUMERIC_DENOM_MASK) == GNC_DENOM_LCD)) {
 
432
    denom = gnc_numeric_lcd(a, b);
 
433
    how   = how & GNC_NUMERIC_RND_MASK;
 
434
  }
 
435
 
 
436
  return gnc_numeric_convert(quotient, denom, how); 
 
437
}
 
438
 
 
439
/********************************************************************
 
440
 *  gnc_numeric_neg
 
441
 *  negate the argument 
 
442
 ********************************************************************/
 
443
 
 
444
gnc_numeric
 
445
gnc_numeric_neg(gnc_numeric a) {
 
446
  if(gnc_numeric_check(a)) {
 
447
    return gnc_numeric_error(GNC_ERROR_ARG);
 
448
  }
 
449
  return gnc_numeric_create(- a.num, a.denom);
 
450
}
 
451
 
 
452
/********************************************************************
 
453
 *  gnc_numeric_neg
 
454
 *  return the absolute value of the argument 
 
455
 ********************************************************************/
 
456
 
 
457
gnc_numeric
 
458
gnc_numeric_abs(gnc_numeric a) {
 
459
  if(gnc_numeric_check(a)) {
 
460
    return gnc_numeric_error(GNC_ERROR_ARG);
 
461
  }
 
462
  return gnc_numeric_create(ABS(a.num), a.denom);
 
463
}
 
464
 
 
465
/********************************************************************
 
466
 *  gnc_numeric_convert
 
467
 ********************************************************************/
 
468
 
 
469
gnc_numeric
 
470
gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how) {
 
471
  gnc_numeric out;
 
472
  gnc_numeric temp;
 
473
  gint64      temp_bc;
 
474
  gint64      temp_a;
 
475
  gint64      remainder;  
 
476
  gint64      sign;
 
477
  gint        denom_neg=0;
 
478
  double      ratio, logratio;
 
479
  double      sigfigs;
 
480
 
 
481
  if(gnc_numeric_check(in)) {
 
482
    return gnc_numeric_error(GNC_ERROR_ARG);
 
483
  }
 
484
  
 
485
  if(denom == GNC_DENOM_AUTO) {
 
486
    switch(how & GNC_NUMERIC_DENOM_MASK) {
 
487
    case GNC_DENOM_EXACT:
 
488
      return in;
 
489
      break;
 
490
      
 
491
    case GNC_DENOM_REDUCE:
 
492
      /* reduce the input to a relatively-prime fraction */
 
493
      return gnc_numeric_reduce(in);
 
494
      break;
 
495
      
 
496
    case GNC_DENOM_FIXED:
 
497
      if(in.denom != denom) {
 
498
        return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
 
499
      }
 
500
      else {
 
501
        return in;
 
502
      }
 
503
      break;
 
504
      
 
505
    case GNC_DENOM_SIGFIG:
 
506
      ratio    = fabs(gnc_numeric_to_double(in));
 
507
      if(ratio < 10e-20) {
 
508
        logratio = 0;
 
509
      }
 
510
      else {
 
511
        logratio = log10(ratio);
 
512
        logratio = ((logratio > 0.0) ? 
 
513
                    (floor(logratio)+1.0) : (ceil(logratio)));
 
514
      }
 
515
      sigfigs  = GNC_NUMERIC_GET_SIGFIGS(how);
 
516
 
 
517
      if(sigfigs-logratio >= 0) {
 
518
        denom    = (gint64)(pow(10, sigfigs-logratio));
 
519
      }
 
520
      else {
 
521
        denom    = -((gint64)(pow(10, logratio-sigfigs)));
 
522
      }
 
523
      
 
524
      how = how & ~GNC_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
 
525
      break;
 
526
 
 
527
    case GNC_DENOM_LCD:
 
528
      /* this is a no-op. */
 
529
    default:
 
530
      break;
 
531
    }
 
532
  }
 
533
  
 
534
  /* make sure we need to do the work */
 
535
  if(in.denom == denom) {
 
536
    return in;
 
537
  }
 
538
  
 
539
  /* if the denominator of the input value is negative, get rid of that. */
 
540
  if(in.denom < 0) {
 
541
    in.num = in.num * (- in.denom);
 
542
    in.denom = 1;
 
543
  }
 
544
  
 
545
  sign = (in.num < 0) ? -1 : 1;
 
546
 
 
547
  /* if the denominator is less than zero, we are to interpret it as 
 
548
   * the reciprocal of its magnitude. */
 
549
  if(denom < 0) {
 
550
    denom     = - denom;
 
551
    denom_neg = 1;
 
552
    temp_a    = (in.num < 0) ? -in.num : in.num;
 
553
    temp_bc   = in.denom * denom;
 
554
    remainder = in.num % temp_bc;
 
555
    out.num   = in.num / temp_bc;
 
556
    out.denom = - denom;    
 
557
  }
 
558
  else {
 
559
    /* do all the modulo and int division on positive values to make
 
560
     * things a little clearer. Reduce the fraction denom/in.denom to
 
561
     * help with range errors (FIXME : need bigger intermediate rep) */
 
562
    temp.num   = denom;
 
563
    temp.denom = in.denom;
 
564
    temp       = gnc_numeric_reduce(temp);
 
565
  
 
566
    out.num   = in.num * temp.num;
 
567
    out.num   = (out.num < 0) ? -out.num : out.num;
 
568
    remainder = out.num % temp.denom;
 
569
    out.num   = out.num / temp.denom;
 
570
    out.denom = denom;
 
571
  }
 
572
 
 
573
  if(remainder > 0) {
 
574
    switch(how) {
 
575
    case GNC_RND_FLOOR:
 
576
      if(sign < 0) {
 
577
        out.num = out.num + 1;
 
578
      }
 
579
      break;
 
580
      
 
581
    case GNC_RND_CEIL:
 
582
      if(sign > 0) {
 
583
        out.num = out.num + 1;
 
584
      }
 
585
      break;
 
586
      
 
587
    case GNC_RND_TRUNC:
 
588
      break;
 
589
 
 
590
    case GNC_RND_PROMOTE:
 
591
      out.num = out.num + 1;
 
592
      break;
 
593
      
 
594
    case GNC_RND_ROUND_HALF_DOWN:
 
595
      if(denom_neg) {
 
596
        if((2 * remainder) > in.denom*denom) {
 
597
          out.num = out.num + 1;
 
598
        }
 
599
      }
 
600
      else if((2 * remainder) > temp.denom) {
 
601
        out.num = out.num + 1;
 
602
      }
 
603
      break;
 
604
      
 
605
    case GNC_RND_ROUND_HALF_UP:
 
606
      if(denom_neg) {
 
607
        if((2 * remainder) >= in.denom*denom) {
 
608
          out.num = out.num + 1;
 
609
        }
 
610
      }
 
611
      else if((2 * remainder ) >= temp.denom) {
 
612
        out.num = out.num + 1;
 
613
      }
 
614
      break;
 
615
      
 
616
    case GNC_RND_ROUND:
 
617
      if(denom_neg) {
 
618
        if((2 * remainder) > in.denom*denom) {
 
619
          out.num = out.num + 1;
 
620
        }
 
621
        else if((2 * remainder) == in.denom*denom) {
 
622
          if(out.num % 2) {
 
623
            out.num = out.num + 1;
 
624
          }
 
625
        }        
 
626
      }
 
627
      else {
 
628
        if((2 * remainder ) > temp.denom) {
 
629
          out.num = out.num + 1;
 
630
        }
 
631
        else if((2 * remainder) == temp.denom) {
 
632
          if(out.num % 2) {
 
633
            out.num = out.num + 1;
 
634
          }
 
635
        }    
 
636
      }    
 
637
      break;
 
638
      
 
639
    case GNC_RND_NEVER:
 
640
      return gnc_numeric_error(GNC_ERROR_REMAINDER);
 
641
      break;
 
642
    }
 
643
  }
 
644
  
 
645
  out.num = (sign > 0) ? out.num : (-out.num);
 
646
  
 
647
  return out;
 
648
}
 
649
 
 
650
 
 
651
/********************************************************************
 
652
 *  gnc_numeric_lcd
 
653
 *  Find the least common multiple of the denominators of 
 
654
 *  a and b
 
655
 ********************************************************************/
 
656
 
 
657
gint64
 
658
gnc_numeric_lcd(gnc_numeric a, gnc_numeric b) {
 
659
  gint64 current_divisor = 2;
 
660
  gint64 max_square;
 
661
  gint64 three_count = 0;
 
662
  gint64 small_denom;
 
663
  gint64 big_denom;
 
664
 
 
665
  if(gnc_numeric_check(a) || gnc_numeric_check(b)) {
 
666
    return GNC_ERROR_ARG;
 
667
  }
 
668
  
 
669
  if(b.denom < a.denom) {
 
670
    small_denom = b.denom;
 
671
    big_denom = a.denom;
 
672
  }
 
673
  else {
 
674
    small_denom = a.denom;
 
675
    big_denom = b.denom;
 
676
  }
 
677
 
 
678
  /* special case: smaller divides smoothly into larger */
 
679
  if((big_denom % small_denom) == 0) {
 
680
    return big_denom;
 
681
  }
 
682
  
 
683
  max_square = small_denom;
 
684
  
 
685
  /* the LCM algorithm : take the union of the prime factors of the
 
686
   * two args and multiply them together. To do this, we find the
 
687
   * successive prime factors of the smaller denominator and eliminate
 
688
   * them from the larger denominator, then multiply the smaller by
 
689
   * the remains of the larger. */
 
690
  while(current_divisor * current_divisor <= max_square) {
 
691
    if(((small_denom % current_divisor) == 0) &&
 
692
       ((big_denom % current_divisor) == 0)) {
 
693
      big_denom = big_denom / current_divisor;
 
694
    }
 
695
    else {
 
696
      if(current_divisor == 2) {
 
697
        current_divisor++;
 
698
      }
 
699
      else if(three_count == 3) { 
 
700
        current_divisor += 4;
 
701
        three_count = 1;
 
702
      }
 
703
      else {
 
704
        current_divisor += 2;
 
705
        three_count++;
 
706
      }
 
707
    }
 
708
    
 
709
    if((current_divisor > small_denom) ||
 
710
       (current_divisor > big_denom)) {
 
711
      break;
 
712
    }
 
713
  }
 
714
  
 
715
  return small_denom * big_denom;
 
716
 
 
717
}
 
718
  
 
719
 
 
720
/********************************************************************
 
721
 *  gnc_numeric_reduce
 
722
 *  reduce a fraction by GCF elimination.  This is NOT done as a
 
723
 *  part of the arithmetic API unless GNC_DENOM_REDUCE is specified 
 
724
 *  as the output denominator.
 
725
 ********************************************************************/
 
726
 
 
727
gnc_numeric
 
728
gnc_numeric_reduce(gnc_numeric in) {
 
729
 
 
730
  gint64   current_divisor = 2;
 
731
  gint64   max_square;
 
732
  gint64   num = (in.num < 0) ? (- in.num) : in.num ;
 
733
  gint64   denom = in.denom;
 
734
  int      three_count = 0;
 
735
  gnc_numeric out;
 
736
 
 
737
  if(gnc_numeric_check(in)) {
 
738
    return gnc_numeric_error(GNC_ERROR_ARG);
 
739
  }
 
740
 
 
741
  /* the strategy is to eliminate common factors from 
 
742
   * 2 up to 'max', where max is the smaller of the smaller
 
743
   * part of the fraction and the sqrt of the larger part of 
 
744
   * the fraction.  There's also the special case of the 
 
745
   * smaller of fraction parts being a common factor.
 
746
   * 
 
747
   * we test for 2 and 3 first, and thereafter skip all even numbers
 
748
   * and all odd multiples of 3 (that's every third odd number,
 
749
   * i.e. 9, 15, 21), thus the three_count stuff. */
 
750
 
 
751
  /* special case: one side divides evenly by the other */
 
752
  if (num == 0) {
 
753
    denom = 1;
 
754
  }
 
755
  else if((num > denom) && (num % denom == 0)) {
 
756
    num = num / denom;
 
757
    denom = 1;
 
758
  }
 
759
  else if ((num <= denom) && (denom % num == 0)) {
 
760
    denom = denom / num;
 
761
    num = 1;
 
762
  }
 
763
 
 
764
  max_square = (num > denom) ? denom : num;
 
765
 
 
766
  /* normal case: test 2, then 3, 5, 7, 11, etc.
 
767
   * (skip multiples of 2 and 3) */
 
768
  while(current_divisor * current_divisor <= max_square) {
 
769
    if((num % current_divisor == 0) &&
 
770
       (denom % current_divisor == 0)) {
 
771
      num = num / current_divisor;
 
772
      denom = denom / current_divisor;
 
773
    }
 
774
    else {
 
775
      if(current_divisor == 2) {
 
776
        current_divisor++;
 
777
      }
 
778
      else if(three_count == 3) { 
 
779
        current_divisor += 4;
 
780
        three_count = 1;
 
781
      }
 
782
      else {
 
783
        current_divisor += 2;
 
784
        three_count++;
 
785
      }
 
786
    }
 
787
 
 
788
    if((current_divisor > num) ||
 
789
       (current_divisor > denom)) {
 
790
      break;
 
791
    }
 
792
  }
 
793
 
 
794
  /* all calculations are done on positive num, since it's not 
 
795
   * well defined what % does for negative values */
 
796
  out.num   = (in.num < 0) ? (- num) : num;
 
797
  out.denom = denom;
 
798
  return out;
 
799
}
 
800
 
 
801
/********************************************************************
 
802
 *  double_to_gnc_numeric
 
803
 ********************************************************************/
 
804
 
 
805
gnc_numeric
 
806
double_to_gnc_numeric(double in, gint64 denom, gint how) {
 
807
  gnc_numeric out;
 
808
  gint64 int_part=0;
 
809
  double frac_part;
 
810
  gint64 frac_int=0;
 
811
  double logval; 
 
812
  double sigfigs;
 
813
 
 
814
  if((denom == GNC_DENOM_AUTO) && (how & GNC_DENOM_SIGFIG)) {
 
815
    if(fabs(in) < 10e-20) {
 
816
      logval = 0;
 
817
    }
 
818
    else {
 
819
      logval   = log10(fabs(in));
 
820
      logval   = ((logval > 0.0) ? 
 
821
                  (floor(logval)+1.0) : (ceil(logval)));
 
822
    }
 
823
    sigfigs  = GNC_NUMERIC_GET_SIGFIGS(how);
 
824
    if(sigfigs-logval >= 0) {
 
825
      denom    = (gint64)(pow(10, sigfigs-logval));
 
826
    }
 
827
    else {
 
828
      denom    = -((gint64)(pow(10, logval-sigfigs)));
 
829
    }
 
830
 
 
831
    how =  how & ~GNC_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
 
832
  }
 
833
 
 
834
  int_part  = (gint64)(floor(fabs(in)));
 
835
  frac_part = in - (double)int_part;
 
836
  
 
837
  int_part = int_part * denom;
 
838
  frac_part = frac_part * (double)denom;
 
839
 
 
840
  switch(how & GNC_NUMERIC_RND_MASK) {
 
841
  case GNC_RND_FLOOR:
 
842
    frac_int = (gint64)floor(frac_part);
 
843
    break;
 
844
 
 
845
  case GNC_RND_CEIL:
 
846
    frac_int = (gint64)ceil(frac_part);
 
847
    break;
 
848
 
 
849
  case GNC_RND_TRUNC:
 
850
    frac_int = (gint64)frac_part;
 
851
    break;
 
852
    
 
853
  case GNC_RND_ROUND:
 
854
  case GNC_RND_ROUND_HALF_UP:
 
855
    frac_int = (gint64)rint(frac_part);
 
856
    break;
 
857
 
 
858
  case GNC_RND_NEVER:
 
859
    frac_int = (gint64)floor(frac_part);
 
860
    if(frac_part != (double) frac_int) {
 
861
      /* signal an error */
 
862
    }
 
863
    break;
 
864
  }
 
865
 
 
866
  out.num   = int_part + frac_int; 
 
867
  out.denom = denom;
 
868
  return out;
 
869
}
 
870
 
 
871
/********************************************************************
 
872
 *  gnc_numeric_to_double
 
873
 ********************************************************************/
 
874
 
 
875
double
 
876
gnc_numeric_to_double(gnc_numeric in) {
 
877
  if(in.denom >= 0) {
 
878
    return (double)in.num/(double)in.denom;
 
879
  }
 
880
  else {
 
881
    return (double)(in.num * in.denom);
 
882
  }
 
883
}
 
884
 
 
885
 
 
886
/********************************************************************
 
887
 *  gnc_numeric_create
 
888
 ********************************************************************/
 
889
 
 
890
gnc_numeric
 
891
gnc_numeric_create(gint64 num, gint64 denom) {
 
892
  gnc_numeric out;
 
893
  out.num = num;
 
894
  out.denom = denom;
 
895
  return out;
 
896
}
 
897
 
 
898
 
 
899
/********************************************************************
 
900
 *  gnc_numeric_error
 
901
 ********************************************************************/
 
902
 
 
903
gnc_numeric
 
904
gnc_numeric_error(int error_code) {
 
905
  if(abs(error_code) < 5) {
 
906
    //    PERR("%s", _numeric_error_strings[ - error_code]);
 
907
  }
 
908
  return gnc_numeric_create(error_code, 0LL);
 
909
}
 
910
 
 
911
 
 
912
/********************************************************************
 
913
 *  gnc_numeric_zero
 
914
 ********************************************************************/
 
915
 
 
916
gnc_numeric
 
917
gnc_numeric_zero(void) {
 
918
  return gnc_numeric_create(0LL, 1LL);
 
919
}
 
920
 
 
921
 
 
922
/********************************************************************
 
923
 *  gnc_numeric_num
 
924
 ********************************************************************/
 
925
 
 
926
gint64
 
927
gnc_numeric_num(gnc_numeric a) {
 
928
  return a.num;
 
929
}
 
930
 
 
931
 
 
932
/********************************************************************
 
933
 *  gnc_numeric_denom
 
934
 ********************************************************************/
 
935
 
 
936
gint64
 
937
gnc_numeric_denom(gnc_numeric a) {
 
938
  return a.denom;
 
939
}
 
940
 
 
941
 
 
942
/********************************************************************
 
943
 *  gnc_numeric_add_with_error
 
944
 ********************************************************************/
 
945
 
 
946
gnc_numeric
 
947
gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b, 
 
948
                           gint64 denom, gint how,
 
949
                           gnc_numeric * error) {
 
950
 
 
951
  gnc_numeric sum   = gnc_numeric_add(a, b, denom, how);
 
952
  gnc_numeric exact = gnc_numeric_add(a, b, GNC_DENOM_AUTO, 
 
953
                                      GNC_DENOM_REDUCE);
 
954
  gnc_numeric err   = gnc_numeric_sub(sum, exact, GNC_DENOM_AUTO,
 
955
                                      GNC_DENOM_REDUCE);
 
956
 
 
957
  if(error) {
 
958
    *error = err;
 
959
  }
 
960
  return sum;
 
961
}
 
962
 
 
963
/********************************************************************
 
964
 *  gnc_numeric_sub_with_error
 
965
 ********************************************************************/
 
966
 
 
967
gnc_numeric
 
968
gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b, 
 
969
                           gint64 denom, gint how,
 
970
                           gnc_numeric * error) {
 
971
 
 
972
  gnc_numeric diff  = gnc_numeric_sub(a, b, denom, how);
 
973
  gnc_numeric exact = gnc_numeric_sub(a, b, GNC_DENOM_AUTO,
 
974
                                      GNC_DENOM_REDUCE);
 
975
  gnc_numeric err   = gnc_numeric_sub(diff, exact, GNC_DENOM_AUTO, 
 
976
                                      GNC_DENOM_REDUCE);
 
977
  if(error) {
 
978
    *error = err;
 
979
  }
 
980
  return diff;
 
981
}
 
982
 
 
983
 
 
984
/********************************************************************
 
985
 *  gnc_numeric_mul_with_error
 
986
 ********************************************************************/
 
987
 
 
988
gnc_numeric
 
989
gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b, 
 
990
                           gint64 denom, gint how,
 
991
                           gnc_numeric * error) {
 
992
 
 
993
  gnc_numeric prod  = gnc_numeric_mul(a, b, denom, how);
 
994
  gnc_numeric exact = gnc_numeric_mul(a, b, GNC_DENOM_AUTO,
 
995
                                      GNC_DENOM_REDUCE);
 
996
  gnc_numeric err   = gnc_numeric_sub(prod, exact, GNC_DENOM_AUTO,
 
997
                                      GNC_DENOM_REDUCE);
 
998
  if(error) {
 
999
    *error = err;
 
1000
  }
 
1001
  return prod;
 
1002
}
 
1003
 
 
1004
 
 
1005
/********************************************************************
 
1006
 *  gnc_numeric_div_with_error
 
1007
 ********************************************************************/
 
1008
 
 
1009
gnc_numeric
 
1010
gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b, 
 
1011
                           gint64 denom, gint how,
 
1012
                           gnc_numeric * error) {
 
1013
 
 
1014
  gnc_numeric quot  = gnc_numeric_div(a, b, denom, how);
 
1015
  gnc_numeric exact = gnc_numeric_div(a, b, GNC_DENOM_AUTO, 
 
1016
                                      GNC_DENOM_REDUCE);
 
1017
  gnc_numeric err   = gnc_numeric_sub(quot, exact, 
 
1018
                                      GNC_DENOM_AUTO, GNC_DENOM_REDUCE);
 
1019
  if(error) {
 
1020
    *error = err;
 
1021
  }
 
1022
  return quot;
 
1023
}
 
1024
 
 
1025
int
 
1026
gnc_numeric_check(gnc_numeric in) {
 
1027
  if(in.denom != 0) {
 
1028
    return GNC_ERROR_OK;
 
1029
  }
 
1030
  else if(in.num) {
 
1031
    return in.num;
 
1032
  }
 
1033
  else {
 
1034
    return GNC_ERROR_ARG;
 
1035
  }
 
1036
}
 
1037
 
 
1038
/********************************************************************
 
1039
 *  gnc_numeric text IO
 
1040
 ********************************************************************/
 
1041
 
 
1042
gchar *
 
1043
gnc_numeric_to_string(gnc_numeric n) {
 
1044
  gchar *result;
 
1045
  long long int tmpnum = n.num;
 
1046
  long long int tmpdenom = n.denom;
 
1047
 
 
1048
  result = g_strdup_printf("%lld/%lld", tmpnum, tmpdenom);
 
1049
 
 
1050
  return result;
 
1051
}
 
1052
 
 
1053
const gchar *
 
1054
string_to_gnc_numeric(const gchar* str, gnc_numeric *n) {
 
1055
  /* Read a gnc_numeric from str, skipping any leading whitespace, and
 
1056
     returning a pointer to just past the last byte read.  Return NULL
 
1057
     on error. */
 
1058
  int num_read;
 
1059
  long long int tmpnum;
 
1060
  long long int tmpdenom;
 
1061
    
 
1062
  if(!str) return NULL;
 
1063
 
 
1064
  /* must use "<" here because %n's effects aren't well defined */
 
1065
  if(sscanf(str, " " GNC_SCANF_LLD "/" GNC_SCANF_LLD "%n",
 
1066
            &tmpnum, &tmpdenom, &num_read) < 2) {
 
1067
    return(NULL);
 
1068
  }
 
1069
  n->num = tmpnum;
 
1070
  n->denom = tmpdenom;
 
1071
  return(str + num_read);
 
1072
}
 
1073
 
 
1074
#ifdef _GNC_NUMERIC_TEST
 
1075
 
 
1076
static char *
 
1077
gnc_numeric_print(gnc_numeric in) {
 
1078
  char * retval;
 
1079
  if(gnc_numeric_check(in)) {
 
1080
    retval = g_strdup_printf("<ERROR> [%lld / %lld]",
 
1081
                             (long long int) in.num,
 
1082
                             (long long int) in.denom); 
 
1083
  }
 
1084
  else {
 
1085
    retval = g_strdup_printf("[%lld / %lld]",
 
1086
                             (long long int) in.num,
 
1087
                             (long long int) in.denom); 
 
1088
  }
 
1089
  return retval;
 
1090
}
 
1091
 
 
1092
int
 
1093
main(int argc, char ** argv) {
 
1094
  gnc_numeric a = gnc_numeric_create(1, 3);
 
1095
  gnc_numeric b = gnc_numeric_create(1, 4);
 
1096
  gnc_numeric c;
 
1097
  gnc_numeric d = gnc_numeric_create(1, 2);
 
1098
  
 
1099
  gnc_numeric err;
 
1100
  int i;
 
1101
 
 
1102
  printf("add exact : %s + %s = %s\n",
 
1103
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1104
         gnc_numeric_print(gnc_numeric_add(a, b, 
 
1105
                                           GNC_DENOM_AUTO, 
 
1106
                                           GNC_DENOM_EXACT)));
 
1107
  
 
1108
  
 
1109
  printf("add least : %s + %s = %s\n",
 
1110
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1111
         gnc_numeric_print(gnc_numeric_add(a, b, 
 
1112
                                           GNC_DENOM_AUTO, 
 
1113
                                           GNC_DENOM_REDUCE)));
 
1114
  
 
1115
  printf("add 100ths (banker's): %s + %s = %s\n",
 
1116
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1117
         gnc_numeric_print(gnc_numeric_add(a, b, 100,
 
1118
                                           GNC_RND_ROUND)));
 
1119
  
 
1120
  c = gnc_numeric_add_with_error(a, b, 100, GNC_RND_ROUND, &err);
 
1121
  printf("add 100ths/error : %s + %s = %s + (error) %s\n\n",
 
1122
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1123
         gnc_numeric_print(c),
 
1124
         gnc_numeric_print(err));
 
1125
  
 
1126
  printf("sub exact : %s - %s = %s\n",
 
1127
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1128
         gnc_numeric_print(gnc_numeric_sub(a, b, GNC_DENOM_AUTO, 
 
1129
                                           GNC_DENOM_EXACT)));
 
1130
  
 
1131
  printf("sub least : %s - %s = %s\n",
 
1132
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1133
         gnc_numeric_print(gnc_numeric_sub(a, b, 
 
1134
                                           GNC_DENOM_AUTO, 
 
1135
                                           GNC_DENOM_REDUCE)));
 
1136
  
 
1137
  printf("sub 100ths : %s - %s = %s\n",
 
1138
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1139
         gnc_numeric_print(gnc_numeric_sub(a, b, 100,
 
1140
                                           GNC_RND_ROUND)));
 
1141
  
 
1142
  c = gnc_numeric_sub_with_error(a, b, 100, GNC_RND_FLOOR, &err);
 
1143
  printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
 
1144
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1145
         gnc_numeric_print(c),
 
1146
         gnc_numeric_print(err));
 
1147
  
 
1148
  printf("mul exact : %s * %s = %s\n",
 
1149
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1150
         gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, 
 
1151
                                           GNC_DENOM_EXACT)));
 
1152
 
 
1153
  printf("mul least : %s * %s = %s\n",
 
1154
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1155
         gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, 
 
1156
                                           GNC_DENOM_REDUCE)));
 
1157
  
 
1158
  printf("mul 100ths : %s * %s = %s\n",
 
1159
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1160
         gnc_numeric_print(gnc_numeric_mul(a, b, 100,
 
1161
                                           GNC_RND_ROUND)));
 
1162
 
 
1163
  c = gnc_numeric_mul_with_error(a, b, 100, GNC_RND_ROUND, &err);
 
1164
  printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
 
1165
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1166
         gnc_numeric_print(c),
 
1167
         gnc_numeric_print(err));
 
1168
  
 
1169
  printf("div exact : %s / %s = %s\n",
 
1170
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1171
         gnc_numeric_print(gnc_numeric_div(a, b, GNC_DENOM_AUTO, 
 
1172
                                           GNC_DENOM_EXACT)));
 
1173
  
 
1174
  printf("div least : %s / %s = %s\n",
 
1175
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1176
         gnc_numeric_print(gnc_numeric_div(a, b, GNC_DENOM_AUTO, 
 
1177
                                           GNC_DENOM_REDUCE)));
 
1178
  
 
1179
  printf("div 100ths : %s / %s = %s\n",
 
1180
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1181
         gnc_numeric_print(gnc_numeric_div(a, b, 100,
 
1182
                                           GNC_RND_ROUND)));  
 
1183
  
 
1184
  c = gnc_numeric_div_with_error(a, b, 100, GNC_RND_ROUND, &err);
 
1185
  printf("div 100ths/error : %s / %s = %s + (error) %s\n\n",
 
1186
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1187
         gnc_numeric_print(c),
 
1188
         gnc_numeric_print(err));
 
1189
  
 
1190
  printf("7/16 as float: %e\n",
 
1191
         gnc_numeric_to_double(gnc_numeric_create(7, 16)));
 
1192
  
 
1193
  printf("7/16 as 100ths (floor): %s\n",
 
1194
         gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(7, 16),
 
1195
                                               100, GNC_RND_FLOOR)));
 
1196
  printf("7/16 as 100ths (ceil): %s\n",
 
1197
         gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(7, 16),
 
1198
                                               100, GNC_RND_CEIL)));
 
1199
  printf("7/16 as 100ths (trunc): %s\n",
 
1200
         gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(7, 16),
 
1201
                                               100, GNC_RND_TRUNC)));
 
1202
  printf("7/16 as 100ths (round): %s\n",
 
1203
         gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(7, 16),
 
1204
                                               100, GNC_RND_ROUND)));
 
1205
 
 
1206
  printf("1511/1000 as 1/100 (round): %s\n",
 
1207
         gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(1511, 1000),
 
1208
                                               100, GNC_RND_ROUND)));
 
1209
  printf("1516/1000 as 1/100 (round): %s\n",
 
1210
         gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(1516, 1000),
 
1211
                                               100, GNC_RND_ROUND)));
 
1212
  printf("1515/1000 as 1/100 (round): %s\n",
 
1213
         gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(1515, 1000),
 
1214
                                               100, GNC_RND_ROUND)));
 
1215
  printf("1525/1000 as 1/100 (round): %s\n",
 
1216
         gnc_numeric_print(gnc_numeric_convert(gnc_numeric_create(1525, 1000),
 
1217
                                               100, GNC_RND_ROUND)));
 
1218
 
 
1219
  printf("100023234 / 334216654 reduced: %s\n",
 
1220
         gnc_numeric_print(gnc_numeric_reduce(gnc_numeric_create(10023234LL,
 
1221
                                                                 334216654LL))));
 
1222
  printf("2^10*3^10*17^2 / 2^8*3^12 reduced: %s\n",
 
1223
         gnc_numeric_print
 
1224
         (gnc_numeric_reduce(gnc_numeric_create(17474724864LL,
 
1225
                                                136048896LL))));
 
1226
  printf("1024 / 1024^4 reduced: %s\n",
 
1227
         gnc_numeric_print
 
1228
         (gnc_numeric_reduce(gnc_numeric_create(1024LL,
 
1229
                                                1099511627776LL))));
 
1230
  printf("reducing 100,000 times:\n\n");
 
1231
  for(i = 0; i < 100000; i++) {
 
1232
    gnc_numeric_reduce(gnc_numeric_create(17474724864LL,
 
1233
                                          136048896LL));
 
1234
  }
 
1235
  
 
1236
  printf("add LCM: %s + %s = %s\n",
 
1237
         gnc_numeric_print(b), gnc_numeric_print(d),
 
1238
         gnc_numeric_print(gnc_numeric_add(b, d, GNC_DENOM_AUTO,
 
1239
                                           GNC_DENOM_LCD)));
 
1240
 
 
1241
  printf("float to 6 sigfigs: %s\n",
 
1242
         gnc_numeric_print(double_to_gnc_numeric(1.1234567890123, 
 
1243
                                                 GNC_DENOM_AUTO, 
 
1244
                                                 GNC_DENOM_SIGFIGS(6) |
 
1245
                                                 GNC_RND_ROUND)));
 
1246
  printf("float to 6 sigfigs: %s\n",
 
1247
         gnc_numeric_print(double_to_gnc_numeric(.011234567890123, 
 
1248
                                                 GNC_DENOM_AUTO, 
 
1249
                                                 GNC_DENOM_SIGFIGS(6) |
 
1250
                                                 GNC_RND_ROUND)));
 
1251
  printf("float to 6 sigfigs: %s\n",
 
1252
         gnc_numeric_print(double_to_gnc_numeric(1123.4567890123, 
 
1253
                                                 GNC_DENOM_AUTO, 
 
1254
                                                 GNC_DENOM_SIGFIGS(6) |
 
1255
                                                 GNC_RND_ROUND)));
 
1256
  printf("float to 6 sigfigs: %s\n",
 
1257
         gnc_numeric_print(double_to_gnc_numeric(1.1234567890123e-5, 
 
1258
                                                 GNC_DENOM_AUTO, 
 
1259
                                                 GNC_DENOM_SIGFIGS(6) |
 
1260
                                                 GNC_RND_ROUND)));
 
1261
  printf("add to 4 sigfigs: %s + %s = %s\n",
 
1262
         gnc_numeric_print(a), gnc_numeric_print(b),
 
1263
         gnc_numeric_print(gnc_numeric_add(a, b, 
 
1264
                                           GNC_DENOM_AUTO, 
 
1265
                                           GNC_DENOM_SIGFIGS(4) |
 
1266
                                           GNC_RND_ROUND)));
 
1267
  
 
1268
   
 
1269
  return 0;
 
1270
}
 
1271
#endif