Explorar o código

BCDecimal - add

Meta.Unsafe - aplicable to constructors
Ranides Atterwim %!s(int64=12) %!d(string=hai) anos
pai
achega
c8730a2aa0

+ 27 - 27
src/main/java/net/ranides/assira/annotations/Meta.java

@@ -17,10 +17,10 @@ import java.util.ServiceLoader;
 
 /**
  * Adnotacje dodające do kodu informacje o znaczeniu semantycznym.
- * Z niektórych adnotacji bliblioteka może intensywnie korzystać w runtime, 
+ * Z niektórych adnotacji bliblioteka może intensywnie korzystać w runtime,
  * inne są tylko podpowiedziami dla programistów i/lub narzędzi sprawdzających
  * kod.
- * 
+ *
  * @author ranides
  */
 public final class Meta {
@@ -28,37 +28,37 @@ public final class Meta {
     private Meta() { }
 
     /**
-     * W jaki sposób kod jest generowany. 
+     * W jaki sposób kod jest generowany.
      */
     public enum GenerationStrategy {
         /** Automatycznie, wstawiany przed wywołaniem metody */
-        BEFORE, 
-        
+        BEFORE,
+
         /** Automatycznie, wstawiany po wywołaniu metody */
-        AFTER, 
-        
+        AFTER,
+
         /** Automatycznie, zastępuje istniejącą implementację metody */
-        REPLACE, 
-        
+        REPLACE,
+
         /** Programista użył w kodzie metody jawnie generatora */
         MANUAL
     }
-    
+
     /**
      * W jaki sposób wywołanie metody ma być synchronizowane z systemem
      */
     public enum SyncStrategy {
-        
+
         /** Brak synchronizacji */
         NONE,
-        
+
         /** Wywołanie w "event dispatching thread" biblioteki AWT */
         AWT,
-        
+
         /** Wywołanie w "event dispatching thread" biblioteki AWT i oczekiwanie na zakończenie */
         AWT_WAIT
     }
-    
+
     /**
      * Element zamrożony, gwarantowany brak zmian w API.
      */
@@ -71,13 +71,13 @@ public final class Meta {
          * @return default = 1
          */
         int version() default 1;
-        
+
         /**
          * Numer wersji podczas której zamrożono wskazane API (minor).
          * @return default = 0
          */
         int minor() default 0;
-        
+
         /**
          * Numer rewizji podczas której zamrożono wskazane API (np svn).
          * @return default = 0
@@ -133,13 +133,13 @@ public final class Meta {
     @Target({CONSTRUCTOR,METHOD})
     @Documented
     public static @interface Generated {
-        
+
         /**
          * Symboliczna nazwa użytego generatora
          * @return default = ""
          */
         String generator() default "";
-        
+
         /**
          * W jaki sposób  kod jest integrowany z istniejącą implementacją metody
          * @return default = {@code GenerationStrategy.MANUAL}
@@ -178,15 +178,15 @@ public final class Meta {
          * @return default = ""
          */
         String value() default "";
-        
+
         /**
          * Czy obsługa ma być uruchomiona w wątku AWT
          * @return default = {@link SyncStrategy#NONE}
          */
         SyncStrategy sync() default SyncStrategy.NONE;
-        
+
     }
-    
+
     /**
      * Metoda obsługi wyjątku. Przeznaczona tylko jako wywołanie zwrotne, a nie
      * bezpośrednie.
@@ -199,9 +199,9 @@ public final class Meta {
 
     /**
      * <p>
-     * Jeśli funkcja z dowolnego powodu wymaga szczególnej ostrożności, 
+     * Jeśli funkcja z dowolnego powodu wymaga szczególnej ostrożności,
      * to powinna tym być oznaczona. Przykłady zachowań:</p>
-     * <ul> 
+     * <ul>
      *      <li>funkcja wykonuje rzutowania "unchecked"</li>
      *      <li>"undefined behaviour" w niektórych warunkach</li>
      *      <li>"expose internal array"</li>
@@ -210,15 +210,15 @@ public final class Meta {
      * </ul>
      */
     @Retention(RUNTIME)
-    @Target({TYPE, METHOD})
+    @Target({TYPE, METHOD, CONSTRUCTOR})
     @Documented
     public @interface Unsafe {
     }
 
     /**
      * Adnotowana klasa jest implementacją interfejsu obsługiwanego za pomocą
-     * {@link ServiceLoader}. Powinien zostać wygenerowany odpowiedni wpis do 
-     * manifestu pliku JAR. 
+     * {@link ServiceLoader}. Powinien zostać wygenerowany odpowiedni wpis do
+     * manifestu pliku JAR.
      */
     @Retention(SOURCE)
     @Documented
@@ -227,7 +227,7 @@ public final class Meta {
         /**
          * Jeśli klasa implementuje więcej niż jeden interfejs, to należy wskazać
          * interfejs, która powinien zostać wyeksportowany w manifeście.
-         * @return 
+         * @return
          */
         Class value() default void.class;
     }

+ 74 - 33
src/main/java/net/ranides/assira/math/BCDecimal.java

@@ -7,7 +7,10 @@
 
 package net.ranides.assira.math;
 
+import java.math.BigDecimal;
 import java.util.Arrays;
+import net.ranides.assira.annotations.Meta;
+import net.ranides.assira.collection.ArrayUtils;
 import net.ranides.assira.text.Strings;
 
 /**
@@ -18,8 +21,8 @@ public class BCDecimal extends Number implements Comparable<BCDecimal> {
 
     private final byte[] data;
 
-    public BCDecimal(long value) {
-        this(32, value);
+    public BCDecimal(int size) {
+        this.data = new byte[floor2(size)];
     }
 
     public BCDecimal(int size, long value) {
@@ -45,8 +48,20 @@ public class BCDecimal extends Number implements Comparable<BCDecimal> {
         }
     }
 
-    public BCDecimal(Number value) {
-        throw new UnsupportedOperationException("Not supported yet.");
+    public BCDecimal(BCDecimal value) {
+        this.data = ArrayUtils.arraycopy(value.data);
+    }
+
+    public static BCDecimal valueOf(Number value) {
+        assert value != null;
+
+        if(value instanceof BCDecimal) {
+            return new BCDecimal((BCDecimal)value);
+        }
+        if(value instanceof Long || value instanceof Integer || value instanceof Short || value instanceof Byte) {
+            return new BCDecimal( 32, value.longValue() );
+        }
+        throw new UnsupportedOperationException("Not supported type: " + value.getClass());
     }
 
     @Override
@@ -79,6 +94,10 @@ public class BCDecimal extends Number implements Comparable<BCDecimal> {
         return longValue();
     }
 
+    public BigDecimal bigValue() {
+        return new BigDecimal(toString());
+    }
+
     @Override
     public int compareTo(BCDecimal value) {
         int n = Math.max(size(), value.size());
@@ -105,7 +124,11 @@ public class BCDecimal extends Number implements Comparable<BCDecimal> {
             return 0 == compareTo( (BCDecimal)object );
         }
         if( object instanceof Number) {
-            return 0 == new BCDecimal((Number)object).compareTo(this);
+            try {
+                return 0 == BCDecimal.valueOf((Number)object).compareTo(this);
+            } catch(UnsupportedOperationException cause) {
+                return false;
+            }
         }
         return false;
     }
@@ -127,8 +150,53 @@ public class BCDecimal extends Number implements Comparable<BCDecimal> {
         return builder.toString();
     }
 
+    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 final 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 final int size() {
+        return data.length * 2;
+    }
+
     public BCDecimal add(BCDecimal value) {
-        throw new UnsupportedOperationException("Not supported yet.");
+        return add(this, value);
+    }
+
+    public static BCDecimal add(BCDecimal number1, BCDecimal number2) {
+        if( number1.size() < number2.size() ) {
+            return add(number2, number1);
+        }
+        BCDecimal ret = new BCDecimal(number1.size());
+        int cv = 0;
+        for(int i=0, n=number2.size(); i<n; i++) {
+            int v = number1.at(i) + number2.at(i) + cv;
+            ret.at(i, v % 10);
+            cv = v / 10;
+        }
+        if(cv > 0) {
+            if( ret.size() == number2.size() ) {
+                throw new ArithmeticException("BCDecimal: value is too large.");
+            }
+            ret.at(number2.size(), cv);
+        }
+        return ret;
     }
 
     public BCDecimal sub(BCDecimal value) {
@@ -171,31 +239,4 @@ public class BCDecimal extends Number implements Comparable<BCDecimal> {
         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;
-    }
-
-
-
 }

+ 11 - 1
src/test/java/net/ranides/assira/math/BCDecimalTest.java

@@ -39,7 +39,17 @@ public class BCDecimalTest {
 
     @Test
     public void testValue() {
-        System.out.println("value = " + new BCDecimal(16, 1997).intValue() );
+        assertEquals(1997, new BCDecimal(16, 1997).intValue() );
+    }
+
+    @Test
+    public void testAdd() {
+        assertEquals(858, BCDecimal.valueOf(132).add(BCDecimal.valueOf(726)).intValue() );
+        assertEquals(158, BCDecimal.valueOf(132).add(BCDecimal.valueOf(26)).intValue() );
+        assertEquals(142, BCDecimal.valueOf(134).add(BCDecimal.valueOf(8)).intValue() );
+        assertEquals(202, BCDecimal.valueOf(134).add(BCDecimal.valueOf(68)).intValue() );
+        assertEquals(1102, BCDecimal.valueOf(134).add(BCDecimal.valueOf(968)).intValue() );
+
     }
 
 }