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);
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
This program is supposed to go through the number of 2 to 50 people and get the probability out of 100,000 trials whether 2 people will have the same birthday or not.
import java.util.Random;
public class birthday {
public static void main(String[] args) {
int N = 2;
while (N != 51) {
double probability = one_probability(N);
System.out.println(N + " " + probability);
N++;
}
}
public static boolean one_group(int N) {
int A[] = new int[N];
Random random = new Random();
boolean have_match = false;
for (int i = 0; i < N; i++) { //assigns each person a birthday
int k = random.nextInt(365);
A[i] = k;
}
for (int i = 0; i < N; i++) { //testing to see if birthdays match up
for (int j = i+1; j < N; j++) {
if (A[i] == A[j]) { have_match = true; break; }
}
}
return have_match;
}
public static double one_probability(int N) {
int x = 0;
for (int i = 0; i < 100000; i++) { //repeating 100,000 times to get average probability
boolean have_match = one_group(N);
if (have_match == true) { x++; }
}
double probability = x / 100000; //getting the average probability
return probability;
}
}
Here's the result (it goes from 2-50), it keeps giving me zeros so I know something is wrong. Please help :)
Output
Try with
int probability = x / 1000; // 1/100 of the value to get an probability in percent (integer)
or
float probably = x / 100000F; //F for a `float`
double probability = x / 100000.0; //a decimal without a F is a `double`
Without that, this can't work :
float probably = x / 100000;
First, the division of two integer will be stored in memory like an integer then store in a float/double. That storage truncate the value. This is the operator logic to return the biggest type in an operation so :
int * int -> int
int * float -> float
int * double -> double
short * short -> int //that's a trick, int is the minimal value an operation can return
int probability=x/100000; always return 0.
convert it to double probability=x/100000.0; the value of probability will always less than or equal one. because x will never be greater than 100000. And also change the return type of one_probability method to double.
Task is to calculate expression for natural numbers entered.
I know I should calculate binominal coefficient here right?
Also I know that (-1)^p determines whether this array is decrementing or incrementing, but don't know how to use p in my code
I am not quite sure how to put it all together, this is what I came up with so far and it is really nothing special as I still can't grasp on the idea of how to write this in program.
public static int calculateExpression(int n, int k,int p) {
if(k<0 || n<k)
{
return 0;
}
// Find factorial of n
int n_fac = 1;
for (int j = 1; j <= n; j++) {
n_fac = n_fac * j;
}
// Find factorial of k
int k_fac = 1;
for(int i = 1; i<=k; i++) {
k_fac = k_fac * i;
}
// Find n-k fac
int n_k = n-k;
int n_k_fac = 1;
for(int l = 1; l<=n_k;l++) {
n_k_fac*=l;
}
// n/k = n!/k!(n-k)!
double resultOf_n_kDivision = n_fac/k_fac*n_k_fa;
System.out.println(resultOf_n_kDivision);
return n_k_fac;
}
The factorial function is a very fast-growing one, so calculating the numerator and denominator separately may not be a good idea, as it may lead to overflow for even relatively small values of n.
Let's look at an iterative method for calculating the coefficient:
We see that we can calculate the next coefficient of the row if we know the current one. Thus we can incrementally calculate each term in S, while being less concerned about overflow problems.
static int calculateExpression(int n, int k, int p)
{
// first term of the row is (n, 0) = 1
int binom = 1;
// Iteratively find (n, k)
for (int i = 0; i < k; i++)
binom = (binom * (n - i)) / (i + 1);
// sum the series
int S = binom;
for (int i = 0; i < p; i++) {
// "trick": multiply with a minus sign each time to flip the sign
binom = (-binom * (n - k - i)) / (k + i + 1);
S += binom;
}
return S;
}
UPDATE: Parallel numerical tests:
n k p | orig new
----------------------
5 3 2 | 6 6
10 4 1 | -42 -42
12 3 7 | 44 44
15 8 6 | 3433 8 // integer overflow occurred with the original method
As you can see the two functions were consistent until the last line with n = 15, as 15! = 1307674368000 is much bigger than the maximum positive value of int in most implementations of Java (32-bit).
Use abstraction for better tackling problems; define fac and over.
Then the problem becomes:
public static int calculateExpression(int n, int k,int p) {
int sum = 0;
int minus1toP = 1;
for (int i = 0; i <= p; i++) {
sum += minus1toP * over(n, ...);
minus1toP = -minus1toP;
}
return sum;
}
static int over(int n, int k) {
return fac(n) / fac(k) / fac(n - k);
}
static int fac(int n) {
int f = 1;
for(int i = 2; i <= n; i++) {
f *= i;
}
return f;
}
I did not give the entire solution (...), but maybe too much already.
I did not really get your question, but you can just use this.
public static double combination(int n, int k)
{
double nFactorial = getFactorialFromNToK(n, k);
double kFactorial = getFactorialFromNToK(k, 1);
return nFactorial / kFactorial;
}
public static double getFactorialFromNToK(double n, double k)
{
double factorial = 1;
for (; n - k + 1 > 0; n--)
{
factorial *= n;
}
return factorial;
}
This is the evaluation of nCk for the coef of a term in the binomial expansion.
If nCn is a term in the expansion, then it converges and if it does not exist as term in the expansion, then it will not converge. So if it is a natural number expansion, then it will always converge.
A better solution is to use the lngamma function instead of factorial. It's a more efficient way to calculate factorials. The natural log means that dividing large numbers will be less of a problem.
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 ;)
I'm having difficulty writing a program to solve this exercise from a Java text book:
Write a method raiseRealToPower that takes a floating-point value x and an integer
k and returns xk. Implement your method so that it can correctly calculate the result
when k is negative, using the relationship
x^(-k) = 1 / x^k.
Use your method to display a table of values of πk for all values of k from –4 to 4.
I didn't done this part with PI, i know that, if my programs starts to work... this is what i done... tell me please, what is wrong.
import acm.program.*;
public class vjezba55 extends ConsoleProgram {
private static final double PI = 3.14159253;
public void run() {
double x = readDouble ("x: ");
double k = readDouble ("k: ");
println ("x^k = " + raiseDoublePower(x,k));
}
/* Method that counts x^k */
private double raiseDoublePower (double x, double k){
if (k >= 0) {
return Math.pow(x, k);
}
else {
double total = 1;
for (int i= 0; i>k; i--) {
total = (double) 1 / x;
}
return total;
}
}
}
Take a look at your loop code. You are just recalculating total from scratch on each iteration, rather than updating the previous result.
I don't understand the part in the question regarding PI, but your method may be much simpler (according to using the relationship x^(-k) = 1 / x^k):
private double raiseDoublePower (double x, double k){
if (k >= 0) {
return Math.pow(x, k);
}
else {
return 1 / Math.pow(x, -k);
}
}
Is there a Java equivalent of the C / C++ function called frexp? If you aren't familiar, frexp is defined by Wikipedia to "break floating-point number down into mantissa and exponent."
I am looking for an implementation with both speed and accuracy but I would rather have the accuracy if I could only choose one.
This is the code sample from the first reference. It should make the frexp contract a little more clear:
/* frexp example */
#include <stdio.h>
#include <math.h>
int main ()
{
double param, result;
int n;
param = 8.0;
result = frexp (param , &n);
printf ("%lf * 2^%d = %f\n", result, n, param);
return 0;
}
/* Will produce: 0.500000 * 2^4 = 8.000000 */
How's this?
public static class FRexpResult
{
public int exponent = 0;
public double mantissa = 0.;
}
public static FRexpResult frexp(double value)
{
final FRexpResult result = new FRexpResult();
long bits = Double.doubleToLongBits(value);
double realMant = 1.;
// Test for NaN, infinity, and zero.
if (Double.isNaN(value) ||
value + value == value ||
Double.isInfinite(value))
{
result.exponent = 0;
result.mantissa = value;
}
else
{
boolean neg = (bits < 0);
int exponent = (int)((bits >> 52) & 0x7ffL);
long mantissa = bits & 0xfffffffffffffL;
if(exponent == 0)
{
exponent++;
}
else
{
mantissa = mantissa | (1L<<52);
}
// bias the exponent - actually biased by 1023.
// we are treating the mantissa as m.0 instead of 0.m
// so subtract another 52.
exponent -= 1075;
realMant = mantissa;
// normalize
while(realMant > 1.0)
{
mantissa >>= 1;
realMant /= 2.;
exponent++;
}
if(neg)
{
realMant = realMant * -1;
}
result.exponent = exponent;
result.mantissa = realMant;
}
return result;
}
This is "inspired" or actually nearly copied identically from an answer to a similar C# question. It works with the bits and then makes the mantissa a number between 1.0 and 0.0.
This does do what you want.
public class Test {
public class FRex {
public FRexPHolder frexp (double value) {
FRexPHolder ret = new FRexPHolder();
ret.exponent = 0;
ret.mantissa = 0;
if (value == 0.0 || value == -0.0) {
return ret;
}
if (Double.isNaN(value)) {
ret.mantissa = Double.NaN;
ret.exponent = -1;
return ret;
}
if (Double.isInfinite(value)) {
ret.mantissa = value;
ret.exponent = -1;
return ret;
}
ret.mantissa = value;
ret.exponent = 0;
int sign = 1;
if (ret.mantissa < 0f) {
sign = -1; // Thx Kevin
ret.mantissa = -(ret.mantissa);
}
while (ret.mantissa < 0.5f) {
ret.mantissa *= 2.0f;
ret.exponent -= 1;
}
while (ret.mantissa >= 1.0f) {
ret.mantissa *= 0.5f;
ret.exponent++;
}
ret.mantissa *= sign;
return ret;
}
}
public class FRexPHolder {
int exponent;
double mantissa;
}
public static void main(String args[]) {
new Test();
}
public Test() {
double value = 8.0;
//double value = 0.0;
//double value = -0.0;
//double value = Double.NaN;
//double value = Double.NEGATIVE_INFINITY;
//double value = Double.POSITIVE_INFINITY;
FRex test = new FRex();
FRexPHolder frexp = test.frexp(value);
System.out.println("Mantissa: " + frexp.mantissa);
System.out.println("Exponent: " + frexp.exponent);
System.out.println("Original value was: " + value);
System.out.println(frexp.mantissa+" * 2^" + frexp.exponent + " = ");
System.out.println(frexp.mantissa*(1<<frexp.exponent));
}
}
See Float.floatToIntBits and Double.doubleToLongBits. You still need a little additional logic to decode IEEE 754 floating points.
If I'm reading this right...
public class Frexp {
public static void main (String[] args)
{
double param, result;
int n;
param = 8.0;
n = Math.getExponent(param);
//result = ??
System.out.printf ("%f * 2^%d = %f\n", result, n, param);
}
}
Unfortunately, there doesn't appear to be a built-in method to get the mantissa without converting it to a BigDecimal first (or just doing the division: result = param / Math.pow(2,n).
Strangely enough, scalb does the exact opposite: take a mantissa and exponent and generate a new float from it.
I'm not familiar with the frexp function, but I think you need to look at the BigDecimal' scaled and unscaled values. 'unscaled' is the precision mantissa, scale is the exponent. In psuedocode: value = unscaledValue 10^(-scale)
Nope there is no current implementation in core Java or in the Commons Lang(most likely other place to find it) that has the exact same functionality and ease of frexp; that I know of. If it does exist it's probably in a not widely used toolkit.