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