MIDP1.0的float类实现代码
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="http://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);
}
}