text: /*******************************************************************************
   * Copyright (c) 2004 Actuate Corporation.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *  Actuate Corporation  - initial API and implementation
   *******************************************************************************/
  
  package org.eclipse.birt.chart.internal.model;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import org.eclipse.birt.chart.computation.ValueFormatter;
  import org.eclipse.birt.chart.util.ChartUtil;
  
  public class ContinuedFraction
  {
  
  	private double decimal = 0;
  	private List<Long> integerList = new ArrayList<Long>( );
  
  	public ContinuedFraction( double decimal )
  	{
  		// Correct double precision error here
  		this.decimal = ValueFormatter.normalizeDouble( decimal ).doubleValue( );
  		computeList( );
  	}
  
  	public Fraction getExactFraction( )
  	{
  		int lastIndex = integerList.size( ) - 1;
  		return getFraction( lastIndex,
  				new Fraction( ( integerList.get( lastIndex ) ).intValue( ), 1 ) );
  	}
  
  	public Fraction getFractionWithMaxDigits( int maxDigitsForDenominator )
  	{
  		int lastIndex = integerList.size( );
  		Fraction previousFraction = null;
  		for ( int i = 0; i < lastIndex; i++ )
  		{
  			Fraction fraction = getFraction( i,
  					new Fraction( ( integerList.get( i ) ).intValue( ), 1 ) );
  			if ( fraction.getDenominatorDigits( ) > maxDigitsForDenominator )
  				return previousFraction;
  			previousFraction = fraction;
  		}
  		return previousFraction;
  	}
  
  	private Fraction getFraction( int index, Fraction fraction )
  	{
  		if ( index > 0 )
  		{
  			return getFraction( index - 1,
  					( fraction.invert( ) ).add( integerList.get( index - 1 ) ) );
  		}
  		return fraction;
  	}
  
  	private void computeList( )
  	{
  		int decimalDigits = 0;
  		double decimalTemp = decimal;
  		while ( Math.abs( Math.ceil( decimalTemp ) - decimalTemp ) > Math.pow( 10,
  				decimalDigits - 8 ) )
  		{
  			decimalTemp *= 10.0;
  			decimalDigits++;
  		}
  		long dividend = (long) Math.pow( 10, decimalDigits );
  		long start = (long) decimalTemp;
  		if ( ChartUtil.mathEqual( decimalTemp, Math.ceil( decimalTemp ) ) )
  		{
  			start = (long) Math.ceil( decimalTemp );
  		}
  
  		long quotient = 0;
  		long oldDividend = 0;
  		do
  		{
  			quotient = start / dividend;
  			integerList.add( Long.valueOf( quotient ) );
  			oldDividend = dividend;
  			dividend = start % dividend;
  			start = oldDividend;
  
  		} while ( dividend != 0 );
  	}
  
  	@Override
  	public String toString( )
  	{
  		StringBuffer s = new StringBuffer( );
  		for ( long l : integerList )
  		{
  			s.append( l ).append( ',' );
  		}
  		if ( integerList.size( ) > 0 )
  		{
  			s.deleteCharAt( s.length( ) - 1 );
  		}
  		return s.toString( );
  	}
  }
  