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