Package jscicalc

Source Code of jscicalc.ParseBase

/** @file
* Copyright (C) 2005 John D Lamb (J.D.Lamb@btinternet.com)
* Copyright (C) 2007 John D Lamb (J.D.Lamb@btinternet.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package jscicalc;
import jscicalc.complex.Complex;

/**
* This class is designed to convert a string in base Base.BINARY, Base.OCTAL,
* Base.HEXADECIMAL into a jscicalc.complex.Complex.
* It also handles Base.DECIMAL by using a function in DOUBLE.
*
* It was origainlly designed to convert a string in base Base.BINARY, Base.OCTAL,
* Base.HEXADECIMAL into a double. It also handles Base.DECIMAL by using a function
* in java.Math.BigDecimal. In fact it only needs to do this conversion because any
* number that we convert is a real or imaginary part, absolute value or argument.
*
* When you enter an expression as a sequence of Numeral objects, Parser converts
* them to a string and then must convert the string to a double. This class
* does the conversion for Parser.
*
* @see Parser
*
* @author J. D. Lamb
* @version $Revision: 1.5 $
*/
class ParseBase {
   
    /**
     * Private inner class used by ParseBase. It is similar to
     * DisplayFormat.Format.
     *
     * @author J. D. Lamb
     * @version 1.0
     */
    private static class Number {
  /**
   * The constructor must know what Base we are working with.
   * @param b The Base we need to parse
   */
  public Number( Base b ){
      base = b;
      significand = exponent = 0;
  }
 
  /**
   * The significand of the double.
   */
  public long significand;
  /**
   * The significand of the double.
   */
  public long exponent;
  /**
   * The exponent of the double.
   */
  public boolean negative;
  /**
   * Is the exponent negative
   */
  public boolean exponentNegative;
  /**
   * The Base.
   */
  public Base base;

  /**
   * Reads the string and extracts the significand.
   * @param s The string
   * @param b The Base we are working in
   */
  public static Number parseSignificand( String s, Base b ){
      Number number = new Number( b );
      int end = 15;
      int shift = 4;
      if( b == Base.BINARY ){
    end = 60;
    shift = 1;
      }
      else if( b == Base.OCTAL ){
    end = 20;
    shift = 3;
      }
      number.negative = s.charAt( 0 ) == '-';
      int offset = number.negative ? 1 : 0;
      boolean leading = true;
      for( int i = 0; i < end; ++i ){
    long digit = 0;
    if( i + offset < s.length() )
        digit = getDigit( s.charAt( i + offset ) );
    if( digit < 0 ){
        ++offset; // deal with baseimal point, etc.
        --i;
        continue;
    } else if( leading )
        if( digit == 0 && offset < end ){
      ++offset; // deal with leading zeros
      --i;
      continue;
        } else
      leading = false;
    number.significand <<= shift;
    number.significand |= digit;
      }
      return number;
  }
   
  /**
   * Reads the string and extracts the exponent.
   * @param s The string
   */
  private void parseExponent( String s ){
      //System.out.println( s );
      int shift = 0;
      switch( base ){
      case BINARY:
    shift = 1;
    break;
      case OCTAL:
    shift = 3;
    break;
      case HEXADECIMAL:
      default:
    shift = 4;
      }
      exponentNegative = false;
      for( Character c : s.toCharArray() ){
    if( c == '-' )
        exponentNegative = !exponentNegative;
    long digit = getDigit( c );
    if( digit < 0 ) continue;
    exponent <<= shift;
    if( (exponent & 0x1000L) != 0 ){
        break;
    }
    //System.out.println( "++++++++++++++++++++++++++" );
    //System.out.println( exponent );
    //System.out.println( digit );
    //System.out.println( digit * shift );
    //System.out.println( exponent + digit * shift );
    //System.out.println( "--------------------------" );
    exponent += digit * shift;
      }
      if( exponentNegative )
    exponent =- exponent;
      //System.out.println( exponent );
  }
 
  /**
   * Finds the base point, useful for making sure the exponent is correct.
   * @param s The string
   */
  private void parsePoint( String s ){
      //System.out.println( s );
      boolean fraction = false;
      int leadingZeros = 0;
      int fractionalZeros = 0;
      for( Character c : s.toCharArray() ){
    if( c == '.' )
        fraction = true;
    else if( c != '0' ) break;
    else if( fraction )
        ++fractionalZeros;
    else
        ++leadingZeros;
      }
      int leadingDigits = 0;
      for( Character c : s.toCharArray() ){
    if( c == '.' ) break;
    else ++leadingDigits;
      }
      int count = leadingDigits - leadingZeros - fractionalZeros - 1;
      //System.out.println( exponent );
      //System.out.println( count );
      // there are count nonzero digits in front of the base point
      if( base == Base.HEXADECIMAL )
    count *= 4;
      else if( base == Base.OCTAL )
    count *= 3;
      exponent += count;
      //System.out.println( exponent );
      //System.out.println( "**************" );
  }
 
  /**
   * Reads two strings, one contains significand, the other exponent. These
   * will have been obtained using a regular expression.
   * @param s The string containing the significand
   * @param e The string containing the exponent
   * @param b The Base we are working in
   */
  private static Number parseStrings( String s, java.lang.String e,
             Base b ){
      Number number = Number.parseSignificand( s, b );
      if( e.length() > 0 )
    number.parseExponent( e );
      number.parsePoint( s );
      //System.out.println( number.exponent );
      //System.out.println( "$$$$$$$$$$$$$$" );
      return number;
  }

  /**
   * Parses an entire string. Uses a regular expression to split it into
   * significand and exponent and then parses these separately.
   * @param s The string containing the significand
   * @param b The Base we are working in
   */
  public static Number parseString( String s, Base b ){
      java.util.regex.Matcher m = pattern.matcher( s );
      m.matches();
      return parseStrings( m.group( 1 ), m.group( 2 ), b );
  }

  /**
   * A regular expression pattern used to split a string into significand
   * and exponent.
   */
  private static java.util.regex.Pattern pattern
      = java.util.regex.Pattern .compile( "([-|+]?[0-9A-F]+" +
            "|[-|+]?[0-9A-F]+[.][0-9A-F]*" +
            "|[-|+]?[0-9A-F]*[.][0-9A-F]+)" +
            "(e[-|+]?[0-9A-F]+|)" );
 
    }
   
    /**
     * String is composed from Numeral PObject objects. Each contains a char and
     * eventually we need to extract the char from a string and convert it into
     * the corresponding integer
     * @param c a char representing a Numeral
     * @return the corresponding integer
     */
    private static long getDigit( char c ){
  switch( c ){
  case '0':
      return 0;
  case '1':
      return 1;
  case '2':
      return 2;
  case '3':
      return 3;
  case '4':
      return 4;
  case '5':
      return 5;
  case '6':
      return 6;
  case '7':
      return 7;
  case '8':
      return 8;
  case '9':
      return 9;
  case 'A':
      return 10;
  case 'B':
      return 11;
  case 'C':
      return 12;
  case 'D':
      return 13;
  case 'E':
      return 14;
  case 'F':
      return 15;
  default:
      return -1;
  }
    }

    /**
     * This is the function that Parser actually uses. Converts a string to
     * a double in Base b.
     * @param s The string (a number composed from Numeral objects)
     * @param b The Base
     * @return The number as a double
     * @see Parser
     */
    public static Complex parseString( String s, Base b ){
  return new Complex( dparseString( s, b ) );
    }

    /**
     * This is the function that Parser uses for doubles. Converts a string to
     * a double in Base b.
     * @param s The string (a number composed from Numeral objects)
     * @param b The Base
     * @return The number as a double
     * @see Parser
     */
    public static double dparseString( String s, Base b ){
  //System.out.println( s );
  if( b == Base.DECIMAL ){
      java.util.regex.Matcher m = Number.pattern.matcher( s );
      m.matches(); // throws an exception if s is not a suitable number
      return (new java.math.BigDecimal( s )).doubleValue();
      //return Double.valueOf( s ); /* older version */
  }
  Number number = Number.parseString( s, b );
  if( number.significand == 0 )
      return 0;
  // significand has up to 60 binary digits - reduce to 53
  switch( b ){
  case HEXADECIMAL:
      number.significand >>>= 4;
      break;
  case OCTAL:
      number.significand >>>= 5;
      break;
  default:
      number.significand >>>= 7;
  }
  for(; (number.significand & 0xFFE0000000000000L) != 0; ++number.exponent )
      number.significand >>>= 1;
  // exponent has possible overflow/underflow
  if( number.exponent > E_MAX )
      if( number.negative )
    return Double.NEGATIVE_INFINITY;
      else
    return Double.POSITIVE_INFINITY;
  else if( number.exponent < E_MIN ){
      // underflow
      if( number.exponent < E_MIN - 52 )
    return 0;
      else {
    for(; number.exponent < E_MIN; ++number.exponent )
        number.significand >>>= 1;
    number.exponent = -BIAS;
      }
  }
  long result = number.exponent + BIAS;
  //System.out.println( number.exponent );
  result <<= 52; // shift exponent into position
  //System.out.println( Long.toHexString( result ) );
  if( number.negative )
      result |= 0x8000000000000000L;
  else
      result &= 0x7FFFFFFFFFFFFFFFL;
  result |= (number.significand & 0x000FFFFFFFFFFFFFL);
  //System.out.println( Long.toHexString( result ) );
  //System.out.println( Long.toBinaryString( result ) );
  return Double.longBitsToDouble( result );
    }

    public static void main( String[] args ){
   System.out.println( parseString( "777", Base.OCTAL ).real() );
   System.out.println( parseString( "77.7", Base.OCTAL ).real() );
   System.out.println( parseString( "177", Base.OCTAL ).real() );
   System.out.println( parseString( "077", Base.OCTAL ).real() );
   System.out.println( parseString( "0.01", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "0.01", Base.OCTAL ).real() );
   System.out.println( parseString( "0.01", Base.BINARY ).real() );
   System.out.println( parseString( "-0.01", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "-0.01", Base.OCTAL ).real() );
   System.out.println( parseString( "-0.01", Base.BINARY ).real() );
   System.out.println( parseString( "1e3", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "1e3", Base.OCTAL ).real() );
   System.out.println( parseString( "1e11", Base.BINARY ).real() );
   System.out.println( parseString( "1e-3", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "1e-3", Base.OCTAL ).real() );
   System.out.println( parseString( "-1e-11", Base.BINARY ).real() );
   System.out.println( parseString( "1e-13", Base.OCTAL ).real() );
   System.out.println( parseString( "1e+1111111111", Base.BINARY ).real() );
   System.out.println( parseString( "1e+10000000000", Base.BINARY ).real() );
   System.out.println( parseString( "1e-10000000000", Base.BINARY ).real() );
   System.out.println( parseString( "1e-10000000000", Base.BINARY ).real() );
   System.out.println( parseString( "1e-100000000000", Base.BINARY ).real() );
   System.out.println( parseString( "1e-1000000000000", Base.BINARY ).real() );
   System.out.println( parseString( "8e+FF", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "1e+100", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "8e2", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "8e-FF", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "1e-108", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "1e-109", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "1e-109", Base.HEXADECIMAL ).real() );
   System.out.println( parseString( "1e-10A", Base.HEXADECIMAL ).real() );
  System.out.println( parseString( "1e-10C", Base.HEXADECIMAL ).real() );
  System.out.println( parseString( "1e+8", Base.HEXADECIMAL ).real() );
    }
   
    /**
     * Standard constant for IEEE 754 doubles
     */
    public static final long BIAS = 1023;
    /**
     * Standard constant for IEEE 754 doubles
     */
    public static final long E_MAX = 1023;
    /**
     * Standard constant for IEEE 754 doubles
     */
    public static final long E_MIN = -1022;
   
}
TOP

Related Classes of jscicalc.ParseBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.