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