Revision: 4327
          http://vexi.svn.sourceforge.net/vexi/?rev=4327&view=rev
Author:   mkpg2
Date:     2012-01-16 14:41:37 +0000 (Mon, 16 Jan 2012)
Log Message:
-----------
New class, Rational. Unlimited precision rational values.

Added Paths:
-----------
    trunk/org.vexi-library.value/src/main/java/org/vexi/value/Rational.java
    trunk/org.vexi-library.value/src/poke/
    trunk/org.vexi-library.value/src/poke/java/
    trunk/org.vexi-library.value/src/poke/java/poke/
    trunk/org.vexi-library.value/src/poke/java/poke/PokeDivide.java
    trunk/org.vexi-library.value/src/poke/java/poke/PokeDoubleBits.java
    trunk/org.vexi-library.value/src/test/java/org/vexi/value/TestRational.java

Property Changed:
----------------
    trunk/org.vexi-library.value/


Property changes on: trunk/org.vexi-library.value
___________________________________________________________________
Modified: svn:ignore
   - 
.configuration

gen

.classpath

.project

.settings

   + 
.configuration

gen

.classpath

.project

.settings

build

release


Added: trunk/org.vexi-library.value/src/main/java/org/vexi/value/Rational.java
===================================================================
--- trunk/org.vexi-library.value/src/main/java/org/vexi/value/Rational.java     
                        (rev 0)
+++ trunk/org.vexi-library.value/src/main/java/org/vexi/value/Rational.java     
2012-01-16 14:41:37 UTC (rev 4327)
@@ -0,0 +1,286 @@
+package org.vexi.value;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Rational extends Number implements Comparable {
+    static final public Rational INFINITY = new Rational(BigInteger.ONE, 
BigInteger.ZERO);
+    static final public Rational INFINITY_NEG = new 
Rational(BigInteger.valueOf(-1), BigInteger.ZERO);
+    static final public Rational NAN = new Rational(BigInteger.ZERO, 
BigInteger.ZERO);
+    static final public Rational ZERO = new Rational(BigInteger.ZERO, 
BigInteger.ONE);
+    static final public Rational ONE = new Rational(BigInteger.ONE, 
BigInteger.ONE);
+
+    static private Rational canonical(BigInteger numerator, BigInteger 
denominator, boolean checkGcd) {
+        if (denominator.signum() == 0) {
+            if (numerator.signum() == 0) {
+                return NAN;
+            }else if(numerator.signum() >0){
+                return INFINITY;
+            }else{
+                return INFINITY_NEG;
+            }
+        }
+        if (numerator.signum() == 0) {
+            return ZERO;
+        }
+        if (denominator.signum() < 0) {
+            numerator = numerator.negate();
+            denominator = denominator.negate();
+        }
+        if (checkGcd) {
+            BigInteger gcd = numerator.gcd(denominator);
+            if (!gcd.equals(BigInteger.ONE)) {
+                numerator = numerator.divide(gcd);
+                denominator = denominator.divide(gcd);
+            }
+        }
+        return new Rational(numerator, denominator);
+    }
+    
+    static public Rational valueOf(long n) {
+        return canonical(BigInteger.valueOf(n), BigInteger.ONE, false);
+    }
+    
+    static public Rational valueOf(BigInteger n) {
+        return canonical(n, BigInteger.ONE, false);
+    }
+
+
+    static public Rational valueOf(long numerator, long denominator) {
+        return canonical(new BigInteger("" + numerator), new BigInteger("" + 
denominator), true);
+    }
+
+    static public Rational valueOf(BigInteger numerator, BigInteger 
denominator) {
+        return canonical(numerator, denominator, true);
+    }
+    
+    static public Rational valueOf(BigDecimal n) {
+        return valueOf(n.unscaledValue(), BigInteger.TEN.pow(n.scale()));
+    }
+
+    static final private BigInteger BI_TWO = BigInteger.valueOf(2);
+    static public Rational valueOf(double d) {
+        if(0.0d==d){
+            return ZERO;
+        }else if(Double.isNaN(d)){
+            return NAN;
+        }else if(Double.isInfinite(d)) {
+            if(d>0) return INFINITY;
+            else return INFINITY_NEG;
+        } else {
+            long bits = Double.doubleToLongBits(d);
+
+            int  s = (((bits >> 63) == 0) ? 1 : -1);
+            int  e = (int)((bits >> 52) & 0x7ffL);
+            long m = ((e == 0) ?
+                    ((bits & 0xfffffffffffffL) << 1)
+                    : ((bits & 0xfffffffffffffL) | 0x10000000000000L));
+
+            e -= 1075;
+            m  = m * s;
+
+            BigInteger num = BigInteger.valueOf(m);
+            BigInteger den = ((0 == e)?
+                    BigInteger.ONE
+                    : BI_TWO.shiftLeft(Math.abs(e)-1));
+
+            if (0 <= e) {
+                return valueOf(num.multiply(den), BigInteger.ONE);
+            } else {
+                return valueOf(num, den);
+            }
+        }
+    }
+    
+    static Pattern p = 
Pattern.compile("(-?\\d+)(?:.(\\d+)?)?0*(?:e(-?\\d+))?");
+    static public Rational tryParse(String s) {
+        Matcher m = p.matcher(s);
+        if (!m.matches()) {
+            return null;
+        }
+
+        // this translates 23.123e5 to 25,123 / 1000 * 10^5 = 2,512,300 / 1 
(GCD)
+        String whole = m.group(1);
+        String decimal = m.group(2);
+        String exponent = m.group(3);
+        String n = whole;
+
+        // 23.123 => 23123
+        if (decimal != null) {
+            n += decimal;
+        }
+        BigInteger numerator = new BigInteger(n);
+
+        // exponent is an int because BigInteger.pow() takes an int argument
+        // it gets more difficult if exponent needs to be outside {-2 
billion,2 billion}
+        int exp = exponent == null ? 0 : Integer.parseInt(exponent);
+        int decimalPlaces = decimal == null ? 0 : decimal.length();
+        exp -= decimalPlaces;
+        BigInteger denominator;
+        if (exp < 0) {
+            denominator = BigInteger.TEN.pow(-exp);
+        } else {
+            numerator = numerator.multiply(BigInteger.TEN.pow(exp));
+            denominator = BigInteger.ONE;
+        }
+
+        // done
+        return canonical(numerator, denominator, true);
+    }
+
+    
+    
+    
+    final private BigInteger numerator, denominator;
+
+    static int count;
+    private Rational(BigInteger numerator, BigInteger denominator) {
+        this.numerator = numerator;
+        this.denominator = denominator;
+    }
+
+    // Comparable
+    public int compareTo(Object o) {
+        // note: this is a bit of cheat, relying on BigInteger.compareTo() 
returning
+        // -1, 0 or 1.  For the more general contract of compareTo(), you'd 
need to do
+        // more checking
+        Rational r = (Rational)o;
+        if (numerator.signum() != r.numerator.signum()) {
+            return numerator.signum() - r.numerator.signum();
+        } else {
+            // oddly BigInteger has gcd() but no lcm()
+            BigInteger i1 = numerator.multiply(r.denominator);
+            BigInteger i2 = r.numerator.multiply(denominator);
+            return i1.compareTo(i2); // expensive!
+        }
+    }
+
+    public Rational add(Rational o) {
+        if (isNaN() || o.isNaN()) return NAN;
+        if (o.numerator.signum() == 0) {
+            return this;
+        } else if (numerator.signum() == 0) {
+            return o;
+        } else if (denominator.equals(o.denominator)) {
+            return Rational.valueOf(numerator.add(o.numerator), denominator);
+        } else {
+            return 
canonical(numerator.multiply(o.denominator).add(o.numerator.multiply(denominator)),
 denominator.multiply(o.denominator), true);
+        }
+    }
+
+
+    public Rational multiply(Rational o) {
+//        if (isNaN() || o.isNaN()) return NAN;
+        if (numerator.signum() == 0 || o.numerator.signum( )== 0) {
+            if(denominator.signum()==0 || o.denominator.signum()==0)
+                return NAN;
+            return ZERO;
+        } else if (numerator.equals(o.denominator)) {
+            return canonical(o.numerator, denominator, true);
+        } else if (o.numerator.equals(denominator)) {
+            return canonical(numerator, o.denominator, true);
+        } else if (numerator.negate().equals(o.denominator)) {
+            return canonical(o.numerator.negate(), denominator, true);
+        } else if (o.numerator.negate().equals(denominator)) {
+            return canonical(numerator.negate(), o.denominator, true);
+        } else {
+            return canonical(numerator.multiply(o.numerator), 
denominator.multiply(o.denominator), true);
+        }
+    }
+
+    public BigInteger getNumerator() { return numerator; }
+    public BigInteger getDenominator() { return denominator; }
+    public boolean isInt32() { return isInteger() && 
getNumerator().bitLength()<32; }
+    public boolean isInteger() { return numerator.signum() == 0 || 
denominator.equals(BigInteger.ONE); }
+    public boolean isNaN() { return numerator.signum()==0 && 
denominator.signum()==0; }
+    public boolean isFinite() { return denominator.signum()!=0; }
+
+    public Rational negate() { return new Rational(numerator.negate(), 
denominator); }
+    public Rational invert() { return canonical(denominator, numerator, 
false); }
+    public Rational abs() { return numerator.signum() < 0 ? negate() : this; }
+    public Rational pow(int exp) { return canonical(numerator.pow(exp), 
denominator.pow(exp), true); }
+    public Rational subtract(Rational o) { return add(o.negate()); }
+    public Rational divide(Rational o) { 
+        return multiply(o.invert());
+    }
+    
+    public Rational mod(Rational o){ 
+        BigInteger left = numerator.multiply(o.denominator);
+        BigInteger right = o.numerator.multiply(denominator);
+        BigInteger r = left.mod(right);
+        if(numerator.signum()<0 && !BigInteger.ZERO.equals(left)){
+            r = right.abs().subtract(r);
+        }
+        return valueOf(r, denominator.multiply(o.denominator));
+    }
+    public Rational min(Rational o) { return compareTo(o) <= 0 ? this : o; }
+    public Rational max(Rational o) { return compareTo(o) >= 0 ? this : o; }
+
+    public Rational ceil() { 
+        BigInteger[] ii = numerator.divideAndRemainder(denominator);
+        BigInteger result = ii[0];
+        BigInteger remainder = ii[1];
+        if(remainder.signum()==0) return valueOf(result);
+        return valueOf(result.add(BigInteger.ONE));
+    }
+    public Rational floor() { 
+        BigInteger[] ii = numerator.divideAndRemainder(denominator);
+        BigInteger result = ii[0];
+        BigInteger remainder = ii[1];
+        if(remainder.signum()==0) return valueOf(result);
+        return valueOf(result.subtract(BigInteger.ONE));
+    }
+    public Rational round() {
+        BigInteger[] ii = numerator.divideAndRemainder(denominator);
+        BigInteger result = ii[0];
+        BigInteger remainder = ii[1];
+        if(remainder.multiply(BI_TWO).compareTo(denominator)>=0){
+            result.add(BigInteger.ONE);
+        }
+        return valueOf(result);
+    }
+    
+    public BigDecimal toBigDecimal(int scale, RoundingMode roundingMode) {
+        return isInteger() ? new BigDecimal(numerator) : new 
BigDecimal(numerator).divide(new BigDecimal(denominator), scale, roundingMode);
+    }
+
+    // Number
+    public int intValue() { return isInteger() ? numerator.intValue() : 
numerator.divide(denominator).intValue(); }
+    public long longValue() { return isInteger() ? numerator.longValue() : 
numerator.divide(denominator).longValue(); }
+    public float floatValue() { return (float)doubleValue(); }
+    public double doubleValue() { return isInteger() ? numerator.doubleValue() 
: numerator.doubleValue() / denominator.doubleValue(); }
+
+    public String toString() {
+        if(!isFinite()){
+            if(numerator.signum()==0) return "NaN";
+            else if(numerator.signum()>0) return "Infinity";
+            else return "-Infinity";
+        }
+        return isInteger() ? numerator+"" : numerator+" / "+denominator; 
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Rational that = (Rational) o;
+
+        if (denominator != null ? !denominator.equals(that.denominator) : 
that.denominator != null) return false;
+        if (numerator != null ? !numerator.equals(that.numerator) : 
that.numerator != null) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result = numerator != null ? numerator.hashCode() : 0;
+        result = 31 * result + (denominator != null ? denominator.hashCode() : 
0);
+        return result;
+    }
+
+
+
+    
+}
+


Property changes on: 
trunk/org.vexi-library.value/src/main/java/org/vexi/value/Rational.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/org.vexi-library.value/src/poke/java/poke/PokeDivide.java
===================================================================
--- trunk/org.vexi-library.value/src/poke/java/poke/PokeDivide.java             
                (rev 0)
+++ trunk/org.vexi-library.value/src/poke/java/poke/PokeDivide.java     
2012-01-16 14:41:37 UTC (rev 4327)
@@ -0,0 +1,10 @@
+package poke;
+
+public class PokeDivide {
+    static public void main(String[] args) {
+        System.err.println(0.123456d%0.01);
+//        System.err.println(5/4);
+//        System.err.println(Math.floor(-5d/4));
+        
+    }
+}


Property changes on: 
trunk/org.vexi-library.value/src/poke/java/poke/PokeDivide.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: trunk/org.vexi-library.value/src/poke/java/poke/PokeDoubleBits.java
===================================================================
--- trunk/org.vexi-library.value/src/poke/java/poke/PokeDoubleBits.java         
                (rev 0)
+++ trunk/org.vexi-library.value/src/poke/java/poke/PokeDoubleBits.java 
2012-01-16 14:41:37 UTC (rev 4327)
@@ -0,0 +1,59 @@
+package poke;
+
+import java.math.BigDecimal;
+
+public class PokeDoubleBits {
+    
+    static class DoubleParts{
+        boolean negative;
+        int exponent;
+        long mantissa;
+        public String toDecimalString() {
+            BigDecimal bd = new 
BigDecimal(mantissa).divide(BigDecimal.valueOf(0x0010000000000000L));
+            return ((negative)?"-":"+")+bd+"*2^"+exponent;
+        }
+        public String toString() {
+            return 
((negative)?"-":"+")+"1."+Long.toBinaryString((mantissa&0x000fffffffffffffL))+"*2^"+exponent;
+        }
+    }
+
+    static public DoubleParts deconstructDouble(double d){
+        
+        long bits     = Double.doubleToLongBits(d);
+        long sign     = bits & 0x8000000000000000L;
+        int exponent = (int)(((bits & 0x7ff0000000000000L)>>52)-1023);
+        
+        long mantissa = (bits & 0x000fffffffffffffL) | 0x0010000000000000L; // 
implicit bit
+        DoubleParts r = new DoubleParts();
+        r.negative = sign>>63==1;
+        r.exponent = exponent;
+        r.mantissa = mantissa;
+        return r;
+    }
+    
+    static public double constructDouble(DoubleParts ps){ return 
constructDouble(ps.negative, ps.mantissa, ps.exponent); }
+    static public double constructDouble(boolean negative, long mantissa, int 
exponent){
+        if(exponent>=0x7ff)              throw new Error("Expronent too large: 
"+mantissa);
+        if(mantissa>0x001fffffffffffffL) throw new Error("Mantissa too large: 
"+mantissa);
+        long bits = ((long)exponent+1023)<<52 | (mantissa & 
0x000fffffffffffffL);
+        if(negative) bits |=0x7000000000000000L;
+        return Double.longBitsToDouble(bits);
+    }
+    
+    static public void assertDouble(double d){
+        DoubleParts ps = deconstructDouble(d);
+        double d2 = constructDouble(ps);
+        System.err.println(d);
+        System.err.println(ps.toString());
+        System.err.println(d2);
+        if(d!=d2) throw new Error(d+"!="+d2);
+    }
+    
+    
+    static public void main(String[] args) {
+        assertDouble(2.25);
+        assertDouble(4.125);
+    }
+
+}
+


Property changes on: 
trunk/org.vexi-library.value/src/poke/java/poke/PokeDoubleBits.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Added: 
trunk/org.vexi-library.value/src/test/java/org/vexi/value/TestRational.java
===================================================================
--- trunk/org.vexi-library.value/src/test/java/org/vexi/value/TestRational.java 
                        (rev 0)
+++ trunk/org.vexi-library.value/src/test/java/org/vexi/value/TestRational.java 
2012-01-16 14:41:37 UTC (rev 4327)
@@ -0,0 +1,21 @@
+package org.vexi.value;
+
+public class TestRational {
+    static public void dump(String name, Rational r) {
+        System.out.println(name+" "+r);
+        System.out.println();
+    }
+    
+    static public void main(String args[]) {
+        Rational r1 = Rational.valueOf(31400);
+        Rational r2 = Rational.valueOf(111, 7);
+        dump("r1", r1);
+        dump("r2", r2);
+        dump("r1 + r2", r1.add(r2));
+        dump("r1 - r2", r1.subtract(r2));
+        dump("r1 * r2", r1.multiply(r2));
+        dump("r1 / r2", r1.divide(r2));
+        dump("r2 ^ 2", r2.pow(2));
+    }
+
+}


Property changes on: 
trunk/org.vexi-library.value/src/test/java/org/vexi/value/TestRational.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
RSA(R) Conference 2012
Mar 27 - Feb 2
Save $400 by Jan. 27
Register now!
http://p.sf.net/sfu/rsa-sfdev2dev2
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to