001/*
002 * $Id: BigDecimal.java 5568 2016-08-03 19:14:39Z 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 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    }
435
436
437    /**
438     * Compare absolute to BigDecimal b. Experimental, is hacked.
439     * @param b BigDecimal.
440     * @return 0 if abs(this-b) &lt; epsilon, 1 if this &gt; b, -1 if this &lt;
441     *         b.
442     */
443    public int compareToAbsolute(BigDecimal b) {
444        //if (EXACT_EQUAL) {
445        //    return val.compareTo(b.val);
446        //}
447        java.math.BigDecimal s = val.subtract(b.val, context);
448        java.math.BigDecimal u1 = val.ulp();
449        java.math.BigDecimal u2 = b.val.ulp();
450        int u = Math.min(u1.scale(), u2.scale());
451        //System.out.println("u = " + u + ", s = " + s);
452        java.math.BigDecimal eps;
453        if (u <= 0) {
454            eps = u1.max(u2);
455        } else {
456            eps = u1.min(u2);
457        }
458        //eps = eps.movePointRight(1);
459        //System.out.println("ctx = " + context);
460        //System.out.println("eps = " + eps);
461        int t = s.abs().compareTo(eps);
462        if (t < 1) {
463            return 0;
464        }
465        return s.signum();
466    }
467
468
469    /**
470     * Compare to relative BigDecimal b. Experimental, is hacked.
471     * @param b BigDecimal.
472     * @return 0 if abs(this-b)/max(this,b) &lt; epsilon, 1 if this &gt; b, -1
473     *         if this &lt; b.
474     */
475    public int compareToRelative(BigDecimal b) {
476        //if (EXACT_EQUAL) {
477        //    return val.compareTo(b.val);
478        //}
479        java.math.BigDecimal s = val.subtract(b.val, context);
480        java.math.BigDecimal u1 = val.ulp();
481        java.math.BigDecimal u2 = b.val.ulp();
482        int u = Math.min(u1.scale(), u2.scale());
483        //System.out.println("u = " + u + ", s = " + s);
484        java.math.BigDecimal eps;
485        if (u <= 0) {
486            eps = u1.max(u2);
487        } else {
488            eps = u1.min(u2);
489        }
490        eps = eps.movePointRight(1);
491        //System.out.println("ctx = " + context);
492        //System.out.println("eps = " + eps);
493        java.math.BigDecimal m = val.abs().max(b.val.abs());
494        int t;
495        if (m.compareTo(java.math.BigDecimal.ONE) <= 1) {
496            t = s.abs().compareTo(eps);
497        } else {
498            t = s.abs().divide(m, context).compareTo(eps);
499        }
500        if (t < 1) {
501            return 0;
502        }
503        return s.signum();
504    }
505
506
507    /**
508     * Comparison with any other object.
509     * @see java.lang.Object#equals(java.lang.Object)
510     */
511    @Override
512    public boolean equals(Object b) {
513        if (!(b instanceof BigDecimal)) {
514            return false;
515        }
516        BigDecimal bi = (BigDecimal) b;
517        if (EXACT_EQUAL) {
518            return val.equals(bi.val);
519        }
520        return compareTo(bi) == 0;
521    }
522
523
524    /**
525     * Hash code for this BigDecimal.
526     * @see java.lang.Object#hashCode()
527     */
528    @Override
529    public int hashCode() {
530        return val.hashCode();
531    }
532
533
534    /**
535     * Absolute value of this.
536     * @see edu.jas.structure.RingElem#abs()
537     */
538    public BigDecimal abs() {
539        return new BigDecimal(val.abs(), context);
540    }
541
542
543    /* Negative value of this.
544     * @see edu.jas.structure.RingElem#negate()
545     */
546    public BigDecimal negate() {
547        return new BigDecimal(val.negate(), context);
548    }
549
550
551    /**
552     * signum.
553     * @see edu.jas.structure.RingElem#signum()
554     */
555    public int signum() {
556        return val.signum();
557    }
558
559
560    /**
561     * BigDecimal subtract.
562     * @param S BigDecimal.
563     * @return this-S.
564     */
565    public BigDecimal subtract(BigDecimal S) {
566        return new BigDecimal(val.subtract(S.val, context), context);
567    }
568
569
570    /**
571     * BigDecimal divide.
572     * @param S BigDecimal.
573     * @return this/S.
574     */
575    public BigDecimal divide(BigDecimal S) {
576        return new BigDecimal(val.divide(S.val, context), context);
577    }
578
579
580    /**
581     * Integer inverse. R is a non-zero integer. S=1/R if defined else 0.
582     * @see edu.jas.structure.RingElem#inverse()
583     */
584    public BigDecimal inverse() {
585        return ONE.divide(this);
586    }
587
588
589    /**
590     * BigDecimal remainder.
591     * @param S BigDecimal.
592     * @return this - (this/S)*S.
593     */
594    public BigDecimal remainder(BigDecimal S) {
595        return new BigDecimal(val.remainder(S.val, context), context);
596    }
597
598
599    /**
600     * BigDecimal compute quotient and remainder.
601     * @param S BigDecimal.
602     * @return BigDecimal[] { q, r } with q = this/S and r = rem(this,S).
603     */
604    public BigDecimal[] quotientRemainder(BigDecimal S) {
605        BigDecimal[] qr = new BigDecimal[2];
606        java.math.BigDecimal[] C = val.divideAndRemainder(S.val, context);
607        qr[0] = new BigDecimal(C[0], context);
608        qr[1] = new BigDecimal(C[1], context);
609        return qr;
610    }
611
612
613    /**
614     * BigDecimal greatest common divisor.
615     * @param S BigDecimal.
616     * @return gcd(this,S).
617     */
618    public BigDecimal gcd(BigDecimal S) {
619        throw new UnsupportedOperationException("BigDecimal.gcd() not implemented");
620        //return new BigDecimal( val.gcd( S.val ) );
621    }
622
623
624    /**
625     * BigDecimal extended greatest common divisor.
626     * @param S BigDecimal.
627     * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S).
628     */
629    public BigDecimal[] egcd(BigDecimal S) {
630        throw new UnsupportedOperationException("BigDecimal.egcd() not implemented");
631    }
632
633
634    /**
635     * BigDecimal random.
636     * @param n such that 0 &le; val(r) &le; (2<sup>n</sup>-1). 0 &le; exp(r)
637     *            &le; (10-1).
638     * @return r, a random BigDecimal.
639     */
640    public BigDecimal random(int n) {
641        return random(n, random);
642    }
643
644
645    /**
646     * BigDecimal random.
647     * @param n such that 0 &le; val(r) &le; (2<sup>n</sup>-1). 0 &le; exp(r)
648     *            &le; (10-1).
649     * @param rnd is a source for random bits.
650     * @return r, a random BigDecimal.
651     */
652    public BigDecimal random(int n, Random rnd) {
653        return random(n, 10, rnd);
654    }
655
656
657    /**
658     * BigDecimal random.
659     * @param n such that 0 &le; val(r) &le; (2<sup>n</sup>-1).
660     * @param e such that 0 &le; exp(r) &le; (e-1).
661     * @return r, a random BigDecimal.
662     */
663    public BigDecimal random(int n, int e) {
664        return random(n, e, random);
665    }
666
667
668    /**
669     * BigDecimal random.
670     * @param n such that 0 &le; val(r) &le; (2<sup>n</sup>-1).
671     * @param e such that 0 &le; exp(r) &le; (e-1).
672     * @param rnd is a source for random bits.
673     * @return r, a random BigDecimal.
674     */
675    public BigDecimal random(int n, int e, Random rnd) {
676        java.math.BigInteger r = new java.math.BigInteger(n, rnd);
677        if (rnd.nextBoolean()) {
678            r = r.negate();
679        }
680        int scale = rnd.nextInt(e);
681        //if (rnd.nextBoolean()) { // not according to param spec
682        //    scale = -scale;
683        //}
684        java.math.BigDecimal d = new java.math.BigDecimal(r, scale, context);
685        return new BigDecimal(d, context);
686    }
687
688
689    /**
690     * BigDecimal multiply.
691     * @param S BigDecimal.
692     * @return this*S.
693     */
694    public BigDecimal multiply(BigDecimal S) {
695        return new BigDecimal(val.multiply(S.val, context), context);
696    }
697
698
699    /**
700     * BigDecimal summation.
701     * @param S BigDecimal.
702     * @return this+S.
703     */
704    public BigDecimal sum(BigDecimal S) {
705        return new BigDecimal(val.add(S.val, context), context);
706    }
707
708
709    /**
710     * BigDecimal parse from String.
711     * @param s String.
712     * @return Biginteger from s.
713     */
714    public BigDecimal parse(String s) {
715        return new BigDecimal(s, context);
716    }
717
718
719    /**
720     * BigDecimal parse from Reader.
721     * @param r Reader.
722     * @return next Biginteger from r.
723     */
724    public BigDecimal parse(Reader r) {
725        return parse(StringUtil.nextString(r));
726    }
727
728
729    /**
730     * Returns the number of bits in the representation of this BigDecimal,
731     * including a sign bit. For positive BigDecimal, this is equivalent to
732     * {@code val.unscaledValue().bitLength()}.)
733     * @return number of bits in the representation of this BigDecimal,
734     *         including a sign bit.
735     */
736    public long bitLength() {
737        long n = val.unscaledValue().bitLength();
738        if (val.signum() < 0) {
739            n++;
740        }
741        n++;
742        n += BigInteger.bitLength(val.scale());
743        return n;
744    }
745
746}