一个俄罗斯人设计的j2me - float 算法

我们知道j2me出于移动设备的运行速度考虑,设计的时候没有考虑浮点类型数据,大家可以通过以下的浮点算法的学习在自己的程序里变通的实现,源代码如下:

package henson.midp;

import java.lang.*;
/**
 * <p>Title: Class for float-point calculations in J2ME applications (MIDP 1.0/CLDC 1.0 where float or double types are not available)</p>
 * <p>Description: It makes float-point calculations via integer numbers</p>
 * <p>Copyright: Nikolay Klimchuk Copyright (c) 2002-2005</p>
 * <p>Company: UNTEH</p>
 * <p>License: Free for use only for non-commercial purpose</p>
 * <p>If you want to use all or part of this class for commercial applications then take into account these conditions:</p>
 * <p>1. I need a one copy of your product which includes my class with license key and so on</p>
 * <p>2. Please append my copyright information henson.midp.Float (C) by Nikolay Klimchuk on 慉bout?screen of your product</p>
 * <p>3. If you have web site please append link <a href=攈ttp://henson.newmail.ru?Nikolay Klimchuk</a> on the page with description of your product</p>
 * <p>That's all, thank you!</p>
 * @author Nikolay Klimchuk http://henson.newmail.ru
 * @version 1.01
 */

public class Float
{
  /** ERROR constant */
  final static private Float ERROR=new Float(Long.MAX_VALUE, Long.MAX_VALUE);
  /** Number of itterations in sqrt method, if you want to make calculations
   * more precise set ITNUM=6,7,... or ITMUN=4,3,... to make it faster */
  final static private int ITNUM=5;
  /** Square root from 3 */
  final static public Float SQRT3=new Float(1732050807568877294L, -18L);
  /** The Float value that is closer than any other to pi, the ratio of the circumference of a circle to its diameter */
  final static public Float PI=new Float(3141592653589793238L, -18L);
  /** Zero constant */
  final static public Float ZERO=new Float();
  /** One constant */
  final static public Float ONE=new Float(1L);
  /** The Float value that is closer than any other to e, the base of the natural logarithms */
  final static public Float E = new Float(271828182845904512L, -17);
  /** Log10 constant */
  final static public Float LOG10 = new Float(2302585092994045684L, -18);
  //
  /** Pi/2 constant */
  final static public Float PIdiv2=PI.Div(2L);
  /** Pi/4 constant */
  final static public Float PIdiv4=PIdiv2.Div(2L);
  /** Pi/6 constant */
  final static public Float PIdiv6=PIdiv2.Div(3L);
  /** Pi/12 constant */
  final static public Float PIdiv12=PIdiv6.Div(2L);
  /** Pi*2 constant */
  final static public Float PImul2=PI.Mul(2L);
  /** Pi*4 constant */
  final static public Float PImul4=PI.Mul(4L);
  /** ln(0.5) constant */
  final static public Float LOGdiv2 = new Float(-6931471805599453094L, -19);
  /** Mantissa */
  public long m_Val;
  /** Exponent */
  public long m_E;
  /** Limit of value */
  private long maxLimit=Long.MAX_VALUE/100;
  //
  /**
   * Create object with zero inside
   */
  public Float()
  {
    m_Val=m_E=0;
  }
  /**
   * Create object and makes initialization with value
   * @param value long - value
   */
  public Float(long value)
  {
    m_Val=value;
    m_E=0;
  }
  /**
   * Create object and makes initialization both mantissa and exponent
   * @param value long - mantissa
   * @param e long - exponent
   */
  public Float(long value, long e)
  {
    m_Val=value;
    if(m_Val==0)
      m_E=0;
    else
      m_E=e;
  }
  /**
   * Create object and makes initialization by other Float object
   * @param value Float - source object
   */
  public Float(Float value)
  {
    m_Val=value.m_Val;
    if(m_Val==0)
      m_E=0;
    else
      m_E=value.m_E;
  }
  /**
   * Convert Float object to long number
   * @return long - number
   */
  public long toLong()
  {
    long tmpE=m_E;
    long tmpVal=m_Val;
    //
    while(tmpE!=0)
    {
      if(tmpE<0)
      {
        tmpVal/=10;
        tmpE++;
      }
      else
      {
        tmpVal*=10;
        tmpE--;
      }
    }
    return tmpVal;
  }
  /**
   * Convert Float object to string without exponent
   * @return String - string
   */
  public String toShortString()
  {
    if(isError())
      return "NaN";
    //
    StringBuffer sb=new StringBuffer();
    sb.append(m_Val);
    int len=(int)m_E;
    if(len>0)
    {
      for(int k=0; k<len; k++)
        sb.append("0");
      len=0;
    }
    //
    String str=sb.toString();
    len += str.length();
    //
    if(m_Val<0L)
    {
      if(len>1)
        return str.substring(0, len);
    }
    else
    {
      if(len>0)
        return str.substring(0, len);
    }
    //
    return "0";
  }
  /**
   * Check value of current Float object is NaN
   * @return boolean - true-if NaN, false-if not
   */
  public boolean isError()
  {
    return (this.m_Val==ERROR.m_Val && this.m_E==ERROR.m_E);
  }
  /** Convert Float object to string */
  public String toString()
  {
    if(isError())
      return "NaN";
    //
    RemoveZero();
    //
    Long l=new Long(m_Val);
    String str=l.toString();
    int len=str.length();
    boolean neg=false;
    if(m_Val<0L)
    {
      neg=true;
      str=str.substring(1, len);
      len--;
    }
    //
    StringBuffer sb=new StringBuffer();
    //
    if(m_E<0L)
    {
      int absE=(int)Math.abs(m_E);
      if(absE<len)
      {
        sb.append(str.substring(0, len-absE));
        sb.append(".");
        sb.append(str.substring(len-absE));
      }
      else
      {
        sb.append(str);
        for(int  i=0; i<(absE-len); i++)
          sb.insert(0, "0");
        sb.insert(0, "0.");
      }
    }
    else
    {
      if(len+m_E>6)
      {
        sb.append(str.charAt(0));
        if(str.length()>1)
        {
          sb.append(".");
          sb.append(str.substring(1));
        }
        else
          sb.append(".0");
        sb.append("E"+(len-1+m_E));
      }
      else
      {
        sb.append(str);
        for(int i=0; i<m_E; i++)
          sb.append("0");
      }
    }
    //
    str=sb.toString();
    sb=null;
    if(neg)
      str="-"+str;
    //
    return str;
  }
  /**
   * Append value of argument to value of current Float object and return as new Float object
   * @param value Float - argument
   * @return Float - current+value
   */
  public Float Add(Float value)
  {
    if(value.Equal(ZERO))
      return new Float(this);
    //
    long e1=m_E;
    long e2=value.m_E;
    long v1=m_Val;
    long v2=value.m_Val;
    // E must be equal in both operators
    while (e1 != e2)
    {
      if(e1 > e2)
      {
        if(Math.abs(v1)<maxLimit)
        {
          v1*=10;
          e1--;
        }
        else
        {
          v2/=10;
          e2++;
        }
      }
      else
      if(e1 < e2)
      {
        if(Math.abs(v2)<maxLimit)
        {
          v2*=10;
          e2--;
        }
        else
        {
          v1/=10;
          e1++;
        }
      }
    }
    //
    if( (v1>0 && v2>Long.MAX_VALUE-v1) || (v1<0 && v2<Long.MIN_VALUE-v1) )
    {
      v1/=10; e1++;
      v2/=10; e2++;
    }
    //
    if(v1>0 && v2>Long.MAX_VALUE-v1)
      return new Float(ERROR);
    else
    if(v1<0 && v2<Long.MIN_VALUE-v1)
      return new Float(ERROR);
    //
    return new Float(v1+v2, e1);
  }
  /**
   * Subtract value of argument from value of current Float object and return as new Float object
   * @param value Float - argument
   * @return Float - current-value
   */
  public Float Sub(Float value)
  {
    if(value.Equal(ZERO))
      return new Float(m_Val, m_E);
    return Add(new Float(-value.m_Val, value.m_E));
  }
  /**
   * Divide value of current Float object on argument and return as new Float object
   * @param value Float - argument
   * @return Float - current/value
   */
  public Float Mul(long value)
  {
    return Mul(new Float(value, 0));
  }
  /**
   * Multiply value of current Float object on argument and return as new Float object
   * @param value Float - argument
   * @return Float - current*value
   */
  public Float Mul(Float value)
  {
    if(value.Equal(ZERO) || this.Equal(ZERO))
      return new Float(ZERO);
    if(value.Equal(ONE))
      return new Float(this);
    //
    boolean negative1=(m_Val<0);
    if(negative1) m_Val=-m_Val;
    boolean negative2=(value.m_Val<0);
    if(negative2) value.m_Val=-value.m_Val;
    // Check overflow and underflow
    do
    {
      if(value.m_Val>m_Val)
      {
        if(Long.MAX_VALUE/m_Val<value.m_Val)
        {
          value.m_Val/=10;
          value.m_E++;
        }
        else
          break;
      }
      else
      {
        if(Long.MAX_VALUE/value.m_Val<m_Val)
        {
          m_Val/=10;
          m_E++;
        }
        else
          break;
      }
    } while(true);
    //
    if(negative1) m_Val=-m_Val;
    if(negative2) value.m_Val=-value.m_Val;
    //
    long e=m_E+value.m_E;
    long v=m_Val*value.m_Val;
    return new Float(v, e);
  }
  /**
   * Divide value of current Float object on argument and return as new Float object
   * @param value Float - argument
   * @return Float - current/value
   */
  public Float Div(long value)
  {
    return Div(new Float(value, 0));
  }
  /**
   * Divide value of current Float object on argument and return as new Float object
   * @param value Float - argument
   * @return Float - current/value
   */
  public Float Div(Float value)
  {
    if(value.Equal(ONE))
      return new Float(this);
    //
    long e1=m_E;
    long e2=value.m_E;
    long v2=value.m_Val;
    if(v2==0L)
      return new Float(ERROR);
    long v1=m_Val;
    if(v1==0L)
      return new Float(ZERO);
    //
    long val=0L;
    while(true)
    {
      val+=(v1/v2);
      v1%=v2;
      if(v1==0L || Math.abs(val)>(Long.MAX_VALUE/10L))
        break;
      if(Math.abs(v1)>(Long.MAX_VALUE/10L))
      {
        v2/=10L;
        e2++;
      }
      else
      {
        v1*=10L;
        e1--;
      }
      val*=10L;
    }
    //
    Float f=new Float(val, e1-e2);
    f.RemoveZero();
    return f;
  }
  public void RemoveZero()
  {
    if(m_Val==0)
      return;
    while ( m_Val%10 == 0 )
    {
     m_Val/=10;
     m_E++;
    }
  }
  /**
   * Is value of current Float object greater?
   * @param x Float - argument
   * @return boolean - true-if current value is greater x, false-if not
   */
  public boolean Great(Float x)
  {
    long e1=m_E;
    long e2=x.m_E;
    long v1=m_Val;
    long v2=x.m_Val;
    //
    while (e1 != e2)
    {
      if(e1 > e2)
      {
        if(Math.abs(v1)<maxLimit)
        {
          v1*=10;
          e1--;
        }
        else
        {
          v2/=10;
          e2++;
        }
      }
      else
      if(e1 < e2)
      {
        if(Math.abs(v2)<maxLimit)
        {
          v2*=10;
          e2--;
        }
        else
        {
          v1/=10;
          e1++;
        }
      }
    }
    //
    return v1>v2;
  }
  /**
   * Is value of current Float object less?
   * @param x Float - argument
   * @return boolean - true-if current value is less x, false-if not
   */
  public boolean Less(long x)
  {
    return Less(new Float(x, 0));
  }
  /**
   * Is value of current Float object less?
   * @param x Float - argument
   * @return boolean - true-if current value is less x, false-if not
   */
  public boolean Less(Float x)
  {
    long e1=m_E;
    long e2=x.m_E;
    long v1=m_Val;
    long v2=x.m_Val;
    //
    while (e1 != e2)
  {
    if(e1 > e2)
    {
      if(Math.abs(v1)<maxLimit)
      {
        v1*=10;
        e1--;
      }
      else
      {
        v2/=10;
        e2++;
      }
    }
    else
    if(e1 < e2)
    {
      if(Math.abs(v2)<maxLimit)
      {
        v2*=10;
        e2--;
      }
      else
      {
        v1/=10;
        e1++;
      }
    }
  }
  //
  return v1<v2;
  }
  /**
   * Equal with current Float object?
   * @param x Float - argument
   * @return boolean - true-if equal, false-if not
   */
  public boolean Equal(Float x)
  {
    long e1=m_E;
    long e2=x.m_E;
    long v1=m_Val;
    long v2=x.m_Val;
    //
    if((v1==0 && v2==0) || (v1==v2 && e1==e2))
      return true;
    // Values with exponent differences more than 20 times never could be equal
    /*
    if(Math.abs(e1-e2)>20)
      return false;
    */
    long diff=e1-e2;
    if(diff<-20 || diff>20)
      return false;
    //
    while (e1 != e2)
    {
      if(e1 > e2)
      {
        if(Math.abs(v1)<maxLimit)
        {
          v1*=10;
          e1--;
        }
        else
        {
          v2/=10;
          e2++;
        }
      }
      else
      if(e1 < e2)
      {
        if(Math.abs(v2)<maxLimit)
        {
          v2*=10;
          e2--;
        }
        else
        {
          v1/=10;
          e1++;
        }
      }
    }
    //
    return (v1==v2);
  }
  /**
   * Reverse sign of value in current Float object and return as new Float object
   * @return Float - new Float object
   */
  public Float Neg()
  {
    return new Float(-m_Val, m_E);
  }
  /**
   * Returns the trigonometric sine of an angle. Special cases: If the argument is NaN or an infinity, then the result is NaN. If the argument is zero, then the result is a zero with the same sign as the argument. A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic
   * @param x Float - an angle, in radians
   * @return Float - the sine of the argument
   */
  static public Float sin(Float x)
  {
    while( x.Great(PI) )
      x=x.Sub(PImul2);
    while( x.Less(PI.Neg()) )
      x=x.Add(PImul2);
    // x*x*x
    Float m1=x.Mul(x.Mul(x));
    Float q1=m1.Div(6L);
    // x*x*x*x*x
    Float m2=x.Mul(x.Mul(m1));
    Float q2=m2.Div(120L);
    // x*x*x*x*x*x*x
    Float m3=x.Mul(x.Mul(m2));
    Float q3=m3.Div(5040L);
    // x*x*x*x*x*x*x*x*x
    Float m4=x.Mul(x.Mul(m3));
    Float q4=m4.Div(362880L);
    // x*x*x*x*x*x*x*x*x*x*x
    Float m5=x.Mul(x.Mul(m4));
    Float q5=m5.Div(39916800L);
    //
    Float result=x.Sub(q1).Add(q2).Sub(q3).Add(q4).Sub(q5);
    // 1e-6
    if(result.Less(new Float(-999999, -6)))
      return new Float(-1L);
    // 1e-6
    if(result.Great(new Float(999999, -6)))
      return new Float(1L);
    // 5e-4
    if(result.Great(new Float(-5, -4)) && result.Less(new Float(5, -4)))
      return new Float(0L);
    //
    return result;
  }
  /**
   * Returns the trigonometric cosine of an angle. Special cases: If the argument is NaN or an infinity, then the result is NaN. A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic
   * @param x Float - an angle, in radians
   * @return Float - the cosine of the argument
   */
  static public Float cos(Float x)
  {
    while( x.Great(PI) )
      x=x.Sub(PImul2);
    while( x.Less(PI.Neg()) )
      x=x.Add(PImul2);
    // x*x
    Float m1=x.Mul(x);
    Float q1=m1.Div(2L);
    // x*x*x*x
    Float m2=m1.Mul(m1);
    Float q2=m2.Div(24L);
    // x*x*x*x*x*x
    Float m3=m1.Mul(m2);
    Float q3=m3.Div(720L);
    // x*x*x*x*x*x*x*x
    Float m4=m2.Mul(m2);
    Float q4=m4.Div(40320L);
    // x*x*x*x*x*x*x*x*x*x
    Float m5=m4.Mul(m1);
    Float q5=m5.Div(3628800L);
    Float result=ONE.Sub(q1).Add(q2).Sub(q3).Add(q4).Sub(q5);
    // 1e-6
    if(result.Less(new Float(-999999, -6)))
      return new Float(-1L);
    // 1e-6
    if(result.Great(new Float(999999, -6)))
      return new Float(1L);
    // 5e-4
    if(result.Great(new Float(-5, -4)) && result.Less(new Float(5, -4)))
      return new Float(0L);
    //
    return result;
  }
  /**
   * Returns the correctly rounded positive square root of a double value. Special cases: If the argument is NaN or less than zero, then the result is NaN. If the argument is positive infinity, then the result is positive infinity. If the argument is positive zero or negative zero, then the result is the same as the argument. Otherwise, the result is the double value closest to the true mathematical square root of the argument value
   * @param x Float - a value
   * @return Float - the positive square root of a. If the argument is NaN or less than zero, the result is NaN
   */
  static public Float sqrt(Float x)
  {
    int sp=0;
    boolean inv=false;
    Float a,b;
    //
    if(x.Less(ZERO))
      return new Float(ERROR);
    if(x.Equal(ZERO))
      return new Float(ZERO);
    if(x.Equal(ONE))
      return new Float(ONE);
    // argument less than 1 : invert it
    if(x.Less(ONE))
    {
      x=ONE.Div(x);
      inv=true;
    }
    //
    long e=x.m_E/2;
    // exponent compensation
    Float tmp=new Float(x.m_Val, x.m_E-e*2);
    // process series of division by 16 until argument is <16
    while(tmp.Great(new Float(16L)))
    {
      sp++;
      tmp=tmp.Div(16L);
    }
    // initial approximation
    a=new Float(2L);
    // Newtonian algorithm
    for(int i=ITNUM; i>0; i--)
    {
      b=tmp.Div(a);
      a=a.Add(b);
      a=a.Div(2L);
    }
    // multiply result by 4 : as much times as divisions by 16 took place
    while(sp>0)
    {
      sp--;
      a=a.Mul(4L);
    }
    // exponent compensation
    a.m_E+=e;
    // invert result for inverted argument
    if(inv)
      a=ONE.Div(a);
    return a;
  }
  /**
   * Returns the trigonometric tangent of an angle. Special cases: If the argument is NaN or an infinity, then the result is NaN. If the argument is zero, then the result is a zero with the same sign as the argument. A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic
   * @param x Float - an angle, in radians
   * @return Float - the tangent of the argument
   */
  static public Float tan(Float x)
  {
    Float c=cos(x);
    if(c.Equal(ZERO)) return new Float(ERROR);
    return (sin(x).Div(c));
  }
  /**
   * Returns a new Float object initialized to the value represented by the specified String
   * @param str String - the string to be parsed
   * @param radix int - basement of number
   * @return Float - the Float object represented by the string argument
   */
  static public Float parse(String str, int radix)
  {
    // Abs
    boolean neg=false;
    if(str.charAt(0)=='-')
    {
      str=str.substring(1);
      neg=true;
    }
    //
    int pos=str.indexOf(".");
    long exp=0;
    // Find exponent position
    int pos2=str.indexOf('E');
    if(pos2==-1) pos2=str.indexOf('e');
    //
    if(pos2!=-1)
    {
      String tmp=new String(str.substring(pos2+1));
      exp=Long.parseLong(tmp);
      str=str.substring(0, pos2);
    }
    //
    if(pos!=-1)
    {
      for(int m=pos+1; m<str.length(); m++)
      {
        if(Character.isDigit(str.charAt(m)))
          exp--;
        else
          break;
      }
      str=str.substring(0, pos)+str.substring(pos+1);
      while(str.length()>1 && str.charAt(0)=='0' && str.charAt(1)!='.')
        str=str.substring(1);
    }
    //
    long result=0L;
    int len=str.length();
    //
    StringBuffer sb=new StringBuffer(str);
    while(true)
    {
      // Long value can't have length more than 20
      while(len>20)
      {
        // Very large number for Long
        sb=sb.deleteCharAt(len-1);
        // Compensation of removed zeros
        if(len<pos || pos==-1)
          exp++;
        //
        len--;
      }
      //
      try
      {
        result=Long.parseLong(sb.toString(), radix);
        if(neg)
          result=-result;
        break;
      }
      catch(Exception e)
      {
        // Very large number for Long
        sb=sb.deleteCharAt(len-1);
        // Compensation of removed zeros
        if(len<pos || pos==-1)
          exp++;
        //
        len--;
      }
    }
    sb=null;
    //
    Float newValue=new Float(result, exp);
    newValue.RemoveZero();
    return newValue;
  }
  /**
   * Returns the arc cosine of an angle, in the range of 0.0 through pi. Special case: If the argument is NaN or its absolute value is greater than 1, then the result is NaN. A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic
   * @param x Float - the value whose arc cosine is to be returned
   * @return Float - the arc cosine of the argument
   */
  static public Float acos(Float x)
  {
    Float f=asin(x);
    if(f.isError())
      return f;
    return PIdiv2.Sub(f);
  }
  /**
   * Returns the arc sine of an angle, in the range of -pi/2 through pi/2. Special cases: If the argument is NaN or its absolute value is greater than 1, then the result is NaN. If the argument is zero, then the result is a zero with the same sign as the argument. A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic
   * @param x Float - the value whose arc sine is to be returned
   * @return Float - the arc sine of the argument
   */
  static public Float asin(Float x)
  {
    if( x.Less(ONE.Neg()) || x.Great(ONE) ) return new Float(ERROR);
    if( x.Equal(ONE.Neg()) ) return PIdiv2.Neg();
    if( x.Equal(ONE) ) return PIdiv2;
    return atan(x.Div(sqrt(ONE.Sub(x.Mul(x)))));
  }
  /**
   * Returns the arc tangent of an angle, in the range of -pi/2 through pi/2. Special cases: If the argument is NaN, then the result is NaN. If the argument is zero, then the result is a zero with the same sign as the argument. A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic
   * @param x Float - the value whose arc tangent is to be returned
   * @return Float - the arc tangent of the argument
   */
  static public Float atan(Float x)
  {
      boolean signChange=false;
      boolean Invert=false;
      int sp=0;
      Float x2, a;
      // check up the sign change
      if(x.Less(ZERO))
      {
          x=x.Neg();
          signChange=true;
      }
      // check up the invertation
      if(x.Great(ONE))
      {
          x=ONE.Div(x);
          Invert=true;
      }
      // process shrinking the domain until x<PI/12
      while(x.Great(PIdiv12))
      {
          sp++;
          a=x.Add(SQRT3);
          a=ONE.Div(a);
          x=x.Mul(SQRT3);
          x=x.Sub(ONE);
          x=x.Mul(a);
      }
      // calculation core
      x2=x.Mul(x);
      a=x2.Add(new Float(14087812, -7));
      a=new Float(55913709, -8).Div(a);
      a=a.Add(new Float(60310579, -8));
      a=a.Sub(x2.Mul(new Float(5160454, -8)));
      a=a.Mul(x);
      // process until sp=0
      while(sp>0)
      {
          a=a.Add(PIdiv6);
          sp--;
      }
      // invertation took place
      if(Invert) a=PIdiv2.Sub(a);
      // sign change took place
      if(signChange) a=a.Neg();
      //
      return a;
  }
  /**
   * Converts rectangular coordinates (x,爕) to polar (r,爐heta). This method computes the phase theta by computing an arc tangent of y/x in the range of -pi to pi. Special cases: If either argument is NaN, then the result is NaN. If the first argument is positive zero and the second argument is positive, or the first argument is positive and finite and the second argument is positive infinity, then the result is positive zero. If the first argument is negative zero and the second argument is positive, or the first argument is negative and finite and the second argument is positive infinity, then the result is negative zero. If the first argument is positive zero and the second argument is negative, or the first argument is positive and finite and the second argument is negative infinity, then the result is the double value closest to pi. If the first argument is negative zero and the second argument is negative, or the first argument is negative and finite and the second argument is negative infinity, then the result is the double value closest to -pi. If the first argument is positive and the second argument is positive zero or negative zero, or the first argument is positive infinity and the second argument is finite, then the result is the double value closest to pi/2. If the first argument is negative and the second argument is positive zero or negative zero, or the first argument is negative infinity and the second argument is finite, then the result is the double value closest to -pi/2. If both arguments are positive infinity, then the result is the double value closest to pi/4. If the first argument is positive infinity and the second argument is negative infinity, then the result is the double value closest to 3*pi/4. If the first argument is negative infinity and the second argument is positive infinity, then the result is the double value closest to -pi/4. If both arguments are negative infinity, then the result is the double value closest to -3*pi/4. A result must be within 2 ulps of the correctly rounded result. Results must be semi-monotonic
   * @param y Float - the ordinate coordinate
   * @param x Float - the abscissa coordinate
   * @return Float - the theta component of the point (r,爐heta) in polar coordinates that corresponds to the point (x,爕) in Cartesian coordinates
   */
  static public Float atan2(Float y, Float x)
  {
    // if x=y=0
    if(y.Equal(ZERO) && x.Equal(ZERO))
      return new Float(ZERO);
    // if x>0 atan(y/x)
    if(x.Great(ZERO))
      return atan(y.Div(x));
    // if x<0 sign(y)*(pi - atan(|y/x|))
    if(x.Less(ZERO))
    {
      if(y.Less(ZERO))
        return Float.PI.Sub(atan(y.Div(x))).Neg();
      else
        return Float.PI.Sub(atan(y.Div(x).Neg()));
    }
    // if x=0 y!=0 sign(y)*pi/2
    if(y.Less(ZERO))
      return PIdiv2.Neg();
    else
      return new Float(PIdiv2);
  }

  // precise
  // x=-35 diff=1.48%
  // x=-30 diff=0.09%
  // x=30 diff=0.09%
  // x=31 diff=0.17%
  // x=32 diff=0.31%
  // x=33 diff=0.54%
  // x=34 diff=0.91%
  // x=35 diff=1.46%
  /**
   * Returns Euler's number e raised to the power of a double value. Special cases: If the argument is NaN, the result is NaN. If the argument is positive infinity, then the result is positive infinity. If the argument is negative infinity, then the result is positive zero. A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic
   * @param x Float - the exponent to raise e to
   * @return Float - the value e^x, where e is the base of the natural logarithms
   */
  static public Float exp(Float x)
  {
    if(x.Equal(ZERO))
      return new Float(ONE);
    //
    Float f=new Float(ONE);
    long d=1;
    Float k=null;
    boolean isless=x.Less(ZERO);
    if(isless)
      x=x.Neg();
    k=new Float(x).Div(d);
    //
    for(long i=2; i<50; i++)
    {
      f=f.Add(k);
      k=k.Mul(x).Div(i);
    }
    //
    if(isless)
      return ONE.Div(f);
    else
      return f;
  }

  // precise
  // x=25 diff=0.12%
  // x=30 diff=0.25%
  // x=35 diff=0.44%
  // x=40 diff=0.67%
  /**
   * Internal log subroutine
   * @param x Float
   * @return Float
   */
  static private Float _log(Float x)
  {
    if(!x.Great(ZERO))
      return new Float(ERROR);
    //
    Float f=new Float(ZERO);
    // Make x to close at 1
    int appendix=0;
    while(x.Great(ZERO) && x.Less(ONE))
    {
      x=x.Mul(2);
      appendix++;
    }
    //
    x=x.Div(2);
    appendix--;
    //
    Float y1=x.Sub(ONE);
    Float y2=x.Add(ONE);
    Float y=y1.Div(y2);
    //
    Float k=new Float(y);
    y2=k.Mul(y);
    //
    for(long i=1; i<50; i+=2)
    {
      f=f.Add(k.Div(i));
      k=k.Mul(y2);
    }
    //
    f=f.Mul(2);
    for(int i=0; i<appendix; i++)
      f=f.Add(LOGdiv2);
    //
    return f;
  }
  /**
   * Returns the natural logarithm (base e) of a double value. Special cases: If the argument is NaN or less than zero, then the result is NaN. If the argument is positive infinity, then the result is positive infinity. If the argument is positive zero or negative zero, then the result is negative infinity. A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic
   * @param x Float - a number greater than 0.0
   * @return Float - the value ln(x), the natural logarithm of x
   */
  static public Float log(Float x)
  {
    if(!x.Great(ZERO))
      return new Float(ERROR);
    //
    if(x.Equal(ONE))
      return new Float(ZERO);
    //
    if(x.Great(Float.ONE))
    {
      x=ONE.Div(x);
      return _log(x).Neg();
    }
    return _log(x);
  }

  static public Float log10(Float x)
  {
    if(!x.Great(ZERO))
      return new Float(ERROR);
    //
    if(x.Equal(ONE))
      return new Float(ZERO);
    //
    Float f=log(x);
    if(f.isError())
      return f;
    return f.Div(LOG10);
  }
/*
  static public Float log10(Float x)
  {
    if(!x.Great(ZERO))
      return new Float(ERROR);
    //
    boolean neg=false;
    if(x.m_Val<0)
    {
      neg=true;
      x.m_Val=-x.m_Val;
    }
    //
    int index=0;
    if(x.Great(Float.ONE))
    {
      // 令朦 1
      while(x.Great(Float.ONE))
      {
        x=x.Div(10);
        index++;
      }
    }
    else
    {
      // 体睃 桦?疣忭?1
      while(x.Less(Float.ONE))
      {
        x=x.Mul(10);
        index--;
      }
    }
    //
    Float res=new Float(index);
    if(!x.Equal(ONE))
      res=res.Add(log(x).Div(LOG10));
    //
    if(neg)
      return Float.ONE.Div(res);
    else
      return res;
  }
 */

  // precise y=3.5
  // x=15 diff=0.06%
  // x=20 diff=0.40%
  // x=25 diff=1.31%
  // x=30 diff=2.95%
  // if x negative y must be integer value
  /**
   * Returns the value of the first argument raised to the power of the second argument. Special cases: If the second argument is positive or negative zero, then the result is 1.0. If the second argument is 1.0, then the result is the same as the first argument. If the second argument is NaN, then the result is NaN. If the first argument is NaN and the second argument is nonzero, then the result is NaN. If the absolute value of the first argument is greater than 1 and the second argument is positive infinity, or the absolute value of the first argument is less than 1 and the second argument is negative infinity, then the result is positive infinity. If the absolute value of the first argument is greater than 1 and the second argument is negative infinity, or the absolute value of the first argument is less than 1 and the second argument is positive infinity, then the result is positive zero. If the absolute value of the first argument equals 1 and the second argument is infinite, then the result is NaN. If the first argument is positive zero and the second argument is greater than zero, or the first argument is positive infinity and the second argument is less than zero, then the result is positive zero. If the first argument is positive zero and the second argument is less than zero, or the first argument is positive infinity and the second argument is greater than zero, then the result is positive infinity. If the first argument is negative zero and the second argument is greater than zero but not a finite odd integer, or the first argument is negative infinity and the second argument is less than zero but not a finite odd integer, then the result is positive zero. If the first argument is negative zero and the second argument is a positive finite odd integer, or the first argument is negative infinity and the second argument is a negative finite odd integer, then the result is negative zero. If the first argument is negative zero and the second argument is less than zero but not a finite odd integer, or the first argument is negative infinity and the second argument is greater than zero but not a finite odd integer, then the result is positive infinity. If the first argument is negative zero and the second argument is a negative finite odd integer, or the first argument is negative infinity and the second argument is a positive finite odd integer, then the result is negative infinity. If the first argument is finite and less than zero if the second argument is a finite even integer, the result is equal to the result of raising the absolute value of the first argument to the power of the second argument if the second argument is a finite odd integer, the result is equal to the negative of the result of raising the absolute value of the first argument to the power of the second argument if the second argument is finite and not an integer, then the result is NaN. If both arguments are integers, then the result is exactly equal to the mathematical result of raising the first argument to the power of the second argument if that result can in fact be represented exactly as a double value. (In the foregoing descriptions, a floating-point value is considered to be an integer if and only if it is finite and a fixed point of the method ceil or, equivalently, a fixed point of the method floor. A value is a fixed point of a one-argument method if and only if the result of applying the method to the value is equal to the value.) A result must be within 1 ulp of the correctly rounded result. Results must be semi-monotonic.
   * @param x Float - the base
   * @param y Float - the exponent
   * @return Float - the value a^b
   */
  static public Float pow(Float x, Float y)
  {
    if(x.Equal(ZERO))
      return new Float(ZERO);
    if(x.Equal(ONE))
      return new Float(ONE);
    if(y.Equal(ZERO))
      return new Float(ONE);
    if(y.Equal(ONE))
      return new Float(x);
    //
    long l=y.toLong();
    boolean integerValue=y.Equal(new Float(l));
    //
    if(integerValue)
    {
      boolean neg=false;
      if(y.Less(0))
        neg=true;
      //
      Float result=new Float(x);
      for(long i=1; i<(neg?-l:l); i++)
        result=result.Mul(x);
      //
      if(neg)
        return ONE.Div(result);
      else
        return result;
    }
    else
    {
      if(x.Great(ZERO))
        return exp(y.Mul(log(x)));
      else
        return new Float(ERROR);
    }
  }
  /**
   * Returns the smallest (closest to negative infinity) double value that is not less than the argument and is equal to a mathematical integer. Special cases: If the argument value is already equal to a mathematical integer, then the result is the same as the argument. If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument. If the argument value is less than zero but greater than -1.0, then the result is negative zero
   * @param x Float - a value
   * @return Float - the smallest (closest to negative infinity) floating-point value that is not less than the argument and is equal to a mathematical integer
   */
  static public Float ceil(Float x)
  {
    long tmpVal=x.m_Val;
    //
    if(x.m_E<0)
    {
      long coeff=1;
      //
      if(x.m_E>-19)
      {
        for(long i=0; i<-x.m_E; i++)
          coeff*=10;
        tmpVal/=coeff;
        tmpVal*=coeff;
        if(x.m_Val-tmpVal>0)
          tmpVal+=coeff;
      }
      else
      if(tmpVal>0)
        return ONE;
      else
        return ZERO;
    }
    //
    return new Float(tmpVal, x.m_E);
  }
  /**
   * Returns the largest (closest to positive infinity) double value that is not greater than the argument and is equal to a mathematical integer. Special cases: If the argument value is already equal to a mathematical integer, then the result is the same as the argument. If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument
   * @param x Float - a value
   * @return Float - the largest (closest to positive infinity) floating-point value that is not greater than the argument and is equal to a mathematical integer
   */
  static public Float floor(Float x)
  {
    long tmpVal=x.m_Val;
    //
    if(x.m_E<0)
    {
      long coeff=1;
      //
      if(x.m_E>-19)
      {
        for(long i=0; i<-x.m_E; i++)
          coeff*=10;
        tmpVal/=coeff;
        tmpVal*=coeff;
        if(x.m_Val-tmpVal<0)
          tmpVal-=coeff;
      }
      else
      if(tmpVal<0)
        return ONE.Neg();
      else
        return ZERO;
    }
    //
    return new Float(tmpVal, x.m_E);
  }
  /**
   * Returns the absolute value of a Float object. If the argument is not negative, the argument is returned. If the argument is negative, the negation of the argument is returned. Special cases: If the argument is positive zero or negative zero, the result is positive zero. If the argument is infinite, the result is positive infinity. If the argument is NaN, the result is NaN
   * @param x Float - the argument whose absolute value is to be determined
   * @return Float - the absolute value of the argument
   */
  static public Float abs(Float x)
  {
    if(x.m_Val<0)
      return x.Neg();
    return new Float(x);
  }
  /**
   * Integer part of Float object
   * @param x Float - source Float object
   * @return Float - result Float object
   */
  static public Float Int(Float x)
  {
    long tmpVal=x.m_Val;
    //
    if(x.m_E<0)
    {
      long coeff=1;
      //
      if(x.m_E>-19)
      {
        for(long i=0; i<-x.m_E; i++)
          coeff*=10;
        tmpVal/=coeff;
        tmpVal*=coeff;
      }
      else
        return Float.ZERO;
    }
    //
    return new Float(tmpVal, x.m_E);
  }
  /**
   * Fractional part of Float object
   * @param x Float - source Float object
   * @return Float - result Float object
   */
  static public Float Frac(Float x)
  {
    return x.Sub(Int(x));
  }
  /**
   * Converts an angle measured in degrees to an approximately equivalent angle measured in radians. The conversion from degrees to radians is generally inexact
   * @param x Float - an angle, in degrees
   * @return Float - the measurement of the angle x in radians
   */
  static public Float toRadians(Float x)
  {
    return x.Mul(PI).Div(180L);
  }
  /**
   * Converts an angle measured in radians to an approximately equivalent angle measured in degrees. The conversion from radians to degrees is generally inexact; users should not expect cos(toRadians(90.0)) to exactly equal 0.0
   * @param x Float - an angle, in radians
   * @return Float - the measurement of the angle angrad in degrees
   */
  static public Float toDegrees(Float x)
  {
    return x.Mul(180L).Div(PI);
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值