How to get precise Math.exp() in j2me? - java

I am using j2me and I need to get quite precise exp() for values up to 4.
Problem with the j2me is that it's Math library doesn't have pow() and exp() method. To solve this, I just used this method to implement pow():
public static double pow(double num1, double num2) {
double result = 1;
for (int i = 0; i < num2; i++)
result *= num1;
return result;
}
This enabled me to have exp functionality by using setting e as constant (2.718281828459045) and calling pow:
double calculation = (20.386 - (5132.000 / (t + 273.15)));
System.out.println("calc: " + pow(2.71,calculation));
calculation = pow(2.7182818284590452,calculation) * 1.33;
My problem is that result is quite inaccurate, for example if I compare math.exp and my pow method for number 3,75, results are like this:
Pow function returns: 54.5980031309658
Math function returns: 42.52108200006278
So I would need advice, how to implement exp functionality in j2me environment with highest precision possible.

I helped my self with bharath answer in this question: How to get the power of a number in J2ME
Since exp method is just pow, where we use Euler's number for the first argument, I used bharath method:
public double powSqrt(double x, double y)
{
int den = 1024, num = (int)(y*den), iterations = 10;
double n = Double.MAX_VALUE;
while( n >= Double.MAX_VALUE && iterations > 1)
{
n = x;
for( int i=1; i < num; i++ )n*=x;
if( n >= Double.MAX_VALUE )
{
iterations--;
den = (int)(den / 2);
num = (int)(y*den);
}
}
for( int i = 0; i <iterations; i++ )n = Math.sqrt(n);
return n;
}
Method call:
calculation = powSqrt(2.7182818284590452,calculation) * 1.33;
Result is almost as good as Math.pow() method.
PS:
I don't know if this is duplicated thread, if so you can delete it.

Related

Mathematical Operations Without Using Java Math Class

I've been making my own class library in Java and I've run into a small annoyance. The library is centered around math. I started with the intention of not using the Java Math Class. Unfortunately, my lack of skill paired with my inability to find a resource online that tackles this problem has resulted in me falling back onto the Java Math Class. Is there a way I can do logarithms without using Math.log?
We could try to use a power series as per: https://math.stackexchange.com/a/61283
For example:
#Test
public void printMathCalculation() {
double libValue = Math.log(100);
double myValue = getLn(100);
System.out.println("Actual: \t" + libValue);
System.out.println("Approximate: \t" + myValue);
}
//Take double to an integer power
private double pow(double num, int power) {
double result = 1;
for(int i = 0; i < power; i++) {
result *= num;
}
return result;
}
//Get natural log
private double getLn(double num) {
int accuracy = 1000;
double sum = 0;
for(int n = 0; n < accuracy; n++) {
double num1 = (1.0/(2*n+1));
double num2 = (num-1)/(num+1);
sum += num1*pow(num2,2*n+1);
}
return 2 * sum;
}
The results I get are:
Actual: 4.605170185988092
Approximate: 4.605170185988078
You should use Math.log
Try this, using simple maths to calculate
public static int toLog2N(int num){
return num>1 ? 1 + toLog2N(num/2) : 0;
}
Its just an example, you should use Math class as it provides different methods like log(double a), log10(double a), log1p(double a). It will make your code more readable and easier to understand.
hope it helps!

Understanding why my for loop does not work to approximate e

e can be approximated using the formula e = 1 + (1/1!) + (1/2!) + (1/3!)... + (1/n!). I am trying to use for loops to accept whatever integer the user sets n to be. The program should approximate e by using the formula above from (1/1!) + .... (1/n!) and out put the result.
The nested for loop calculates the factorial of n (tested it separately and it works) and the variable defined, frac, puts the factorial into a fraction of 1/(answer to factorial). I store the value into a variable e and it should add the new fraction to the old value every time an iteration is done. I cannot not understand what is wrong with my loops that they are not out putting the right answer.
System.out.println("Enter an integer to show the result of
approximating e using n number of terms.");
int n=scan.nextInt();
double e=1;
double result=1;
for(int i=1; n>=i; n=(n-1))
{
for(int l=1; l<=n; l++)
{
result=result*l;
}
double frac=(1/result);
e=e+frac;
}
System.out.println(e);
Output when I enter the integer 7 as n = 1.0001986906956286
You don't need that whole inner loop. All you need is result *= i.
for (int i = 1; i <= n; i++)
{
result *= i;
double frac = (1 / result);
e += frac;
}
Here's a JavaScript version I just threw together:
function init() {
const elem = document.getElementById('eapprox');
let eapprox = 1;
const n = 15;
let frac = 1;
for (var i = 1; i <= n; ++i) {
frac /= i;
eapprox += frac;
}
elem.textContent = eapprox;
}
This yields 2.718281828458995. Plunker here: http://plnkr.co/edit/OgXbr36dKce21urHH1Ge?p=preview

Accuracy with very small probabilities

I writing a program in Java which requires me to compute some probabilities, and for larger inputs, the probabilities can eventually become very small. Therefore, to prevent underflow issues, I would like to take the log probabilities instead.
I am, however, having trouble implementing this. At each stage of computation there can be a different number of options, to which probabilities need to be assigned, and each stage they need to add up to 1. The probabilities are based on a number of different variables. I take a sum over all possibilities using the following formula:
Math.pow(d[i], a) * Math.pow(1/c[i], b)
This gives me a variable, total. To then establish the probability p_i,
p_i = (Math.pow(d[i], a) * Math.pow(1/c[i], b)) / total
My question is, how can I implement this using log probabilities, so that I do not get 'Infinity' and 'NaN' values, since these are what I have been getting so far.
What I think you should try is to use Kahan Summation. It will allow to sum properly not loosing precision.
In some C-like pseudo-code (sorry, my Java is rusty, code is untested)
double total(int N, double[] d, double[] c, double a, double b) {
double sum = 0.0;
double running_error = 0.0;
for (int i = 0; i != N; ++i) {
if (d[i] == 0.0)
continue;
if (c[i] == 0.0)
throw "XXX"; // some error reporting
double v = 0.0;
if (d[i] > 0.0 && c[i] > 0.0) {
// using log trick, if you want
double lpi = a*Math.log(d[i]) - b*Math.log(c[i]);
v = Math.exp(lpi);
}
else {
v = Math.pow(d[i], a) * Math.pow(1.0/c[i], b);
}
double difference = v - running_error;
double temp = sum + difference;
running_error = (temp - sum) - difference;
sum = temp;
}
return sum;
}

Sum of infinite series inconsistent with Math.exp result

Background: I have the following code which calculates the Gaussian Function as a sum of an infinite series.
The Gaussian Function, at it's simplest form is e^-(x^2).
This can be calculated as the sum of an infinite series, using the Taylor Series expansion.
Therefore, e^-(x^2) = 1 - (x^2) + (x^4)/2! - (x^6)/3! ....
public static double expSeries (double x, int n){
double result = 0.0, x0 = 1.0, x1;
result+= x0;
for (int i=1; i<=n; i++){
x1 = x0 * ((x*x)/i);
if (i%2 == 0){
result += x1;
} else {
result -= x1;
}
x0 = x1;
}
return result;
}
As a comparison, I use Math.exp(-(x*x)) to see if my function works correctly.
The function seems to work for low values of x, but behaves inconsistently after that. Here are the output of a few test cases:
x=1; n=10
Result : 0.3678794642857144
Math.exp: 0.36787944117144233
x=1; n=100
Result : 0.36787944117144245
Math.exp: 0.36787944117144233
x=2; n=100
Result : 0.018315638888733953
Math.exp: 0.01831563888873418
x=3; n=100
Result : 1.234098038990534E-4
Math.exp: 1.2340980408667956E-4
x=4; n=100
Result : 1.1247503313371918E-7
Math.exp: 1.1253517471925912E-7
x=5; n=100
Result : 8.181278981021932E-7
Math.exp: 1.3887943864964021E-11
x=6; n=100
Result : -0.03197975209642004
Math.exp: 2.319522830243569E-16
x=7; n=100
Result : 3.6698962220692825E10
Math.exp: 5.242885663363464E-22
What am I missing here?
Your algorithm looks fine and you are probably hitting the limits of double precision.
I would suggest to rewrite the algo for the Taylor series of exp(x) instead of exp(-x2), which is a little more straightforward to code:
public static double expSeries(double x, int n) {
double term = 1;
double result = term;
for (int i = 1; i <= n; i++) {
term *= x / i;
result += term;
}
return result;
}
You can then add an expSeries_X2(x, i) { return expSeries(-x*x, i); } if you want.
We can then rewrite that method using BigDecimals:
public static double expSeries(double x, int n) {
BigDecimal result = ONE;
BigDecimal term = ONE;
BigDecimal x_ = new BigDecimal(x);
for (int i = 1; i <= n; i++) {
term = term.multiply(x_.divide(BigDecimal.valueOf(i), MathContext.DECIMAL128));
result = result.add(term);
}
return result.doubleValue();
}
And it should return a result that is closer to what you expect.
This is a great lesson in problems with floating point numbers.
Taylor series is not always a good way to calculate a function value.
Look at the general definition here. You're calculating the value of the function by extrapolating out from a certain point a. In your case, that value is zero, so exp(0) = 1. The further you go from zero, the worse the extrapolation. So it is with all extrapolations, regardless of how you do it.
Even worse, you're depending on alternating signs of very large numbers to cancel each other out and give you something sensible. If x = 7 and e = 2.71...., how large a number is 2^49 or 3^49? Very large, indeed.
I don't think the answer should be BigDecimal. A better idea would be to understand exactly what you're doing and find out if there are better ways to approximate the function for large exponents.
Gaussian is used in statistics to model the normal distribution. If you normalize the function parameter to the Z-score (Z = (x-xmean)/stddev) you'll see that 99.9% of the area under the function falls in the range -3 <= Z <= +3 (plus or minus three standard deviations). You aren't likely to need parameter that falls outside that range.
I have rewriten the formula with BigDecimal:
public static void main(String... args){
for(int i=1;i < 8; ++i){
double l = Math.exp(-(Math.pow(i, 2)));
double r = expSeries(BigDecimal.valueOf(i), 100);
System.out.println( l + " - " + r + " = " + (l - r) );
}
}
public static double expSeries (BigDecimal x, int n){
BigDecimal result = BigDecimal.ONE, x1;
for (int i=1; i<=n; i++){
x1 = x.pow(i*2).divide(new BigDecimal(factorial(BigInteger.valueOf(i))), MathContext.DECIMAL128);
if (i%2 == 0) {
result = result.add(x1);
}
else{
result = result.subtract(x1);
}
}
return result.doubleValue();
}
public static BigInteger factorial (BigInteger num){
if (num.compareTo(BigInteger.ONE) == 0) return num;
return num.multiply(
factorial(num.subtract(BigInteger.ONE)));
}
And the result :
0.36787944117144233 - 0.36787944117144233 = 0.0
0.01831563888873418 - 0.01831563888873418 = 0.0
1.2340980408667956E-4 - 1.2340980408667956E-4 = 0.0
1.1253517471925912E-7 - 1.1253517471925912E-7 = 0.0
1.3887943864964021E-11 - 1.3887943997473953E-11 = -1.3250993165605518E-19
2.3195228302435696E-16 - 0.0012040908282411062 = -0.0012040908282408742
5.242885663363464E-22 - 3.6698962251221756E10 = -3.6698962251221756E10
I would say that Math.exp loses precision but I'm not really sure ;)

Translating equivalent formulas in to code isn't giving correct results

I'm trying to calculate the Mean Difference average of a set of data. I have two (supposedly equivalent) formulas which calculate this, with one being more efficient (O^n) than the other (O^n2).
The problem is that while the inefficient formula gives correct output, the efficient one does not. Just by looking at both formulas I had a hunch that they weren't equivalent, but wrote it off because the derivation was made by a statician in a scientific journal. So i'm assuming the problem is my translation. Can anyone help me translate the efficient function properly?
Inefficient formula:
Inefficient formula translation (Java):
public static double calculateMeanDifference(ArrayList<Integer> valuesArrayList)
{
int valuesArrayListSize = valuesArrayList.size();
int sum = 0;
for(int i = 0; i < valuesArrayListSize; i++)
{
for(int j = 0; j < valuesArrayListSize; j++)
sum += (i != j ? Math.abs(valuesArrayList.get(i) - valuesArrayList.get(j)) : 0);
}
return new Double( (sum * 1.0)/ (valuesArrayListSize * (valuesArrayListSize - 1)));
}
Efficient derived formula:
where (sorry, don't know how to use MathML on here):
x(subscript i) = the ith order statistic of the data set
x(bar) = the mean of the data set
Efficient derived formula translation (Java):
public static double calculateMean(ArrayList<Integer> valuesArrayList)
{
double sum = 0;
int valuesArrayListSize = valuesArrayList.size();
for(int i = 0; i < valuesArrayListSize; i++)
sum += valuesArrayList.get(i);
return sum / (valuesArrayListSize * 1.0);
}
public static double calculateMeanDifference(ArrayList<Integer> valuesArrayList)
{
double sum = 0;
double mean = calculateMean(valuesArrayList);
int size = valuesArrayList.size();
double rightHandTerm = mean * size * (size + 1);
double denominator = (size * (size - 1)) / 2.0;
Collections.sort(valuesArrayList);
for(int i = 0; i < size; i++)
sum += (i * valuesArrayList.get(i) - rightHandTerm);
double meanDifference = (2 * sum) / denominator;
return meanDifference;
}
My data set consists of a collection of integers each having a value bounded by the set [0,5].
Randomly generating such sets and using the two functions on them gives different results. The inefficient one seems to be the one producing results in line with what is being measured: the absolute average difference between any two values in the set.
Can anyone tell me what's wrong with my translation?
EDIT: I created a simpler implementation that is O(N) provided the all your data has values limited to a relatively small set.The formula sticks to the methodology of the first method and thus, gives identical results to it (unlike the derived formula). If it fits your use case, I suggest people use this instead of the derived efficient formula, especially since the latter seems to give negative values when N is small).
Efficient, non-derived translation (Java):
public static double calculateMeanDifference3(ArrayList<Integer> valuesArrayList)
{
HashMap<Integer, Double> valueCountsHashMap = new HashMap<Integer, Double>();
double size = valuesArrayList.size();
for(int i = 0; i < size; i++)
{
int currentValue = valuesArrayList.get(i);
if(!valueCountsHashMap.containsKey(currentValue))
valueCountsHashMap.put(currentValue, new Double(1));
else
valueCountsHashMap.put(currentValue, valueCountsHashMap.get(currentValue)+ 1);
}
double sum = 0;
for(Map.Entry<Integer, Double> valueCountKeyValuePair : valueCountsHashMap.entrySet())
{
int currentValue = valueCountKeyValuePair.getKey();
Double currentCount = valueCountKeyValuePair.getValue();
for(Map.Entry<Integer, Double> valueCountKeyValuePair1 : valueCountsHashMap.entrySet())
{
int loopValue = valueCountKeyValuePair1.getKey();
Double loopCount = valueCountKeyValuePair1.getValue();
sum += (currentValue != loopValue ? Math.abs(currentValue - loopValue) * loopCount * currentCount : 0);
}
}
return new Double( sum/ (size * (size - 1)));
}
Your interpretation of sum += (i * valuesArrayList.get(i) - rightHandTerm); is wrong, it should be sum += i * valuesArrayList.get(i);, then after your for, double meanDifference = ((2 * sum) - rightHandTerm) / denominator;
Both equations yields about the same value, but they are not equal. Still, this should help you a little.
You subtract rightHandTerm on each iteration, so it gets [over]multiplied to N.
The big Sigma in the nominator touches only (i x_i), not the right hand term.
One more note: mean * size == sum. You don't have to divide sum by N and then remultiply it back.

Categories

Resources