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 ;)
Related
I'm trying to do the Taylor expansion of the sine of x, but given x greater than 150 degrees, the function diverges.
HereĀ“s my code:
package TaylorJ;
import java.math.*;
public class SeriesSin {
Here I bound the Dominion to be [0, 2pi].
public static double Dominion(double x) {
double dpi = 2*Math.PI;
double dmx = 0;
if((x>=0 && x<=dpi)) {
dmx = x;
}
else if(x<0) {
dmx = dpi+(x%dpi);
}
else {
dmx = x%dpi;
}
return dmx;
}
Here, I defined a factorial function
public static int Factorial(int n) {
n = Math.abs(n);
int a = 1;
int b = 1;
if(n==0 || n == 1) {
return 1;
}
else {
for(int i=n; i>1;i--) {
b *=i;
}
return b;
}
}
Here's the Taylor (Maclaurin) series expansion for sin(x)
public static double Sin(double x) {
if(x%Math.PI == 0) {
x = Dominion(x);
}
else {
x = Dominion(Math.abs(Math.toRadians(x)));
}
int j = 0;
double nmu = 0;
double d1 = 10;
double d2 = 0;
do {
d1 = nmu;
nmu = nmu+ Math.pow(-1,j)*((Math.pow(x, ((2*j)+1)))/(Factorial((2*j)+1)));
d2 = nmu;
j = j+1;
}while((Math.abs(Math.abs(d2)-Math.abs(d1))>0.0001));
return nmu;
}
}
The thing is that it has to be defined for x in [0, 2pi], so I don't know what to do.
Thanks
The error is most likely a ripple effect of numerical over/undeflows. Note that the values of the factorial function, that you use as intermediate results in your computation, grow rather quickly. Using standard floating point number representations you will lose accuracy in computations rather quickly.
However, each of your summation terms can be computed by multiplying the previous term in the series with a suitable factor. This way you avoid overly large or small interim results.
Any text on numerical analysis should provide a much more detailed and stringent discussion.
In your code, replace the loop with the following code:
double asummandj = x;
do {
d1 = nmu;
nmu = nmu + Math.pow(-1,j) * asummandj;
d2 = nmu;
j = j+1;
asummandj = asummandj * (x / (2*j)) * (x / (2*j+1));
} while(Math.abs( d2 - d1 ) > 0.0001);
I was trying to create a program that finds the power of a real number . The problem is that exponent is in decimal and less than 1 but not negative.
suppose we have to find the power of
50.76
what i really tried was i wrote 0.76 as 76/100 and it would be 576/100
and after that i wrote
here is the code if you want to see what i did
public class Struct23 {
public static void main(String[] args) {
double x = 45;
int c=0;
StringBuffer y =new StringBuffer("0.23");
//checking whether the number is valid or not
for(int i =0;i<y.length();i++){
String subs = y.substring(i,i+1);
if(subs.equals(".")){
c=c+1;
}
}
if(c>1){
System.out.println("the input is wrong");
}
else{
String nep= y.delete(0, 2).toString();
double store = Double.parseDouble(nep);
int length = nep.length();
double rootnum = Math.pow(10, length);
double skit = power(x,store,rootnum);
System.out.println(skit);
}
}
static double power(double x,double store,double rootnum){
//to find the nth root of number
double number = Math.pow(x, 1/rootnum);
double power = Math.pow(number, store);
return power;
}
}
the answer would come but the main problem is that i cannot use pow function to do that
i can't also use exp() and log() functions.
i can only use
+
-
*
/
help me suggest your ideas .
thanks in advance
def newtons_sqrt(initial_guess, x, threshold=0.0001):
guess = initial_guess
new_guess = (guess+float(x)/guess)/2
while abs(guess-new_guess) > threshold :
guess=new_guess
new_guess = (guess+float(x)/guess)/2
return new_guess
def power(base, exp,threshold=0.00001):
if(exp >= 1): # first go fast!
temp = power(base, exp / 2);
return temp * temp
else: # now deal with the fractional part
low = 0
high = 1.0
sqr = newtons_sqrt(base/2,base)
acc = sqr
mid = high / 2
while(abs(mid - exp) > threshold):
sqr = newtons_sqrt(sqr/2.0,sqr)
if (mid <= exp):
low = mid
acc *= sqr
else:
high = mid
acc *= (1/sqr)
mid = (low + high) / 2;
return acc
print newtons_sqrt(1,8)
print 8**0.5
print power(5,0.76)
print 5**0.76
I reapropriated most of this answer from https://stackoverflow.com/a/7710097/541038
you could also expound on newtons_sqrt to give newtons_nth_root ... but then you have to figure out that 0.76 == 76/100 (which im sure isnt too hard really)
you can convert your number to complex form of it and then use de Moivre' formula to compute the nth root of your number using your legal oprations.
This is the formula that can be used to calculate the square root of a number.
result=(guess+(number/guess))/2;
For example, I need to get the square root of 9. First, I need to make a guess. For this one, it's 6. Although, I know that the square root of 9 is 3, I chose 6 to show how the program should work.
that makes...
result=(6+(9/6))/2 which is equal to 3.75.
To get the actual square root of 9, I need to make the result the new guess.The program should continue as...
result=(3.75+(9/3.75))/2 which is equal to 3.075.
This process should continue till difference between result and the result after it is equal to 0. For example
result=(3+(9/3))/2 is always equal to 3.
When the value of result is passed to guess, the next result will also be 3. That means 3 is the square root of nine.
Here's my code:
package javaPackage;
public class SquareRoot {
public static void main(String[] args) {
calcRoot();
}
public static void calcRoot(){
double num=9;
double guess=6;
double result=0;
while(Math.abs(guess-ans)!=0){
result=(guess+(num/guess))/2;
guess=result;
}
System.out.print(result);
}
}
Output
3.75
My problem is I can't compare the value of result and the previous result. Since guess is equal to result, the program immediately since guess and result are already equal. How can I fix it?
Just exchange the two statements in the while loop (and the initializations to avoid a division by zero):
public static void calcRoot(){
double num=9;
double guess=0;
double result=6;
while(Math.abs(guess-result)!=0){
guess=result;
result=(guess+(num/guess))/2;
}
System.out.print(result);
}
The trick is to have the old value still in guess and the new one in result when the test is executed.
And you should not test for != 0, due to rounding errors this may not be achieved. Better test for some small value >= 1e-7
To compare the result with the previous result you need to keep both of them in a variable.
This does a binary chop.
public static double sqrt(double ans) {
if (ans < 1)
return 1.0 / sqrt(1.0 / ans);
double guess = 1;
double add = ans / 2;
while (add >= Math.ulp(guess)) {
double guess2 = guess + add;
double result = guess2 * guess2;
if (result < ans)
guess = guess2;
else if (result == ans)
return guess2;
add /= 2;
}
return guess;
}
public static void main(String[] args) {
for (int i = 0; i <= 10; i++)
System.out.println(sqrt(i) + " vs " + Math.sqrt(i));
}
prints
0.0 vs 0.0
1.0 vs 1.0
1.414213562373095 vs 1.4142135623730951
1.7320508075688772 vs 1.7320508075688772
2.0 vs 2.0
2.236067977499789 vs 2.23606797749979
2.449489742783178 vs 2.449489742783178
2.64575131106459 vs 2.6457513110645907
2.82842712474619 vs 2.8284271247461903
3.0 vs 3.0
3.162277660168379 vs 3.1622776601683795
and
for (int i = 0; i <= 10; i++)
System.out.println(i / 10.0 + ": " + sqrt(i / 10.0) + " vs " + Math.sqrt(i / 10.0));
prints
0.0: 0.0 vs 0.0
0.1: 0.31622776601683794 vs 0.31622776601683794
0.2: 0.4472135954999581 vs 0.4472135954999579
0.3: 0.5477225575051662 vs 0.5477225575051661
0.4: 0.6324555320336759 vs 0.6324555320336759
0.5: 0.7071067811865476 vs 0.7071067811865476
0.6: 0.7745966692414834 vs 0.7745966692414834
0.7: 0.8366600265340758 vs 0.8366600265340756
0.8: 0.894427190999916 vs 0.8944271909999159
0.9: 0.9486832980505138 vs 0.9486832980505138
1.0: 1.0 vs 1.0
Just create another variable to store the value of the previous guess.
This is the code:
package javaPackage;
public class SquareRoot {
public static void main(String[] args) {
calcRoot();
}
public static void calcRoot(){
double num=9;
double guess=6;
double prevGuess=0;
double result=0;
while(Math.abs(guess-prevGuess)!=0){
result=(guess+(num/guess))/2;
prevGuess = guess;
guess=result;
}
System.out.print(result);
}
}
For performance,following this code:
public static double sqrt(double num) {
double half = 0.5 * num;
long bit = Double.doubleToLongBits(num);
bit = 0x5fe6ec85e7de30daL - (bit >> 1);
num = Double.longBitsToDouble(bit);
for (int index = 0; index < 4; index++) {
num = num * (1.5f - half * num * num);
}
return 1 / num;
}
About the magic number 0x5fe6ec85e7de30daL,you can see the FAST INVERSE SQUARE ROOT
Let's see the performance,the test code:
double test = 123456;
//trigger the jit compiler
for (int index = 0; index < 100000000; index++) {
sqrt(test);
}
for (int index = 0; index < 100000000; index++) {
Math.sqrt(test);
}
//performance
long start = System.currentTimeMillis();
for (long index = 0; index < 10000000000L; index++) {
sqrt(test);
}
System.out.println("this:"+(System.currentTimeMillis() - start));
start = System.currentTimeMillis();
for (long index = 0; index < 10000000000L; index++) {
Math.sqrt(test);
}
System.out.println("system:"+(System.currentTimeMillis() - start));
System.out.println(sqrt(test));
System.out.println(Math.sqrt(test));
and the result is:
this:3327
system:3236
this result:351.363060095964
system result:351.363060095964
public static double sqrt(double number)
{
double dd=number, sqi, sqrt=0;
long i, b=0, e=0, c=1, z, d=(long)number, r=0, j;
for (i=1l, sqi=1; ; i*=100l, sqi*=10)
{
if (i>dd)
{
i/=100;
sqi/=10;
j=i;
break;
}
}
for (z=0l; z<16; dd=(dd-(double)(r*i))*100, j/=100l, sqi/=10, z++)
{
r=(long)(dd/i);
d=(e*100l)+r;
int a=9;
for (c=((b*10l)+a)*a; ; a--)
{
c=((b*10l)+a)*a;
if (c<=d)
break;
}
//if (a>=0)
// System.out.print(a);
e=d-c;
sqrt+=a*sqi;
if (number==sqrt*sqrt && j==1)
break;
//if (j==1)
// System.out.print('.');
b=b*10l+2l*(a);
}
return sqrt;
}
Sorry for the undefined variable names....but this program really works!
This program is based on long division method of finding square root
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.
The problem is as follows i have a large or small number (can be either one) and i need to tweak this number and put it through a caluclation. Given the result of the calulation it has to mach a certain value on the 5th decimal at least.
So i need to make a method that takes this starting value, tries to increase or decrease it given what the current result is until i get the correct result. I have made some atempts with no success.
Here is an example that won't woork at all but it hints towards what i mean... (this is just a small scale test case)
public class Test {
public static void main(String[]args)
{
double ran = 100 + (int)(Math.random() * 100000.999999999);
int count = 0;
double tmpPay = 3666.545;
double top = tmpPay;
double low = 0;
while ( tmpPay != ran )
{
if ( tmpPay > ran)
{
if( low == 0)
{
tmpPay = top / 2;
top = tmpPay;
}
else
{
tmpPay = tmpPay + ((top - low) / 2);
top = tmpPay;
}
}
if (tmpPay < ran)
{
tmpPay = top * 1.5;
low = top;
top = tmpPay;
}
}
System.out.println(" VAlue of RAN: " +ran + "----VALUE OF tmpPay: " + tmpPay + "---------- COUNTER: " + count);
}
Example 2 mabey a more clear description. This is my solution now..
guessingValue = firstImput;
while (amortization > tmpPV)
{
guessingValue -= (decimal)1;
//guessingVlue -- > blackbox
amortization = blackboxResults;
}
while (amortization < tmpPV)
{
guessingValue += (decimal)0.00001;
//guessingVlue -- > blackbox
amortization = blackboxResults;
}
}
As I already mentioned in the comment above you should not compare doubles using build-in operators. This is the main reason why your code is not working. The second one is that in else clause tmpPay = tmpPay + ((top-low) /2); instead of tmpPay = tmpPay - ((top-low) /2 );
Complete fixed code is below :
public class Test {
private static final double EPSILON = 0.00001;
public static boolean isEqual( double a, double b){
return (Math.abs(a - b) < EPSILON);
}
public static void main(String[]args)
{
double ran = 100 + (int)(Math.random() * 100000.999999999);
int count = 0;
double tmpPay = 3666.545;
double top = tmpPay;
double low = 0;
while ( !isEqual(tmpPay, ran))
{
if ( tmpPay > ran)
{
if( isEqual(low, 0.0))
{
tmpPay = top / 2;
top = tmpPay;
}
else
{
tmpPay = tmpPay - ((top - low) / 2);
top = tmpPay;
}
}
if (tmpPay < ran)
{
tmpPay = top * 1.5;
low = top;
top = tmpPay;
}
System.out.println("RAN:"+ran+" tmpPay:"+tmpPay+" top:"+top+" low:"+low+" counter:"+count);
count++;
}
System.out.println(" VAlue of RAN: " +ran + "----VALUE OF tmpPay: " + tmpPay + "---------- COUNTER: " + count);
}
}
One way would be to define your problem as a local optimization task and use an local optimizer (for example Brent's method or Nelder Mead Simplex from Apache commons).
Your goal function here would be the distance between the desired value and what you get from your black box.
If I understand correctly, you have a function g(x) and a value K, you want to find x0 such that g(x0) = K.
This is equivalent to find the roots of the function f(x) = g(x) - K, because f(x0) == f(x0) - K == K - K == 0.
A simple algorithm would be Newton's method.
If trying to run the program, it will easily be in infinite loop, since the while condition (for double values comparison) could hardly equal.
e.g.
There are 2 values as follows:
double value1 = 3666.545;
double value2 = 3666.54500001;
value1 == value2 is false.
Even this kind of values are not equal.
You'd better define a range for deviation.
e.g, if |value1 - value2| < 0.005, then break the while condition and print the random num information.