Quellcode durchsuchen

BCDecimal - draft

Strings#contains - method moved from "StringUtils"
Strings#asSequence - new method
Ranides Atterwim vor 12 Jahren
Ursprung
Commit
714a9ed51b

+ 201 - 0
src/main/java/net/ranides/assira/math/BCDecimal.java

@@ -0,0 +1,201 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+
+package net.ranides.assira.math;
+
+import java.util.Arrays;
+import net.ranides.assira.text.Strings;
+
+/**
+ *
+ * @author ranides
+ */
+public class BCDecimal extends Number implements Comparable<BCDecimal> {
+
+    private final byte[] data;
+
+    public BCDecimal(long value) {
+        this(32, value);
+    }
+
+    public BCDecimal(int size, long value) {
+        this.data = new byte[floor2(size)];
+        int index = 0;
+        while(value > 0) {
+            if(index >= size) {
+                throw new ArithmeticException("BCDecimal: value is too large.");
+            }
+            at(index++, (int)(value % 10));
+            value /= 10;
+        }
+    }
+
+    public BCDecimal(int size, char[] value) {
+        this(size, Strings.asSequence(value));
+    }
+
+    public BCDecimal(int size, CharSequence value) {
+        this.data = new byte[floor2(size)];
+        for(int n=value.length()-1, i=0; i<=n; i++) {
+            at(n-i, value.charAt(i)-'0');
+        }
+    }
+
+    public BCDecimal(Number value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public int intValue() {
+        int ret = 0;
+        int di= 1;
+        for(int i=0; i<9; i++) {
+            ret +=  di * at(i);
+            di*=10;
+        }
+        return ret;
+    }
+
+    @Override
+    public long longValue() {
+        long ret = 0;
+        for(int i=0; i<20; i++) {
+            ret +=  i * at(i);
+        }
+        return ret;
+    }
+
+    @Override
+    public float floatValue() {
+        return longValue();
+    }
+
+    @Override
+    public double doubleValue() {
+        return longValue();
+    }
+
+    @Override
+    public int compareTo(BCDecimal value) {
+        int n = Math.max(size(), value.size());
+        for(int i=n-1; i>=0; i--) {
+            int d = at(i)-value.at(i);
+            if(d != 0) {
+                return d;
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(data);
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        if( object == this) {
+            return true;
+        }
+        if( object instanceof BCDecimal ) {
+            return 0 == compareTo( (BCDecimal)object );
+        }
+        if( object instanceof Number) {
+            return 0 == new BCDecimal((Number)object).compareTo(this);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder( size() );
+        boolean nz = false;
+        for(int i=size()-1; i>=0; i--) {
+            char v = (char)('0' + at(i));
+            if(v != '0' || nz) {
+                builder.append(v);
+                nz = true;
+            }
+        }
+        if(!nz) {
+            return "0";
+        }
+        return builder.toString();
+    }
+
+    public BCDecimal add(BCDecimal value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal sub(BCDecimal value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal mul(BCDecimal value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal div(BCDecimal value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal mod(BCDecimal value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal pow(BCDecimal value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal abs() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal neg() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal min(BCDecimal value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public BCDecimal max(BCDecimal value) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    private static int floor2(int value) {
+        return (value / 2) + (value % 2);
+    }
+
+    public final void at(int index, int value) {
+        int seg = data.length - index / 2 - 1;
+        if(0 == index % 2) {
+            data[seg] = (byte)((data[seg] & 0xF0) | (value & 0x0F));
+        } else {
+            data[seg] = (byte)((data[seg] & 0x0F) | (value << 4));
+        }
+    }
+
+    public int at(int index) {
+        int seg = data.length - index / 2 - 1;
+        if( seg <0 ) {
+            return 0;
+        }
+        if(0 == index % 2) {
+            return data[seg] & 0x0F;
+        } else {
+            return (data[seg] >> 4) & 0x0F;
+        }
+    }
+
+    public int size() {
+        return data.length * 2;
+    }
+
+
+
+}

+ 0 - 8
src/main/java/net/ranides/assira/text/StringUtils.java

@@ -452,12 +452,4 @@ public final class StringUtils {
         return REGEX_SPECIAL.matcher(text).replaceAll("\\\\$1");
     }
 
-    public static boolean contains(String text, char value) {
-        return text.indexOf(value) != -1;
-    }
-
-    public static boolean contains(String text, CharSequence value) {
-        return text.contains(value);
-    }
-
 }

+ 85 - 7
src/main/java/net/ranides/assira/text/Strings.java

@@ -9,6 +9,7 @@ package net.ranides.assira.text;
 import java.text.MessageFormat;
 import java.util.Formatter;
 import java.util.Locale;
+import net.ranides.assira.annotations.PMD;
 import net.ranides.assira.math.MathUtils;
 
 /**
@@ -19,7 +20,7 @@ import net.ranides.assira.math.MathUtils;
 public final class Strings {
 
     private Strings() { /* utility class */ }
-    
+
     public static String sprintf(Locale locale, String format, Object... args) {
         return new Formatter().format(locale, format, args).toString();
     }
@@ -35,7 +36,7 @@ public final class Strings {
     public static String format(String format, Object... args) {
         return format(Locale.ROOT, format, args);
     }
-    
+
     public static String or(Object... values) {
         for(Object value : values) {
             if(null!=value) { return value.toString(); }
@@ -80,7 +81,7 @@ public final class Strings {
     public static boolean isAssigned(CharSequence value) {
         return (null!=value) && value.length() != 0;
     }
-    
+
     public static boolean isEqual(Object valueA, Object valueB) {
         if(null == valueA) {
             return (null == valueB);
@@ -96,19 +97,96 @@ public final class Strings {
             return valueA.compareTo(valueB);
         }
     }
-    
+
+    public static boolean contains(String text, char value) {
+        return text!=null && text.indexOf(value) != -1;
+    }
+
+    public static boolean contains(String text, CharSequence value) {
+        return text!=null && text.contains(value);
+    }
+
     public static int length(String value) {
         return (null == value) ? 0 : value.length();
     }
-    
+
     public static String substring(String text, int first) {
         if(null == text) { return ""; }
         return substring(text, first, text.length());
     }
-    
+
     public static String substring(String text, int first, int last) {
         if(null == text || first >= last || first>=text.length()) { return ""; }
         return text.substring(first, MathUtils.clip(last, first, text.length()));
     }
-    
+
+    public static CharSequence asSequence(char[] data) {
+        return new ArrayWrapper(data);
+    }
+
+    private static final class SliceWrapper implements CharSequence {
+
+        private final char[] data;
+        private final int start;
+        private final int end;
+
+        public SliceWrapper(char[] data, int start, int end) {
+            this.data = data;
+            this.start = start;
+            this.end = end;
+        }
+
+        @Override
+        public int length() {
+            return end - start;
+        }
+
+        @Override
+        public char charAt(int index) {
+            return data[index + start];
+        }
+
+        @Override
+        public CharSequence subSequence(int start, int end) {
+            return new SliceWrapper(data, this.start+start, this.start+end);
+        }
+
+        @Override
+        public String toString() {
+            return String.valueOf(data, start, length());
+        }
+
+    }
+
+    @PMD.ArrayWrapper
+    private static final class ArrayWrapper implements CharSequence {
+
+        private final char[] data;
+
+        public ArrayWrapper(char[] data) { // NOPMD
+            this.data = data;
+        }
+
+        @Override
+        public int length() {
+            return data.length;
+        }
+
+        @Override
+        public char charAt(int index) {
+            return data[index];
+        }
+
+        @Override
+        public CharSequence subSequence(int start, int end) {
+            return new SliceWrapper(data, start, end);
+        }
+
+        @Override
+        public String toString() {
+            return String.valueOf(data);
+        }
+
+    }
+
 }

+ 45 - 0
src/test/java/net/ranides/assira/math/BCDecimalTest.java

@@ -0,0 +1,45 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.math;
+
+import net.ranides.assira.text.Strings;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author ranides
+ */
+public class BCDecimalTest {
+
+    public BCDecimalTest() {
+    }
+
+    @Test
+    public void testConstruct() {
+        assertEquals("0", new BCDecimal(20, 0).toString());
+        assertEquals("7", new BCDecimal(20, 7).toString());
+        assertEquals("135874", new BCDecimal(20, 135874).toString());
+        assertEquals("13587", new BCDecimal(6, 13587).toString());
+        assertEquals("12345", new BCDecimal(5, 12345).toString());
+
+        try {
+            assertEquals("12345", new BCDecimal(4, 12345).toString());
+            fail("ArithmeticException expected");
+        } catch (ArithmeticException cause) {
+            assertTrue(Strings.contains(cause.getMessage(), "BCDecimal"));
+        }
+
+        assertTrue(true);
+    }
+
+    @Test
+    public void testValue() {
+        System.out.println("value = " + new BCDecimal(16, 1997).intValue() );
+    }
+
+}