I'm having a problem with Math.atan returning the same value as the input.
public double inchToMOA( double in, double range){
double rangeIn = 36*range;
double atan = (in / rangeIn) * -1.0;
double deg = Math.atan(atan);
double moa = deg * 60;
return moa;
}
I had this all in one line, but I broke it down into different variables to see if I could find out why it wasn't working. if in = -10 and range = 300, then atan is about -.00094. The angle should be about -.053 degrees, but math.atan is returning -.00094, the same as the input.
Is my number too small for math.atan?
Inverse tangent is described here:
http://mathworld.wolfram.com/InverseTangent.html
I don't think your argument is the problem here.
You realize, of course, that computer trig functions deal in radians rather than degrees, right?
It might just be. If you look at the strict definition of the tangent function in mathematics what you see if that tan(x) = sin(x)/cos(x) for small values of "x"
lim x->0, sin(x) = x
lim x->0, cos(x) = 1
hence, you could see that lim x->0, tan(x) -> x meaning that it's inverse, arctan, returns the value it is given. As to the numerical accuracy of Math.atan I would think that the authors had gone to great lengths to ensure it's numerical accuracy.
There's nothing wrong with Math.atan. Its value is nearly 1:1 linear, intersecting the origin, for inputs close to zero. So the closer you are to zero the less change from the input there will be.
Related
I'm a bit annoyed with a method I wrote to approximate sine function in Java. Here it is, it's based on Taylor's series.
static double PI = 3.14159265358979323846;
static double eps = 0.0000000000000000001;
static void sin(double x) {
x = x % (2 * PI);
double term = 1.0;
double res = 0.0;
for (int i = 1; term > eps; i++) {
term = term * (x / i);
if (i % 4 == 1) res += term;
if (i % 4 == 3) res -= term;
}
System.out.println(sum);
}
For little values, I got very good approximation of sine, but for large values (e.g pow(10,22)), results seems very very wrong.
Here are the results :
sin(pow(10,22)) // 0.8740280612007599
Math.sin(pow(10,22)) // -0.8522008497671888
Does someone have an idea ? Thank you !
Best regards,
Be reassured that the Java sin function will be off too.
You problem is that the Taylor expansion for sin has a small radius of convergence and convergence is slow even if you're within that radius.
There are floating point considerations too: a floating point double gives you about 15 significant figures of accuracy.
So for large arguments for sin, the accuracy will deteriorate significantly especially given that sin is a periodic function:
sin(x + 2 * pi * n) = sin(x) for any integer n.
Your answer is incorrect for big numbers because you accumulate a lot of rounding errors due to double presentation. When the number is big, then your for loop will iterate a lot before the term becomes smaller than epsilon. In each iteration, a rounding error is accumulated. The result is a very big error in the final value. Read some nice reference on "Numerical Analysis". Anyway, Tylor's series approximate sin near 0, by definition. So, it is normal not to be correct for very big numbers.
The difference actually has nothing to do with the radius of convergence of the Taylor Series and has to do with double precision not being accurate enough to hold the precision required for such big numbers. The radius of the Taylor series for the sine function is infinity.
10^22 is approximately 2^73. Since the mantissa for a double precision number is 52 bits, consecutive values that can be stored with double precision format will be 2^21 apart from each other. Since an evaluation of the sine function requires more resolution than that, you won't be able to reliably get an answer.
I must calculate sin(x) with a Taylor's series, until the output has 6 decimal places. The argument is an angle. I didn't implement checking the decimal places, I'm just printing next values (to check if it's working), but after 10-20 iteration it shows infinities/NaN's.
What's wrong in my thinking?
public static void sin(double x){
double sin = 0;
int n=1;
while(1<2){
sin += (Math.pow(-1,n) / factorial(2*n+1)) * Math.pow(x, 2*n+1);
n++;
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
}
// CHECKING THE PRECISION HERE LATER
System.out.println(sin);
}
}
the Equation:
Don't compute each term using factorials and powers! You will rapidly overflow.
Just realize that each next term is -term * x * x / ((n+1)*(n+2)) where n increases by 2 for each term:
double tolerance = 0.0000007; // or whatever limit you want
double sin = 0.;
int n = 1;
double term = x;
while ( Math.abs(term) > tolerance ) {
sin += term;
term *= -( (x/(n+1)) * (x/(n+2)) );
n+= 2;
}
To add on to the answer provided by #Xoce (and #FredK), remember that you are computing the McLaurin series (special case of Taylor about x = 0). While this will converge fairly quickly for values that are within about pi/2 of zero, you may not get convergence of the digits before the factorial explodes for values of x further than that.
My recommendation is to use the actual Taylor series about the closest value of sin(x) for which the exact value is known (i.e., the nearest multiple of pi/2, not just about zero. And definitely do the convergence check!
Problem:
NAN error is normally a really big number, something that can happend if you divide 2 numbers but the divisor is very small, or zero.
Solution
This happens because your factorial number is getting an overflow, and later at some point you are dividing by zero again
if your factorial is taken as argument an int, then change it by , for example, a BIgInterger object.
How can I multiply and divide without using arithmetic operators? I read similar question here but i still have problem to multiply and divide.
Also, how can square root be calculated without using math functions?
if you have addition and negation, as in the highest voted answer to the post you gave, you can use looped additions and subtractions to implement multiplication and division.
As for the square root, just implement Newton's Iteration on the basis of the operations from step 1.
Using bitwise operators one example I found is here:
http://geeki.wordpress.com/2007/12/12/adding-two-numbers-with-bitwise-and-shift-operators/
Addition can be translated to multiplicity and division. For sqrt you could use Taylor series.
http://en.wikipedia.org/wiki/Taylor_series
Fast square root function(even faster than the library function!):
EDIT: not true, actually slower because of recent hardware improvements. This is however the code used in Quake II.
double fsqrt (double y)
{
double x, z, tempf;
unsigned long *tfptr = ((unsigned long *)&tempf) + 1;
tempf = y;
*tfptr = (0xbfcdd90a - *tfptr)>>1; /* estimate of 1/sqrt(y) */
x = tempf;
z = y*0.5; /* hoist out the “/2” */
x = (1.5*x) - (x*x)*(x*z); /* iteration formula */
x = (1.5*x) – (x*x)*(x*z);
// x = (1.5*x) – (x*x)*(x*z); /* not necessary in games */
return x*y;
}
I have a distance formula using latitude and longitude:
distance = EARTH_MILES_RADIUS
* Math.acos(Math.sin(lat1 / RADIAN_CONV)
* Math.sin(lat2 / RADIAN_CONV)
+ Math.cos(lat1 / RADIAN_CONV)
* Math.cos(lat2 / RADIAN_CONV)
* Math.cos((lng2 - lng1) / RADIAN_CONV));
lat1,lng1,lat2,lng2 are double primitives. They come to me as double primitives and there is nothing I can do about it.
The problem is that when I have a pair of longitude or latitudes that are the same the formula sometimes returns NaN. I believe this is because I am taking the arc cosine of a number very slightly greater than 1, when in fact it should be exactly 1. I would probably have problems if the points were antipodal as well, where they might be slightly less than -1.
How can I best fix this problem?
If you are indeed calculating great circle distance as I think you are, you should use the Vincenty formula instead of what you have.
http://en.wikipedia.org/wiki/Great-circle_distance
Check for two very close (ideally equal) values in your code. For example:
boolean doubleApproxEqual(double a, double b) {
double PRECISION = 0.000001;
if (Math.abs(a-b) < PRECISION) //not sure what the name of the function is
//cannot be bothered to check
return true;
return false;
}
if you get a True, do cos(1.0) or whatever
Simply checking for equality was enough to fix my problem:
if (lat1 == lat2 && lng1 == lng2) ...
I am working on an exercise in Java. I am supposed to use / and % to extract digits from a number. The number would be something like 1349.9431. The output would be something like:
1349.9431
1349.943
1349.94
1349.9
I know this is a strange way to do but the lab exercise requires it.
Let's think about what you know. Let say you have the number 12345. What's the result of dividing 12345 by 10? What's the result of taking 12345 mod 10?
Now think about 0.12345. What's the result of multiplying that by 10? What's the result of that mod 10?
The key is in those answers.
if x is your number you should be able to do something like x - x%0.1 to get the 1349.9, then x - x%.0.01 to get 1349.94 and so on. I'm not sure though, doing mod on floats is kind of unusual to begin with, but I think it should work that way.
x - x%10 would definetly get you 1340 and x - x%100 = 1300 for sure.
Well the work will be done in background anyway, so why even bother, just print it.
float dv = 1349.9431f;
System.out.printf("%8.3f %8.2f %8.1f", dv, dv, dv);
Alternatively this could be archived with:
float dv = 1349.9431f;
System.out.println(String.format("%8.3f %8.2f %8.1f", dv, dv, dv));
This is a homework question so doing something the way you would actually do in the real world (i.e. using the format method of String as Margus did) isn't allowed. I can see three constraints on any answer given what is contained in your question (if these aren't actually constraints you need to reword your question!)
Must accept a float as an input (and, if possible, use floats exclusively)
Must use the remainder (%) and division (/) operator
Input float must be able to have four digits before and after the decimal point and still give the correct answer.
Constraint 1. is a total pain because you're going to hit your head on floating point precision quite easily if you have to use a number with four digits before and after the decimal point.
float inputNumber = 1234.5678f;
System.out.println(inputNumber % 0.1);
prints "0.06774902343743147"
casting the input float to a double casuses more headaches:
float one = 1234.5678f;
double two = (double) one;
prints "1234.5677490234375" (note: rounding off the answer will get you 1234.5677, which != 1234.5678)
To be honest, this had me really stumped, I spent way too much time trying to figure out how to get around the precision issue. I couldn't find a way to make this program work for 1234.5678f, but it does work for the asker's value of 1349.9431f.
float input = 1349.9431f;
float inputCopy = input;
int numberOfDecimalPoints = 0;
while(inputCopy != (int) inputCopy)
{
inputCopy = inputCopy * 10;
numberOfDecimalPoints++;
}
double inputDouble = (double) input;
double test = inputDouble * Math.pow(10, numberOfDecimalPoints);
long inputLong = Math.round(test);
System.out.println(input);
for(int divisor = 10; divisor < Math.pow(10, numberOfDecimalPoints); divisor = divisor * 10)
{
long printMe = inputLong - (inputLong % divisor);
System.out.println(printMe / Math.pow(10, numberOfDecimalPoints));
}
Of my three constraints, I've satisfied 1 (kind of), 2 but not 3 as it is highly value-dependent.
I'm very interested to see what other SO people can come up with. If the asker has parsed the instructions correctly, it's a very poor exercise, IMO.