package org.das2.datum; /** * Represent the ratio of two integers. * @author jbf */ public class Ratio { int numerator; int denominator; public Ratio( int i ) { this.numerator= i; this.denominator= 1; } public static final Ratio one= new Ratio(1); public static final Ratio zero= new Ratio(0); public Ratio( int n, int d ) { if ( n % d == 0 ) { n= n/d; d=1; } //TODO: GCD this.numerator= n; this.denominator= d; } /** * return the Greatest Common Divisor (GCD) of the two numbers. * @param a the first number * @param d the second number, slightly more efficient if this is smaller. * @return the divisor. */ public static long gcd( long a, long d ) { if ( a0 ) { d= r; r= a % d; } return d; } /** * parse aaa.bbbbEcc into Ratio. * @param s * @return */ public static Ratio create( String s ) { s= s.toLowerCase(); int ipt= s.indexOf("."); int ien= s.length(); int ie= s.lastIndexOf("e"); int exp=0; if ( ie>-1 ) { exp= Integer.parseInt(s.substring(ie+1) ); if ( ipt==-1 ) ipt= ie; } else { if ( ipt==-1 ) ipt= s.length(); } int n; if ( ipt>0 ) { n= Integer.parseInt(s.substring(0,ipt) ); } else { n= 0; } if ( ipt==ie ) { if ( exp>0 ) { n=n*(int)Math.pow(10,exp); } else if ( exp<0 ) { throw new IllegalArgumentException("exponent must be positive, use rational Number"); } return new Ratio(n); } else { int d; int np; if ( ipt+10 ) { n=n*10^exp; return new Ratio( n, d ); } else { return new Ratio( n, d ); } } } public static Ratio create( double number ) { if ( number==0 ) { return Ratio.zero; } if ( Double.isNaN(number) ) { throw new IllegalArgumentException("NaN is not supported"); } // Code below doesn't work for 0 and NaN - just check before long bits = Double.doubleToLongBits(number); long sign = bits >>> 63; long exponent = ((bits >>> 52) ^ (sign << 11)) - 1023; long fraction = bits << 12; // bits are "reversed" but that's not a problem long a = 1L; long b = 1L; for (int i = 63; i >= 33; i--) { a = a * 2 + ((fraction >>> i) & 1); b *= 2; } if (exponent > 0) { a *= 1 << exponent; } else { b *= 1 << -exponent; } if (sign == 1) { a *= -1; } long gcd= gcd( a,b ); if ( gcd>1 ) { a= a/gcd; b= b/gcd; } if ( aInteger.MAX_VALUE ) { return create( Math.round( number/1000 ) * 1000 ); // kludge } else if ( bInteger.MAX_VALUE ) { return create( Math.round( number/1000 ) * 1000 ); // kludge } return new Ratio( (int)a,(int)b ); } public Ratio pow( Ratio r ) { if ( r.denominator==1 ) { return new Ratio( (int)Math.pow( this.numerator, r.numerator ), (int)Math.pow( this.denominator, r.numerator ) ); } else { return Ratio.create( Math.pow( this.numerator, r.doubleValue() ) / Math.pow( this.denominator, r.doubleValue() ) ); } } public Ratio sqrt( ) { return Ratio.create( Math.sqrt(numerator)/Math.sqrt(denominator) ); } public Ratio multiply( Ratio r ) { return new Ratio( this.numerator * r.numerator, this.denominator * r.denominator ); } public Ratio divide( Ratio r ) { return new Ratio( this.numerator / r.numerator, this.denominator / r.denominator ); //TODO: check this } public Ratio add( Ratio r ) { return new Ratio( this.numerator * r.denominator + r.numerator * this.denominator, this.denominator * r.denominator ); } public Ratio subtract( Ratio r ) { return new Ratio( this.numerator * r.denominator - r.numerator * this.denominator, this.denominator * r.denominator ); } public boolean isZero() { return this.numerator==0; } public boolean isOne() { return this.numerator==this.denominator; } @Override public int hashCode() { return Double.valueOf(numerator/(double)denominator).hashCode(); } @Override public boolean equals( Object o ) { if ( o instanceof Ratio ) { Ratio r= (Ratio)o; return r.numerator * this.denominator == r.denominator * this.numerator; } else { return super.equals(o); } } @Override public String toString() { if ( denominator==1 ) { return String.format( "%d", numerator ); } else if ( denominator<100 ) { return String.format( "%d/%d", numerator, denominator ); } else { return String.valueOf( numerator/(double)denominator ); } } /** * return the double value closest to this. * @return the double value closest to this. */ public double doubleValue() { return numerator / (double)denominator; } public static void main( String[] args ) { System.err.println( Ratio.create("1.3") ); System.err.println( Ratio.create(".13") ); System.err.println( Ratio.create("13.") ); System.err.println( Ratio.create("13.00") ); System.err.println( new Ratio(4,1).sqrt() ); } }