Browse Source

improved fraction root

Kajetan Johannes Hammerle 7 năm trước cách đây
mục cha
commit
4852b62ae4

+ 1 - 1
nbproject/private/private.properties

@@ -3,4 +3,4 @@ do.depend=false
 do.jar=true
 javac.debug=true
 javadoc.preview=true
-user.properties.file=/Users/kajetanjohannes/Library/Application Support/NetBeans/8.1/build.properties
+user.properties.file=/home/kajetan/.netbeans/8.1/build.properties

+ 175 - 233
src/me/hammerle/math/Fraction.java

@@ -1,231 +1,202 @@
 package me.hammerle.math;
 
-public class Fraction implements Cloneable, Comparable<Fraction>
+import java.util.TreeSet;
+
+public final class Fraction implements Comparable<Fraction>
 {
-    private long numerator;
-    private long denominator;
+    private final long numerator;
+    private final long denominator;
     
-    public Fraction(long n, long d)
+    public Fraction(long numerator, long denominator)
     {
-        if(d == 0)
+        if(denominator == 0)
         {
             throw new ArithmeticException();
         }
-        else if(d < 0)
+        
+        if(denominator != 1)
+        {
+            long divisor = getGreatestCommonDivisor(numerator, denominator);
+            if(divisor != 1)
+            {
+                denominator /= divisor;
+                numerator /= divisor;
+            }
+        }
+        
+        // short fraction
+        if(denominator < 0)
         {
-            this.denominator = -d;
-            this.numerator = -n;
+            this.denominator = -denominator;
+            this.numerator = -numerator;
         }
         else
         {
-            this.denominator = d;
-            this.numerator = n;
+            this.denominator = denominator;
+            this.numerator = numerator;
         }
-        shortFraction();
     }
     
-    public Fraction(long n)
+    public Fraction(long numerator)
     {
-        this(n, 1);
+        this(numerator, 1);
     }
     
     // -----------------------------------------------------------------------------------
-    // Konstanten
+    // constants, chain fractions
     // ----------------------------------------------------------------------------------- 
     
-    private static final Fraction PI = new Fraction(355, 113);
-    private static final Fraction E = new Fraction(2721, 1001);
+    /*public static final Fraction PI = Fraction.getChainFraction(
+              //3,7,15,1,292,1,1,1,2,1,3,1,14,2,1,1,2,2,2,2,1,84,2,1,1,15,3,13,1,4,2,6,6
+                3,7,15,1,292,1,1,1,2,1,3,1,14,2,1);
+    public static final Fraction E = Fraction.getChainFraction(
+              //2,1,2,1,1,4,1,1,6,1,1,8,1,1,10,1,1,12,1,1,14,1,1,16,...
+                2,1,2,1,1,4,1,1,6,1,1,8,1,1,10,1,1,12,1,1,14);*/
     
-    public static Fraction getPi()
-    {
-        return PI.clone();
-    }
-    
-    public static Fraction getE()
-    {
-        return E.clone();
-    }
-    
-    // -----------------------------------------------------------------------------------
-    // Ausgabe
-    // ----------------------------------------------------------------------------------- 
-
-    public double getDoubleValue()
+    public static Fraction getChainFraction(int... ints)
     {
-        return numerator / (double) denominator;
+        if(ints.length == 1)
+        {
+            return new Fraction(ints[0]);
+        }
+        return new Fraction(ints[0]).add(getChainFractionPart(1, ints));
     }
     
-    public long getLongValue()
+    private static Fraction getChainFractionPart(int index, int... ints)
     {
-        return numerator / denominator;
+        if(index + 1 == ints.length)
+        {
+            return new Fraction(1, ints[index]);
+        }
+        return new Fraction(ints[index]).add(getChainFractionPart(index + 1, ints)).invert();
     }
     
     // -----------------------------------------------------------------------------------
-    // Grundrechnungsarten
+    // basic calculating
     // ----------------------------------------------------------------------------------- 
     
     public Fraction add(Fraction f)
     {
         if(denominator == f.denominator)
         {
-            boolean b = true;
-            while(b)
-            {
-                try
-                {
-                    numerator = Math.addExact(numerator, f.numerator);
-                    b = false;
-                }
-                catch(ArithmeticException ex)
-                {
-                    simplify();
-                    f.simplify();
-                }
-            }
+            return new Fraction(Math.addExact(numerator, f.numerator), denominator);
         }
         else
         {
-            boolean b = true;
-            while(b)
-            {
-                try
-                {
-                    long l = Math.addExact(Math.multiplyExact(numerator, f.denominator), Math.multiplyExact(f.numerator, denominator));
-                    long l2 = Math.multiplyExact(denominator, f.denominator);;
-                    numerator = l;
-                    denominator = l2;
-                    b = false;
-                }
-                catch(ArithmeticException ex)
-                {
-                    simplify();
-                    f.simplify();
-                }
-            }
+            long l = getLeastCommonMultiple(denominator, f.denominator);
+            return new Fraction(Math.addExact(Math.multiplyExact(numerator, l / denominator),
+                    Math.multiplyExact(f.numerator, l / f.denominator)), l);
         }
-        shortFraction();
-        return this;
     }
     
     public Fraction mul(Fraction f)
     {
-        boolean b = true;
-        while(b)
-        {
-            try
-            {
-                long l = Math.multiplyExact(denominator, f.denominator);
-                long l2 = Math.multiplyExact(numerator, f.numerator);
-                denominator = l;
-                numerator = l2;
-                b = false;
-            }
-            catch(ArithmeticException ex)
-            {
-                simplify();
-                f.simplify();
-            }
-        }
-        shortFraction();
-        return this;
-    }
-    
-    private Fraction mul(long f)
-    {
-        boolean b = true;
-        while(b)
-        {
-            try
-            {
-                numerator = Math.multiplyExact(numerator, f);
-                b = false;
-            }
-            catch(ArithmeticException ex)
-            {
-                simplify();
-            }
-        }
-        shortFraction();
-        return this;
+        return new Fraction(Math.multiplyExact(numerator, f.numerator), 
+                Math.multiplyExact(denominator, f.denominator));
     }
     
     public Fraction sub(Fraction f)
     {
-        this.add(f.clone().invertSign());
-        return this;
+        return add(f.invertSign());
     }
     
     public Fraction div(Fraction f)
     {
-        this.mul(f.clone().invert());
-        return this;
+        return mul(f.invert());
     }
     
-    private Fraction div(long f)
+    // -----------------------------------------------------------------------------------
+    // roots, power
+    // ----------------------------------------------------------------------------------- 
+    
+    private static long power(long l, long power)
     {
-        boolean b = true;
-        while(b)
+        long factor = 1;
+        if(l < 0)
         {
-            try
+            factor = (power & 1) == 1 ? -1 : 1;
+            l = -l;
+        }
+        long prod = 1;
+        while(power > 0)
+        {
+            if((power & 1) == 1)
             {
-                denominator = Math.multiplyExact(denominator, f);
-                b = false;
+                prod = Math.multiplyExact(prod, l);
             }
-            catch(ArithmeticException ex)
+            power = power >> 1;
+            l = Math.multiplyExact(l, l);
+        }
+        if(factor == -1)
+        {
+            return -prod;
+        }
+        return prod;
+    }
+    
+    private static long rootOfLong(long l, long root)
+    {
+        if(l == 0 || l == 1)
+        {
+            return l;
+        }
+        try
+        {
+            TreeSet<Long> tree = new TreeSet<>();
+            long currentValue = l >> 1; // taking half as start value
+            long an = currentValue;
+            do
             {
-                simplify();
+                tree.add(currentValue);
+                currentValue = currentValue - (currentValue / root) + an / power(currentValue, root - 1); 
             }
+            while(!tree.contains(currentValue));
+            return currentValue;
         }
-        shortFraction();
-        return this;
+        catch(ArithmeticException ex)
+        {
+            return 0;
+        } 
     }
     
-    // -----------------------------------------------------------------------------------
-    // Radizieren, Potenzieren
-    // ----------------------------------------------------------------------------------- 
-    
-    public Fraction squareRoot()
+    private Fraction root(long root)
     {
-        Fraction f = new Fraction((long) Math.sqrt(this.getDoubleValue()));
-        long a = 0;
-        long b = 0;
-        Fraction f2;
-        int k = 0;
-        while(true)
+        if(root == 1)
+        {
+            return this.copy();
+        }
+        // Getting nice start value
+        Fraction currentValue;
+        Fraction n = new Fraction(root);
+        Fraction an = this.div(n);
+
+        Fraction newFraction = new Fraction(rootOfLong(numerator, root), rootOfLong(denominator, root));
+        root--;
+        try
         {
-            k++;
-            f2 = f.clone();
-            f.mul(f2).add(this).div(f2.mul(2));
-            
-            if((k >= 2 && f.denominator == 1) || f.denominator > 281474976710656l || f.numerator == b)
+            do
             {
-                break;
+                currentValue = newFraction;
+                newFraction = currentValue.sub(currentValue.div(n)).add(an.div(currentValue.power(root)));              
             }
-            
-            b = a;
-            a = f.numerator;
+            while(!newFraction.equals(currentValue));
         }
-        tryExactRoot(f);
-        numerator = f.numerator;
-        denominator = f.denominator;
-        if(numerator < 0)
+        catch(ArithmeticException ex)
         {
-            numerator = -numerator;
         }
-        return this;
+        return newFraction;
     }
     
     public Fraction power(Fraction f)
     {
-        if(f.denominator == 1)
+        if(f.numerator == 0)
         {
-            power(f.numerator);
-            return this;
+            return new Fraction(1);
         }
-        throw new ArithmeticException();
+        return this.power(f.numerator).root(f.denominator);
     }
     
-    public Fraction power(long p)
+    private Fraction power(long p)
     {
         if(p < 0)
         {
@@ -234,7 +205,7 @@ public class Fraction implements Cloneable, Comparable<Fraction>
         }
         else if(p == 1)
         {
-            return this;
+            return this.copy();
         }
         long prodn = 1;
         long prodd = 1;
@@ -244,47 +215,23 @@ public class Fraction implements Cloneable, Comparable<Fraction>
         {
             if((p & 1) == 1)
             {
-                prodn *= n;
-                prodd *= d;
+                prodn = Math.multiplyExact(prodn, n);
+                prodd = Math.multiplyExact(prodd, d);
             }
             p = p >> 1;
-            n *= n;
-            d *= d;
-        }
-        numerator = prodn;
-        denominator = prodd;
-        return this;
-    }
-    
-    private void tryExactRoot(Fraction f)
-    {
-        Fraction f2 = f.clone();
-        if(f2.denominator == 1)
-        {
-            return;
-        }
-        int k = 0;
-        while(f2.denominator > 1)
-        {
-            k++;
-            f2.simplify();
-            if(f2.clone().power(2).equals(this))
-            {
-                f.numerator = f2.numerator;
-                f.denominator = f2.denominator;
-                return;
-            }
+            n = Math.multiplyExact(n, n);
+            d = Math.multiplyExact(d, d);
         }
+        return new Fraction(prodn, prodd);
     }
     
     // -----------------------------------------------------------------------------------
-    // Invertieren
+    // inverting
     // ----------------------------------------------------------------------------------- 
     
     public Fraction invertSign()
     {
-        numerator = -numerator;
-        return this;
+        return new Fraction(-numerator, denominator);
     }
     
     public Fraction invert()
@@ -293,50 +240,43 @@ public class Fraction implements Cloneable, Comparable<Fraction>
         {
             throw new ArithmeticException();
         }
-        long helper = numerator;
-        if(helper < 0)
+        else if(numerator < 0)
         {
-            numerator = -denominator;
-            denominator = -helper;
+            return new Fraction(-denominator, -numerator);
         }
-        else
-        {
-            numerator = denominator;
-            denominator = helper;
-        }
-        return this;
+        return new Fraction(denominator, numerator);
     }
     
     // -----------------------------------------------------------------------------------
-    // Winkelfunktionen
+    // trigonometric
     // ----------------------------------------------------------------------------------- 
     
     public Fraction sin()
     {
-        int factor = 1;
+        /*int factor = 1;
         if(numerator < 0)
         {
             factor = -1;
             numerator = -numerator;
         }
         
-        Fraction pi = getPi().mul(2);
+        Fraction pi = Fraction.PI.mul(2);
         while(this.compareTo(pi) >= 0)
         {
             this.sub(pi);
         }
         
-        if(isBetween(new Fraction(0), getPi().div(2)))
+        if(isBetween(new Fraction(0), Fraction.PI.div(2)))
         {
             // Nichts
         }
-        else if(isBetween(getPi().div(2), getPi()))
+        else if(isBetween(Fraction.PI.div(2), Fraction.PI))
         {
-            this.invertSign().add(getPi());
+            this.invertSign().add(Fraction.PI);
         }
-        else if(this.compareTo(getPi()) >= 0)
+        else if(this.compareTo(Fraction.PI) >= 0)
         {
-            this.sub(getPi());
+            this.sub(Fraction.PI);
             factor = -factor;
         }
         
@@ -364,55 +304,35 @@ public class Fraction implements Cloneable, Comparable<Fraction>
             }
         }
         numerator = factor * result.numerator;
-        denominator = result.denominator;
+        denominator = result.denominator;*/
         return this;
     }
     
     public Fraction cos()
     {
-        this.add(getPi().div(2));
-        return sin();
+        return this;
+        //return add(Fraction.PI.div(new Fraction(2))).sin();
     }
     
     public Fraction tan()
     {
-        sin();
-        div(this.clone().cos());
-        return this;
+        return sin().div(cos());
     }
     
     // -----------------------------------------------------------------------------------
-    // Vereinfachung
+    // simplifying
     // ----------------------------------------------------------------------------------- 
     
-    private void shortFraction()
-    {
-        if(denominator == 1)
-        {
-            return;
-        }
-        long divisor = getGreatestCommonDivisor(numerator, denominator);
-        if(divisor != 1)
-        {
-            denominator /= divisor;
-            numerator /= divisor;
-        }
-    }
-    
-    private void simplify()
+    /*private void simplify()
     {
         if(denominator == 1)
         {
-            //denominator += 2;
-            System.out.println(this);
             throw new ArithmeticException();
         }
         denominator = (denominator & 1) == 1 ? denominator - 1 : denominator;
         numerator = (numerator & 1) == 1 ? numerator - 1 : numerator;
-        //System.out.println(denominator + "  WUSI  " + numerator);
         shortFraction();
-        //System.out.println(denominator + "  WUSI  " + numerator);
-    }
+    }*/
     
     private long getGreatestCommonDivisor(long i, long n)
     {
@@ -445,18 +365,36 @@ public class Fraction implements Cloneable, Comparable<Fraction>
         }
     }
     
+    private long getLeastCommonMultiple(long i, long n)
+    {
+        return Math.abs(Math.multiplyExact(i, n)) / getGreatestCommonDivisor(i, n);
+    }
+    
     // -----------------------------------------------------------------------------------
-    // Grundobjektcode
+    // basic stuff
     // ----------------------------------------------------------------------------------- 
     
+    public double getDouble()
+    {
+        return numerator / (double) denominator;
+    }
+    
+    public long getLong()
+    {
+        return Math.round(numerator / (double) denominator);
+    }
+    
     @Override
     public String toString() 
     {
+        if(denominator == 1)
+        {
+            return String.valueOf(numerator);
+        }
         return numerator + " / " + denominator;
     }
 
-    @Override
-    public Fraction clone()
+    public Fraction copy()
     {
         return new Fraction(numerator, denominator);
     }
@@ -464,7 +402,11 @@ public class Fraction implements Cloneable, Comparable<Fraction>
     @Override
     public boolean equals(Object o) 
     {
-        if(!(o instanceof Fraction))
+        if(o == null)
+        {
+            return false;
+        }
+        else if(o.getClass() != Fraction.class)
         {
             return false;
         }
@@ -494,7 +436,7 @@ public class Fraction implements Cloneable, Comparable<Fraction>
         }
         else
         {
-            long i = f.clone().sub(this).numerator;
+            long i = f.sub(this).numerator;
             if(i == 0)
             {
                 return 0;

+ 10 - 12
src/me/hammerle/snuviscript/SnuviScript.java

@@ -1,18 +1,12 @@
 package me.hammerle.snuviscript;
 
-import me.hammerle.code.ISnuviLogger;
-import me.hammerle.code.Script;
-import me.hammerle.code.SnuviParser;
-import me.hammerle.exceptions.SnuviException;
-import me.hammerle.code.ISnuviScheduler;
-import me.hammerle.exceptions.PreScriptException;
 import me.hammerle.math.Fraction;
 
 public class SnuviScript 
 {
     public static void main(String[] args) 
     {
-        ISnuviLogger logger = new ISnuviLogger() 
+        /*ISnuviLogger logger = new ISnuviLogger() 
         {
             @Override
             public void printException(SnuviException ex, Script s) 
@@ -73,7 +67,7 @@ public class SnuviScript
         });
         parser.registerConsumer("debug", (o, sc) -> System.out.println(o[0]));
         parser.registerFunction("ggv", (o, sc) -> o[0]);
-        parser.registerFunction("read.item", (o, sc) -> o[0]);
+        parser.registerFunction("read.item", (o, sc) -> o[0]);*/
         
         /*StringBuilder sb = new StringBuilder("wusi = 1;\n");
         int counter = 0;
@@ -104,9 +98,13 @@ public class SnuviScript
         //parser.startScript(Script.class, "test", sb.toString(), true);
         //parser.startScript(Script.class, "test", s, true);
         //parser.getScript(0).runCode();
-        
-        //Fraction f = new Fraction(2);
-        //Fraction f2 = new Fraction(2, 6);
-        System.out.println(Fraction.getE());
+
+        Fraction f = new Fraction(1, 3);
+        Fraction f2 = new Fraction(2, 3);
+        System.out.println(
+                f.power(new Fraction(2))
+                        .add(f2.power(new Fraction(2)))
+                        .add(f2.power(new Fraction(2)))
+                        .power(new Fraction(1, 2)));
     }   
 }