|
@@ -0,0 +1,189 @@
|
|
|
|
|
+/*
|
|
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
|
|
+ * @license WTFPL
|
|
|
|
|
+ * @url http://ranides.net/projects/assira
|
|
|
|
|
+ */
|
|
|
|
|
+package net.ranides.assira.math;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * Number represented in "place-value notation" / "positional notation"
|
|
|
|
|
+ * @author ranides
|
|
|
|
|
+ */
|
|
|
|
|
+public abstract class PVNumber extends Number implements Cloneable, Comparable<PVNumber> {
|
|
|
|
|
+
|
|
|
|
|
+ protected static final int DIGITS_INT = 14;
|
|
|
|
|
+
|
|
|
|
|
+ protected static final int DIGITS_LONG = 24;
|
|
|
|
|
+
|
|
|
|
|
+ protected static final int DIGITS_FLOAT = 45;
|
|
|
|
|
+
|
|
|
|
|
+ protected static final int DIGITS_DOUBLE = 325;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * base used by number
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public abstract int base();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * maximal number of digits
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public abstract int capacity();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * minimal exponent (can be negative)
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public abstract int begin();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * maximal exponent (can be negative)
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public abstract int end();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * get digit for passed exponent
|
|
|
|
|
+ * @param exponent
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public abstract int get(int exponent);
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * set digit for passed exponent
|
|
|
|
|
+ * @param exponent
|
|
|
|
|
+ * @param value
|
|
|
|
|
+ */
|
|
|
|
|
+ public abstract void set(int exponent, int value);
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * actual number of digits
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ public int size() {
|
|
|
|
|
+ return end() - begin();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int intValue() {
|
|
|
|
|
+ int ret = 0;
|
|
|
|
|
+ int b = base();
|
|
|
|
|
+ int r = 1;
|
|
|
|
|
+ for(int i=0, n=Math.min(DIGITS_INT,end()); i<=n; i++) {
|
|
|
|
|
+ ret += r*get(i);
|
|
|
|
|
+ r *= b;
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public long longValue() {
|
|
|
|
|
+ long ret = 0;
|
|
|
|
|
+ long b = base();
|
|
|
|
|
+ long r = 1;
|
|
|
|
|
+ for(int i=0, n=Math.min(DIGITS_LONG,end()); i<=n; i++) {
|
|
|
|
|
+ ret += r*get(i);
|
|
|
|
|
+ r *= b;
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public float floatValue() {
|
|
|
|
|
+ float b = base();
|
|
|
|
|
+ float ret = 0;
|
|
|
|
|
+ float r = 1.0f;
|
|
|
|
|
+ for(int i=0, n=Math.min(DIGITS_FLOAT,end()); i<=n; i++) {
|
|
|
|
|
+ ret += r * get(i);
|
|
|
|
|
+ r *= b;
|
|
|
|
|
+ }
|
|
|
|
|
+ r = 1.0f / b;
|
|
|
|
|
+ for(int i=-1, n=Math.max(-DIGITS_FLOAT, begin()); i>=n; i--) {
|
|
|
|
|
+ ret += r * get(i);
|
|
|
|
|
+ r /= b;
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public double doubleValue() {
|
|
|
|
|
+ double b = base();
|
|
|
|
|
+ double ret = 0;
|
|
|
|
|
+ double r = 1.0f;
|
|
|
|
|
+ for(int i=0, n=Math.min(DIGITS_DOUBLE,end()); i<=n; i++) {
|
|
|
|
|
+ ret += r * get(i);
|
|
|
|
|
+ r *= b;
|
|
|
|
|
+ }
|
|
|
|
|
+ r = 1.0f / b;
|
|
|
|
|
+ for(int i=-1, n=Math.max(-DIGITS_DOUBLE, begin()); i>=n; i--) {
|
|
|
|
|
+ ret += r * get(i);
|
|
|
|
|
+ r /= b;
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public String toString() {
|
|
|
|
|
+ return toString(63,63); // maximal length of string: 127 or 255
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public String toString(int imax, int fmax) {
|
|
|
|
|
+ String sep = base()<=10 ? "" : " ";
|
|
|
|
|
+ StringBuilder ret = new StringBuilder();
|
|
|
|
|
+
|
|
|
|
|
+ for(int i=Math.min(imax-1,end()); i>0; i--) {
|
|
|
|
|
+ ret.append( get(i) ).append(sep);
|
|
|
|
|
+ }
|
|
|
|
|
+ ret.append( get(0) );
|
|
|
|
|
+ if(begin() < 0) {
|
|
|
|
|
+ ret.append(sep).append(".");
|
|
|
|
|
+ }
|
|
|
|
|
+ for(int i=-1, mi=Math.max(-fmax,begin()); i>=mi; i--) {
|
|
|
|
|
+ ret.append(sep).append( get(i) );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ret.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int compareTo(PVNumber value) {
|
|
|
|
|
+ if( value.base() != base() ) {
|
|
|
|
|
+ // @todo (assira # 7) PVNumber: comparing different bases
|
|
|
|
|
+ throw new UnsupportedOperationException("Not supported yet.");
|
|
|
|
|
+ }
|
|
|
|
|
+ int rr = end() - value.end();
|
|
|
|
|
+ if(rr != 0) {
|
|
|
|
|
+ return rr;
|
|
|
|
|
+ }
|
|
|
|
|
+ for(int i=end(), n=Math.min(begin(), value.begin()); i>=n; i--) {
|
|
|
|
|
+ int dr = get(i) - value.get(i);
|
|
|
|
|
+ if(dr != 0) {
|
|
|
|
|
+ return dr;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public boolean equals(Object object) {
|
|
|
|
|
+ if(object instanceof PVNumber) {
|
|
|
|
|
+ return compareTo((PVNumber)object) == 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int hashCode() {
|
|
|
|
|
+ int ret = 0;
|
|
|
|
|
+ int b = 19 * base();
|
|
|
|
|
+ for(int i=begin(), c=0, n=end(); i<=n && c<16; i++, c++) {
|
|
|
|
|
+ ret = (b*ret) ^ get(i);
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+}
|