📄 hfloat.java
字号:
/*
* Created on 27-Nov-2005 at 14:08:51.
*
* HFloat - floating point arithmetics for mobile devices
*
* Copyright (c) 2005 Horst Jaeger / Medienkonzepte GbR, Cologne, Germany
*
* This file is part of J2ME Polish.
*
* HFloat 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.
*
* HFloat 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 can receive a copy of the GNU General Public License
* if you write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Commercial licenses are also available indpendently of J2ME Polish, please mail
* hfloat@medienkonzepte.de for details.
* You can also use HFloat commercially when you have obtained a commercial
* license of J2ME Polish.
*
*/
package de.enough.polish.math;
/*
* This class implements floating point arithmetics and some maths. HFloats can be constructed from int like in new HFloat(3) or from String like in new HFloat("-3.14E-2") which means -0.0314 . If you don't want to use the E-Syntax, type new HFloat("-0.0314") instead.
*
* The first argument of each operation is the HFloat object itself. E.g. if you want to know what 2.3 * 4.7 is, type
* System.out.println((new HFloat("2.3")).mlt(new HFloat("4.7")).toString()); this yields "1.08100000E1" which is
* just another way of writing 10.81 . HFloat will always use the scientific output format - there's no way of telling it
* to use a different one.
*
* In case of any invalid operation, the result will be NaN (Not A Number) . We did not want to waste Memory on additinal
* classes so we did not define any HFloat-Exceptions.
*
* Because a HFloat may be invalid, it can't be cast to int - it can be cast to Integer instead, using the toInteger()
* function. The result will be null if the HFloat is NAN.
*
* Two HFloats x and y can be compared using the cmp-Function. The result of x.cmp(y) will be -1 if x < y, 0 if x == y
* and +1 if x > y . You can give a tolerance value eps as well using x.softCmp(y, eps, true) or x.softCmp(y, eps, false).
* Then x and y will be considered equal if they differ less than or no more than eps respectively. The cmp and softCmp
* functions both yield Integer instead of int so the result can be null in case of NaNs.
*
* There are lots of examples about how to use HFloats in the HFloat.java source file as well.
*/public class HFloat extends Object{
//Internal
protected class HFloatHTaylor extends Object implements HTaylor{
public HFloatHTaylor( ){init( -1);}
public HFloatHTaylor(int werBinIchP){init(werBinIchP);}
protected void init(int werBinIchA){
this.werBinIchP = werBinIchA;
this.altN = 0;
this.altCoeff = new HFloat(1); // haengt aus purem Zufall nicht von von werBinIchP ab
}
public HFloat coeff(int n){
switch(this.werBinIchP){
case ASIN_HTAYLOR:
if(n < this.altN) init(this.werBinIchP);
for(int m = this.altN + 1; m <= n; ++m){
int m2 = 2 * m;
this.altCoeff = this.altCoeff.mlt(m2 - 1).div(m2);
}
this.altN = n;
return this.altCoeff.div(2 * n + 1);
case ATAN_HTAYLOR:
if(n % 2 == 0) return (new HFloat( 1)).div(2 * n + 1);
else return (new HFloat(-1)).div(2 * n + 1);
case COS_HTAYLOR:
if(n < this.altN) init(this.werBinIchP);
for(int m = this.altN + 1; m <= n; ++m){
int m2 = 2 * m;
this.altCoeff = this.altCoeff.div(m2 * (1 - m2));
}
this.altN = n;
return this.altCoeff;
case EXP_HTAYLOR:
if(n < this.altN) init(this.werBinIchP);
for(int m = this.altN + 1; m <= n; ++m) this.altCoeff = this.altCoeff.div(m);
this.altN = n;
return this.altCoeff;
case LN_HTAYLOR:
if(n % 2 == 0) return (new HFloat( 1)).div(n + 1);
else return (new HFloat(-1)).div(n + 1);
case SIN_HTAYLOR:
if(n < this.altN) init(this.werBinIchP);
for(int m = this.altN + 1; m <= n; ++m){
int m2 = 2 * m;
this.altCoeff = this.altCoeff.div(-m2 * (1 + m2));
}
this.altN = n;
return this.altCoeff;
default:
return new HFloat();
}
}
protected int werBinIchP;
protected int altN;
protected HFloat altCoeff;
}
//Constructors
public HFloat(){HFloatInit(0, 0, false);}
public HFloat(HFloat orig){HFloatInit(orig.mant, orig.expo, orig.valid);}
public HFloat(int wertA){HFloatInit(wertA, 0, true);}
public HFloat(int wertA, int expoA){HFloatInit(wertA, expoA, true);}
public HFloat(String text){
if(text.toLowerCase().equals("nan")){
HFloatInit(0, 0, false);
}else{
int[] hilf = format(text);
HFloatInit(hilf[0], hilf[1], true);
}
}
//Cast
public Integer toInteger(){
if(!this.valid) return null;
int retval = this.mant;
boolean rund = false;
for(int n = 0; n < this.expo; n++) retval *= 10;
for(int n = 0; n > this.expo; n--){
if(retval % 10 != 0) rund = true;
retval /= 10;
}
if((this.mant < 0) && rund) retval--;
return new Integer(retval);
}
public String toString(){
if(!this.valid) return "NaN";
int expoA;
int cmpI = cmp().intValue();
String wertS;
if(cmpI == -1) return "-" + neg().toString();
if(cmpI == 0) expoA = 0;
else{
expoA = -1;
for(int wertA = abs(this.mant); wertA > 0; wertA /= 10) expoA++;
}
wertS = (new Integer(this.mant)).toString();
for(int n = wertS.length(); n < eInt; n++) wertS += "0";
return wertS.substring(0, 1) + "." + wertS.substring(1, eInt) + "E" + (new Integer(expoA + this.expo)).toString();
}
// Member (public)
public HFloat get(){return new HFloat(this);}
public void set(HFloat orig){HFloatInit(orig.mant, orig.expo, orig.valid);}
public HFloat add(HFloat arg){
if(!this.valid || !arg.valid) return NaN;
if( cmp().intValue() == 0) return arg.get();
if(arg.cmp().intValue() == 0) return get();
int wertH = this.mant;
int argWertH = arg.mant;
int expoH = this.expo;
int argExpoH = arg.expo;
while(expoH < argExpoH){
expoH++;
wertH /= 10;
}
while(expoH > argExpoH){
argExpoH++;
argWertH /= 10;
}
int expoR = expoH;
int wertR = wertH + argWertH;
while(wertR > iMax){
expoR++;
wertR /= 10;
}
return new HFloat(wertR, expoR);
}
public HFloat add(int arg){return add(new HFloat(arg));}
public HFloat add(String arg){return add(new HFloat(arg));}
public HFloat neg(){
if(!this.valid) return NaN;
return new HFloat(-this.mant, this.expo);
}
public HFloat sbt(HFloat arg){return add(arg.neg());}
public HFloat sbt(int arg){return sbt(new HFloat(arg));}
public HFloat sbt(String arg){return sbt(new HFloat(arg));}
public HFloat mlt(HFloat arg){
if(!this.valid || !arg.valid) return NaN;
int[] hilf = format(this.mant * (long) arg.mant);
return new HFloat(hilf[0], this.expo + arg.expo + hilf[1]);
}
public HFloat mlt(int arg){return mlt(new HFloat(arg));}
public HFloat mlt(String arg){return mlt(new HFloat(arg));}
public HFloat inv(){
if(!this.valid || (cmp().intValue() == 0)) return NaN;
int[] hilf = format(lMax / this.mant);
return new HFloat(hilf[0], -this.expo - eLong + hilf[1]);
}
public HFloat div(HFloat arg){return mlt(arg.inv());}
public HFloat div(int arg){return div(new HFloat(arg));}
public HFloat div(String arg){return div(new HFloat(arg));}
public HFloat abs(){
if(!this.valid) return NaN;
if(this.mant < 0) return new HFloat(-this.mant, this.expo);
else return new HFloat( this.mant, this.expo);
}
public Integer cmp(){
if(!this.valid) return null;
if (this.mant == 0) return new Integer( 0);
else if(this.mant > 0) return new Integer( 1);
else return new Integer(-1);
}
public Integer cmp(HFloat arg){return sbt(arg).cmp();}
public Integer cmp(int arg){return sbt(arg).cmp();}
public Integer cmp(String arg){return sbt(arg).cmp();}
public Integer softCmp(HFloat tol, boolean strict){
if(!this.valid || !tol.valid) return null;
int cmpVal = abs().cmp(tol).intValue();
if((cmpVal == -1) || (!strict && (cmpVal != 1))) return new Integer(0);
return cmp();
}
public Integer softCmp(int tol, boolean strict){return softCmp(new HFloat(tol), strict);}
public Integer softCmp(String tol, boolean strict){return softCmp(new HFloat(tol), strict);}
public Integer softCmp(HFloat arg, HFloat tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public Integer softCmp(HFloat arg, int tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public Integer softCmp(HFloat arg, String tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public Integer softCmp(int arg, HFloat tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public Integer softCmp(int arg, int tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public Integer softCmp(int arg, String tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public Integer softCmp(String arg, HFloat tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public Integer softCmp(String arg, int tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public Integer softCmp(String arg, String tol, boolean strict){return sbt(arg).softCmp(tol, strict);}
public HFloat unFrac(){
Integer i = toInteger();
if(i == null) return NaN;
return new HFloat(i.intValue());
}
public HFloat frac(){return sbt(unFrac());}
public HFloat mod(HFloat arg){return div(arg).frac().mlt(arg);}
public HFloat mod(int arg){return div(arg).frac().mlt(arg);}
public HFloat mod(String arg){return div(arg).frac().mlt(arg);}
//Analysis
public HFloat quad(){return mlt(this);}
public HFloat sqrt(){
if(!this.valid) return NaN;
int cmpInt = cmp().intValue();
if(cmpInt == -1) return neg().sqrt();
if(cmpInt == 0) return new HFloat(0);
HFloat altRet = new HFloat(2);
HFloat ret = new HFloat(1);
HFloat arg = get();
int mltMe = 0;
while(arg.cmp(1).intValue() == 1){
++mltMe;
arg = arg.div(4);
}
for(;ret.cmp(altRet).intValue() == -1;){
altRet = ret;
ret = (arg.add(ret.quad())).div(ret).div(2);
}
for(int mltLauf = 0; mltLauf < mltMe; ++mltLauf) ret = ret.mlt(2);
return ret;
}
public HFloat pow(HFloat arg){
if(!this.valid) return NaN;
if(cmp().intValue() == 0) return new HFloat(0);
return ln().mlt(arg).exp();
}
public HFloat pow(int arg){return pow(new HFloat(arg));}
public HFloat pow(String arg){return pow(new HFloat(arg));}
public HFloat exp(){
if(!this.valid) return NaN;
if(cmp().intValue() < 0) return neg().exp().inv();
return taylor(new HFloatHTaylor(EXP_HTAYLOR));
}
public HFloat ln(){
if(!this.valid) return NaN;
int cmpInt = cmp().intValue();
if(cmpInt == 0) return NaN;
if(cmpInt == -1) return neg().ln();
HFloat arg = this;
HFloat zuKlein = new HFloat("0.5");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -