001/*
002 * $Id$
003 */
004
005package edu.jas.arith;
006
007
008import java.io.Reader;
009import java.math.MathContext;
010import java.util.ArrayList;
011import java.util.List;
012import java.util.Random;
013
014import edu.jas.kern.StringUtil;
015import edu.jas.structure.GcdRingElem;
016import edu.jas.structure.RingFactory;
017
018
019/**
020 * BigDecimal class to make java.math.BigDecimal available with RingElem
021 * interface. Objects of this class are immutable. Experimental, use with care,
022 * compareTo is some times hacked.
023 * @author Heinz Kredel
024 * @see java.math.BigDecimal
025 */
026
027public final class BigDecimal implements GcdRingElem<BigDecimal>, RingFactory<BigDecimal> {
028
029
030    /**
031     * The data structure.
032     */
033    public final java.math.BigDecimal val;
034
035
036    private final static Random random = new Random();
037
038
039    public static final MathContext DEFAULT_CONTEXT = MathContext.DECIMAL64; //32; //64; //128;
040
041
042    public static final int DEFAULT_PRECISION = DEFAULT_CONTEXT.getPrecision();
043
044
045    public final MathContext context;
046
047
048    /**
049     * If true, then use equals from java.math.BigDecimal, else use hacked
050     * approximate compareTo().
051     */
052    public final static boolean EXACT_EQUAL = true;
053
054
055    /**
056     * The constant 0.
057     */
058    public final static BigDecimal ZERO = new BigDecimal(java.math.BigDecimal.ZERO);
059
060
061    /**
062     * The constant 1.
063     */
064    public final static BigDecimal ONE = new BigDecimal(java.math.BigDecimal.ONE);
065
066
067    /**
068     * Constructor for BigDecimal from math.BigDecimal.
069     * @param a java.math.BigDecimal.
070     */
071    public BigDecimal(java.math.BigDecimal a) {
072        this(a, DEFAULT_CONTEXT);
073    }
074
075
076    /**
077     * Constructor for BigDecimal from math.BigDecimal.
078     * @param a java.math.BigDecimal.
079     * @param mc MathContext.
080     */
081    public BigDecimal(java.math.BigDecimal a, MathContext mc) {
082        val = a;
083        context = mc;
084    }
085
086
087    /**
088     * Constructor for BigDecimal from long.
089     * @param a long.
090     */
091    public BigDecimal(long a) {
092        this(a, DEFAULT_CONTEXT);
093    }
094
095
096    /**
097     * Constructor for BigDecimal from long and a context.
098     * @param a long.
099     * @param mc MathContext.
100     */
101    public BigDecimal(long a, MathContext mc) {
102        this(new java.math.BigDecimal(String.valueOf(a)), mc);
103    }
104
105
106    /**
107     * Constructor for BigDecimal from double.
108     * @param a double.
109     */
110    public BigDecimal(double a) {
111        this(a, DEFAULT_CONTEXT);
112    }
113
114
115    /**
116     * Constructor for BigDecimal from double and a context.
117     * @param a double.
118     * @param mc MathContext.
119     */
120    public BigDecimal(double a, MathContext mc) {
121        this(new java.math.BigDecimal(a, mc), mc);
122    }
123
124
125    /**
126     * Constructor for BigDecimal from java.math.BigInteger.
127     * @param a java.math.BigInteger.
128     */
129    public BigDecimal(java.math.BigInteger a) {
130        this(a, DEFAULT_CONTEXT);
131    }
132
133
134    /**
135     * Constructor for BigDecimal from java.math.BigInteger.
136     * @param a java.math.BigInteger.
137     * @param mc MathContext.
138     */
139    public BigDecimal(java.math.BigInteger a, MathContext mc) {
140        this(new java.math.BigDecimal(a), mc);
141    }
142
143
144    /**
145     * Constructor for BigDecimal from BigRational.
146     * @param a edu.jas.arith.BigRational.
147     */
148    public BigDecimal(BigRational a) {
149        this(a, DEFAULT_CONTEXT);
150    }
151
152
153    /**
154     * Constructor for BigDecimal from BigRational.
155     * @param a edu.jas.arith.BigRational.
156     * @param mc MathContext.
157     */
158    public BigDecimal(BigRational a, MathContext mc) {
159        this((new java.math.BigDecimal(a.num, mc)).divide(new java.math.BigDecimal(a.den, mc), mc), mc);
160    }
161
162
163    /**
164     * Constructor for BigDecimal from String.
165     * @param s String.
166     */
167    public BigDecimal(String s) {
168        this(s, DEFAULT_CONTEXT);
169    }
170
171
172    /**
173     * Constructor for BigDecimal from String.
174     * @param s String.
175     * @param mc MathContext.
176     */
177    public BigDecimal(String s, MathContext mc) {
178        this(new java.math.BigDecimal(s.trim()), mc);
179    }
180
181
182    /**
183     * Constructor for BigDecimal without parameters.
184     */
185    public BigDecimal() {
186        this(java.math.BigDecimal.ZERO, DEFAULT_CONTEXT);
187    }
188
189
190    /*
191     * Get the value.
192     * @return val java.math.BigDecimal. public java.math.BigDecimal getVal() {
193     *         return val; }
194     */
195
196
197    /**
198     * Get the corresponding element factory.
199     * @return factory for this Element.
200     * @see edu.jas.structure.Element#factory()
201     */
202    public BigDecimal factory() {
203        return this;
204    }
205
206
207    /**
208     * Get a list of the generating elements.
209     * @return list of generators for the algebraic structure.
210     * @see edu.jas.structure.ElemFactory#generators()
211     */
212    public List<BigDecimal> generators() {
213        List<BigDecimal> g = new ArrayList<BigDecimal>(1);
214        g.add(getONE());
215        return g;
216    }
217
218
219    /**
220     * Is this structure finite or infinite.
221     * @return true if this structure is finite, else false.
222     * @see edu.jas.structure.ElemFactory#isFinite() <b>Note: </b> is actually
223     *      finite but returns false.
224     */
225    public boolean isFinite() {
226        return false;
227    }
228
229
230    /**
231     * Clone this.
232     * @see java.lang.Object#clone()
233     */
234    @Override
235    public BigDecimal copy() {
236        return new BigDecimal(val, context);
237    }
238
239
240    /**
241     * Copy BigDecimal element c.
242     * @param c BigDecimal.
243     * @return a copy of c.
244     */
245    public BigDecimal copy(BigDecimal c) {
246        return new BigDecimal(c.val, c.context);
247    }
248
249
250    /**
251     * Get the zero element.
252     * @return 0.
253     */
254    public BigDecimal getZERO() {
255        return ZERO;
256    }
257
258
259    /**
260     * Get the one element.
261     * @return 1.
262     */
263    public BigDecimal getONE() {
264        return ONE;
265    }
266
267
268    /**
269     * Query if this ring is commutative.
270     * @return true.
271     */
272    public boolean isCommutative() {
273        return true;
274    }
275
276
277    /**
278     * Query if this ring is associative. Floating point number addition is not
279     * associative, but multiplication is.
280     * @return true.
281     */
282    public boolean isAssociative() {
283        return true;
284    }
285
286
287    /**
288     * Query if this ring is a field.
289     * @return true.
290     */
291    public boolean isField() {
292        return true;
293    }
294
295
296    /**
297     * Characteristic of this ring.
298     * @return characteristic of this ring.
299     */
300    public java.math.BigInteger characteristic() {
301        return java.math.BigInteger.ZERO;
302    }
303
304
305    /**
306     * Get a BigDecimal element from a math.BigDecimal.
307     * @param a math.BigDecimal.
308     * @return a as BigDecimal.
309     */
310    public BigDecimal fromInteger(java.math.BigInteger a) {
311        return new BigDecimal(new java.math.BigDecimal(a), context);
312    }
313
314
315    /**
316     * Get a BigDecimal element from a math.BigDecimal.
317     * @param a math.BigDecimal.
318     * @return a as BigDecimal.
319     */
320    public static BigDecimal valueOf(java.math.BigDecimal a) {
321        return new BigDecimal(a, DEFAULT_CONTEXT);
322    }
323
324
325    /**
326     * Get a BigDecimal element from long.
327     * @param a long.
328     * @return a as BigDecimal.
329     */
330    public BigDecimal fromInteger(long a) {
331        return new BigDecimal(a, context);
332    }
333
334
335    /**
336     * Get a BigDecimal element from long.
337     * @param a long.
338     * @return a as BigDecimal.
339     */
340    public static BigDecimal valueOf(long a) {
341        return new BigDecimal(a, DEFAULT_CONTEXT);
342    }
343
344
345    /**
346     * Is BigDecimal number zero.
347     * @return If this is 0 then true is returned, else false.
348     * @see edu.jas.structure.RingElem#isZERO()
349     */
350    public boolean isZERO() {
351        if (EXACT_EQUAL) {
352            return val.compareTo(java.math.BigDecimal.ZERO) == 0;
353        }
354        return compareTo(ZERO) == 0;
355    }
356
357
358    /**
359     * Is BigDecimal number one.
360     * @see edu.jas.structure.RingElem#isONE()
361     */
362    public boolean isONE() {
363        if (EXACT_EQUAL) {
364            return val.compareTo(java.math.BigDecimal.ONE) == 0;
365        }
366        return compareTo(ONE) == 0;
367    }
368
369
370    /**
371     * Is BigDecimal number unit.
372     * @see edu.jas.structure.RingElem#isUnit()
373     */
374    public boolean isUnit() {
375        return (!isZERO());
376    }
377
378
379    /**
380     * Get the String representation.
381     * @see java.lang.Object#toString()
382     */
383    @Override
384    public String toString() {
385        //return val.toString() + "(ulp=" + val.ulp() + ")";
386        return val.toString();
387    }
388
389
390    /**
391     * Get this decimal as a <tt>double</tt>.
392     * @return the decimal as a <tt>double</tt>
393     * @see java.lang.Number#doubleValue()
394     */
395    public double doubleValue() {
396        return val.doubleValue();
397    }
398
399
400    /**
401     * Get a scripting compatible string representation.
402     * @return script compatible representation for this Element.
403     * @see edu.jas.structure.Element#toScript()
404     */
405    @Override
406    public String toScript() {
407        // Python+Ruby case
408        return toString();
409    }
410
411
412    /**
413     * Get a scripting compatible string representation of the factory.
414     * @return script compatible representation for this ElemFactory.
415     * @see edu.jas.structure.Element#toScriptFactory()
416     */
417    @Override
418    public String toScriptFactory() {
419        // Python+Ruby case
420        return "DD()";
421    }
422
423
424    /**
425     * Compare to BigDecimal b. Experimental, is hacked.
426     * @param b BigDecimal.
427     * @return 0 if abs(this-b) &lt; epsilon, 1 if this &gt; b, -1 if this &lt;
428     *         b.
429     */
430    @Override
431    public int compareTo(BigDecimal b) {
432        //return compareToAbsolute(b);
433        //return compareToRelative(b);
434        return val.compareTo(b.val);
435    }
436
437
438    /**
439     * Compare absolute to BigDecimal b. Experimental, is hacked.
440     * @param b BigDecimal.
441     * @return 0 if abs(this-b) &lt; epsilon, 1 if this &gt; b, -1 if this &lt;
442     *         b.
443     */
444    public int compareToAbsolute(BigDecimal b) {
445        //if (EXACT_EQUAL) {
446        //    return val.compareTo(b.val);
447        //}
448        java.math.BigDecimal s = val.subtract(b.val, context);
449        java.math.BigDecimal u1 = val.ulp();
450        java.math.BigDecimal u2 = b.val.ulp();
451        int u = Math.min(u1.scale(), u2.scale());
452        //System.out.println("u = " + u + ", s = " + s);
453        java.math.BigDecimal eps;
454        if (u <= 0) {
455            eps = u1.max(u2);
456        } else {
457            eps = u1.min(u2);
458        }
459        //eps = eps.movePointRight(1);
460        //System.out.println("ctx = " + context);
461        //System.out.println("eps = " + eps);
462        int t = s.abs().compareTo(eps);
463        if (t < 1) {
464            return 0;
465        }
466        return s.signum();
467    }
468
469
470    /**
471     * Compare to relative BigDecimal b. Experimental, is hacked.
472     * @param b BigDecimal.
473     * @return 0 if abs(this-b)/max(this,b) &lt; epsilon, 1 if this &gt; b, -1
474     *         if this &lt; b.
475     */
476    public int compareToRelative(BigDecimal b) {
477        //if (EXACT_EQUAL) {
478        //    return val.compareTo(b.val);
479        //}
480        java.math.BigDecimal s = val.subtract(b.val, context);
481        java.math.BigDecimal u1 = val.ulp();
482        java.math.BigDecimal u2 = b.val.ulp();
483        int u = Math.min(u1.scale(), u2.scale());
484        //System.out.println("u = " + u + ", s = " + s);
485        java.math.BigDecimal eps;
486        if (u <= 0) {
487            eps = u1.max(u2);
488        } else {
489            eps = u1.min(u2);
490        }
491        eps = eps.movePointRight(1);
492        //System.out.println("ctx = " + context);
493        //System.out.println("eps = " + eps);
494        java.math.BigDecimal m = val.abs().max(b.val.abs());
495        int t;
496        if (m.compareTo(java.math.BigDecimal.ONE) <= 1) {
497            t = s.abs().compareTo(eps);
498        } else {
499            t = s.abs().divide(m, context).compareTo(eps);
500        }
501        if (t < 1) {
502            return 0;
503        }
504        return s.signum();
505    }
506
507
508    /**
509     * Comparison with any other object.
510     * @see java.lang.Object#equals(java.lang.Object)
511     */
512    @Override
513    public boolean equals(Object b) {
514        if (!(b instanceof BigDecimal)) {
515            return false;
516        }
517        BigDecimal bi = (BigDecimal) b;
518        if (EXACT_EQUAL) {
519            return val.equals(bi.val);
520        }
521        return compareTo(bi) == 0;
522    }
523
524
525    /**
526     * Hash code for this BigDecimal.
527     * @see java.lang.Object#hashCode()
528     */
529    @Override
530    public int hashCode() {
531        return val.hashCode();
532    }
533
534
535    /**
536     * Absolute value of this.
537     * @see edu.jas.structure.RingElem#abs()
538     */
539    public BigDecimal abs() {
540        return new BigDecimal(val.abs(), context);
541    }
542
543
544    /* Negative value of this.
545     * @see edu.jas.structure.RingElem#negate()
546     */
547    public BigDecimal negate() {
548        return new BigDecimal(val.negate(), context);
549    }
550
551
552    /**
553     * signum.
554     * @see edu.jas.structure.RingElem#signum()
555     */
556    public int signum() {
557        return val.signum();
558    }
559
560
561    /**
562     * BigDecimal subtract.
563     * @param S BigDecimal.
564     * @return this-S.
565     */
566    public BigDecimal subtract(BigDecimal S) {
567        return new BigDecimal(val.subtract(S.val, context), context);
568    }
569
570
571    /**
572     * BigDecimal divide.
573     * @param S BigDecimal.
574     * @return this/S.
575     */
576    public BigDecimal divide(BigDecimal S) {
577        return new BigDecimal(val.divide(S.val, context), context);
578    }
579
580
581    /**
582     * Integer inverse. R is a non-zero integer. S=1/R if defined else 0.
583     * @see edu.jas.structure.RingElem#inverse()
584     */
585    public BigDecimal inverse() {
586        return ONE.divide(this);
587    }
588
589
590    /**
591     * BigDecimal remainder.
592     * @param S BigDecimal.
593     * @return this - (this/S)*S.
594     */
595    public BigDecimal remainder(BigDecimal S) {
596        return new BigDecimal(val.remainder(S.val, context), context);
597    }
598
599
600    /**
601     * BigDecimal compute quotient and remainder.
602     * @param S BigDecimal.
603     * @return BigDecimal[] { q, r } with q = this/S and r = rem(this,S).
604     */
605    public BigDecimal[] quotientRemainder(BigDecimal S) {
606        BigDecimal[] qr = new BigDecimal[2];
607        java.math.BigDecimal[] C = val.divideAndRemainder(S.val, context);
608        qr[0] = new BigDecimal(C[0], context);
609        qr[1] = new BigDecimal(C[1], context);
610        return qr;
611    }
612
613
614    /**
615     * BigDecimal greatest common divisor.
616     * @param S BigDecimal.
617     * @return gcd(this,S).
618     */
619    public BigDecimal gcd(BigDecimal S) {
620        throw new UnsupportedOperationException("BigDecimal.gcd() not implemented");
621        //return new BigDecimal( val.gcd( S.val ) );
622    }
623
624
625    /**
626     * BigDecimal extended greatest common divisor.
627     * @param S BigDecimal.
628     * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S).
629     */
630    public BigDecimal[] egcd(BigDecimal S) {
631        throw new UnsupportedOperationException("BigDecimal.egcd() not implemented");
632    }
633
634
635    /**
636     * BigDecimal random.
637     * @param n such that 0 &le; val(r) &le; (2<sup>n</sup>-1). 0 &le; exp(r)
638     *            &le; (10-1).
639     * @return r, a random BigDecimal.
640     */
641    public BigDecimal random(int n) {
642        return random(n, random);
643    }
644
645
646    /**
647     * BigDecimal random.
648     * @param n such that 0 &le; val(r) &le; (2<sup>n</sup>-1). 0 &le; exp(r)
649     *            &le; (10-1).
650     * @param rnd is a source for random bits.
651     * @return r, a random BigDecimal.
652     */
653    public BigDecimal random(int n, Random rnd) {
654        return random(n, 10, rnd);
655    }
656
657
658    /**
659     * BigDecimal random.
660     * @param n such that 0 &le; val(r) &le; (2<sup>n</sup>-1).
661     * @param e such that 0 &le; exp(r) &le; (e-1).
662     * @return r, a random BigDecimal.
663     */
664    public BigDecimal random(int n, int e) {
665        return random(n, e, random);
666    }
667
668
669    /**
670     * BigDecimal random.
671     * @param n such that 0 &le; val(r) &le; (2<sup>n</sup>-1).
672     * @param e such that 0 &le; exp(r) &le; (e-1).
673     * @param rnd is a source for random bits.
674     * @return r, a random BigDecimal.
675     */
676    public BigDecimal random(int n, int e, Random rnd) {
677        java.math.BigInteger r = new java.math.BigInteger(n, rnd);
678        if (rnd.nextBoolean()) {
679            r = r.negate();
680        }
681        int scale = rnd.nextInt(e);
682        //if (rnd.nextBoolean()) { // not according to param spec
683        //    scale = -scale;
684        //}
685        java.math.BigDecimal d = new java.math.BigDecimal(r, scale, context);
686        return new BigDecimal(d, context);
687    }
688
689
690    /**
691     * BigDecimal multiply.
692     * @param S BigDecimal.
693     * @return this*S.
694     */
695    public BigDecimal multiply(BigDecimal S) {
696        return new BigDecimal(val.multiply(S.val, context), context);
697    }
698
699
700    /**
701     * BigDecimal summation.
702     * @param S BigDecimal.
703     * @return this+S.
704     */
705    public BigDecimal sum(BigDecimal S) {
706        return new BigDecimal(val.add(S.val, context), context);
707    }
708
709
710    /**
711     * BigDecimal parse from String.
712     * @param s String.
713     * @return Biginteger from s.
714     */
715    public BigDecimal parse(String s) {
716        return new BigDecimal(s, context);
717    }
718
719
720    /**
721     * BigDecimal parse from Reader.
722     * @param r Reader.
723     * @return next Biginteger from r.
724     */
725    public BigDecimal parse(Reader r) {
726        return parse(StringUtil.nextString(r));
727    }
728
729
730    /**
731     * Returns the number of bits in the representation of this BigDecimal,
732     * including a sign bit. For positive BigDecimal, this is equivalent to
733     * {@code val.unscaledValue().bitLength()}.)
734     * @return number of bits in the representation of this BigDecimal,
735     *         including a sign bit.
736     */
737    public long bitLength() {
738        long n = val.unscaledValue().bitLength();
739        if (val.signum() < 0) {
740            n++;
741        }
742        n++;
743        n += BigInteger.bitLength(val.scale());
744        return n;
745    }
746
747}