Ranides Atterwim 12 年之前
父節點
當前提交
a426e8fa51

+ 23 - 0
src/main/java/net/ranides/assira/math/PVMath.java

@@ -20,4 +20,27 @@ public final class PVMath {
         return (int) Math.ceil( value.capacity() * Math.log(value.base()) / Math.log(newbase) );
     }
 
+    static int c2i(char value) {
+        if( value >= '0' && value <= '9') {
+            return value - '0';
+        }
+        if( value >= 'a' && value <= 'z') {
+            return value - 'a';
+        }
+        if( value >= 'A' && value <= 'Z') {
+            return value - 'A';
+        }
+        throw new IllegalArgumentException("'" + value +"' is not correct digit");
+    }
+
+    static char i2c(int value) {
+        if( value >=0 && value <=9 ) {
+            return (char)('0'+value);
+        }
+        if( value >=10 && value <=36 ) {
+            return (char)('A'+value-10);
+        }
+        throw new IllegalArgumentException("'" + value +"' is not displayable as digit");
+    }
+
 }

+ 95 - 11
src/main/java/net/ranides/assira/math/PVNumber.java

@@ -6,6 +6,9 @@
  */
 package net.ranides.assira.math;
 
+import java.util.List;
+import net.ranides.assira.collection.list.VirtualList;
+
 /**
  * Number represented in "place-value notation" / "positional notation"
  * @author ranides
@@ -20,6 +23,16 @@ public abstract class PVNumber extends Number implements Cloneable, Comparable<P
 
     protected static final int DIGITS_DOUBLE = 325;
 
+    public interface Digit {
+
+        int base();
+
+        int exponent();
+
+        int value();
+
+    }
+
     /**
      * base used by number
      * @return
@@ -63,7 +76,7 @@ public abstract class PVNumber extends Number implements Cloneable, Comparable<P
      * @return
      */
     public int size() {
-        return end() - begin();
+        return end() - begin() + 1;
     }
 
     @Override
@@ -130,18 +143,31 @@ public abstract class PVNumber extends Number implements Cloneable, Comparable<P
     }
 
     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) );
+        if(base()<=10 || base()==16) {
+            for(int i=Math.min(imax-1,end()); i>0; i--) {
+                ret.append( PVMath.i2c(get(i)) );
+            }
+            ret.append( PVMath.i2c(get(0)) );
+            if(begin() < 0) {
+                ret.append(".");
+            }
+            for(int i=-1, mi=Math.max(-fmax,begin()); i>=mi; i--) {
+                ret.append( PVMath.i2c(get(i)) );
+            }
+            return ret.toString();
+        } else {
+            for(int i=Math.min(imax-1,end()); i>0; i--) {
+                ret.append( get(i) ).append(" ");
+            }
+            ret.append( get(0) );
+            if(begin() < 0) {
+                ret.append(" .");
+            }
+            for(int i=-1, mi=Math.max(-fmax,begin()); i>=mi; i--) {
+                ret.append(" ").append( get(i) );
+            }
         }
 
         return ret.toString();
@@ -184,6 +210,64 @@ public abstract class PVNumber extends Number implements Cloneable, Comparable<P
         return ret;
     }
 
+    /**
+     * Natural ordered list, i.e. most significat digits are before least significant.
+     * @return
+     */
+    public List<Digit> digits() {
+        return new NDCollection();
+    }
+
+    public boolean isZero() {
+        return (0 == begin()) && (0 == end()) && (0 == get(0));
+    }
+
+    private class NDCollection extends VirtualList<Digit> {
+
+        private final int imax;
+        private final int isize;
+
+        public NDCollection() {
+            this.imax = PVNumber.this.end();
+            this.isize = PVNumber.this.size();
+        }
+
+        @Override
+        public int size() {
+            return isize;
+        }
+
+        @Override
+        public Digit get(int index) {
+            return new NDigit(imax - index);
+        }
+
+    }
+
+    private class NDigit implements Digit {
+
+        private final int exp;
+
+        public NDigit(int exp) {
+            this.exp = exp;
+        }
+
+        @Override
+        public int base() {
+            return PVNumber.this.base();
+        }
+
+        @Override
+        public int exponent() {
+            return exp;
+        }
+
+        @Override
+        public int value() {
+            return PVNumber.this.get(exp);
+        }
+
+    }
 
 
 }

+ 54 - 3
src/test/java/net/ranides/assira/math/PVNumberTest.java

@@ -29,7 +29,6 @@ import org.junit.Test;
         public RINumber(int base) {
             this.base = base;
             this.data = new TreeMap<Integer, Integer>();
-            this.data.put(0, 0);
         }
 
         public RINumber(String value) {
@@ -60,12 +59,12 @@ import org.junit.Test;
 
         @Override
         public int begin() {
-            return data.firstKey();
+            return data.isEmpty() ? 0 : data.firstKey();
         }
 
         @Override
         public int end() {
-            return data.lastKey();
+            return data.isEmpty() ? 0 : data.lastKey();
         }
 
         @Override
@@ -81,6 +80,7 @@ import org.junit.Test;
     }
 
     public PVNumberTest() {
+        // do nothing
     }
 
     @Test
@@ -113,6 +113,53 @@ import org.junit.Test;
 
     }
 
+
+    @Test
+    public void testDigits() {
+        assertEquals("1:1 0:7", digitHash(ri("17")) );
+        assertEquals("0:0 -1:0 -2:0 -3:1 -4:7", digitHash(ri("0.0017")) );
+        assertEquals("1:1 0:7 -1:9 -2:2 -3:3", digitHash(ri("17.923")) );
+    }
+
+    @Test
+    public void testRebase() {
+        System.out.println(" rebase = " + irebase(2, ri(0xA4)));
+        System.out.println(" rebase = " + irebase(16, ri(0xA4)) );
+        System.out.println(" rebase = " + irebase(16, ri(0xC8A4)) );
+    }
+
+    private static PVNumber irebase(int base, PVNumber number) {
+        PVNumber ret = ri(base);
+        PVNumber b = ri(base);
+        PVNumber v = number;
+        int e = 0;
+
+        while( !v.isZero() ) {
+            ret.set(e++, rem(v, b).intValue());
+            v = div(v, b);
+        }
+        return ret;
+    }
+
+    private static PVNumber rem(PVNumber n1, PVNumber n2) {
+        return new RINumber( String.valueOf(n1.longValue() % n2.longValue()) );
+    }
+
+    private static PVNumber div(PVNumber n1, PVNumber n2) {
+        return new RINumber( String.valueOf(n1.longValue() / n2.longValue()) );
+    }
+
+    private static String digitHash(PVNumber number) {
+        StringBuilder ret = new StringBuilder(number.size() * 6);
+        for(PVNumber.Digit item : number.digits()) {
+            if(ret.length() > 0) {
+                ret.append(' ');
+            }
+            ret.append(item.exponent()).append(':').append(item.value());
+        }
+        return ret.toString();
+    }
+
     private static PVNumber ri(int zeros, String value) {
         return new RINumber("0." + StringUtils.nCopies(zeros, '0') + value);
     }
@@ -121,4 +168,8 @@ import org.junit.Test;
         return new RINumber(value);
     }
 
+    private static PVNumber ri(int value) {
+        return new RINumber(String.valueOf(value));
+    }
+
 }