Calculate the distance between points with large xy values - java

I'm trying to compare the distance between Point 1 and Point 2 with the distance between Point 1 and Point 3. And I'm trying to find the smaller one. The only problem is that the xy values of all three points are rather large and using the distance formula will likely cause an overflow. Is there another way to find the distances?

Scale the values by a constant, calculate the distance, then "unscale" the values. For example, divide your values by 10^6, or 10^9, or whatever it takes, then calculate the scaled distance and then convert back using your scale constant.

Math.hypot() may be useful in this context, as "the final result is without medium underflow or overflow."

It is the fastest solution:
double dx12=x1-x2;
double dy12=y1-y2;
double dx13=x1-x3;
double dy13=y1-y3;
double r12sq=dx12*dx12+dy12*dy12;
double r13sq=dx13*dx13+dy13*dy13;
int minR= r12sq>r13sq ? Math.sqrt(r13sq) : Math.sqrt(r12sq);
you need to take only one sqrt - that one for the shortest distance.
Normalization by some fixed constant is senseless for double.
If you use integers instead of doubles, the normalization and centering of coordinates by some fixed constant could be useful for some distances and bad for others. For example, if you are dividing by 1000, it is good for coordinates that have differences about some billions, but for differences about some hundreds its effect will be killing. So, you can evaluate the useful coefficient of normalization only after you have the medium dx and dy. Let us you need 4 digits for work
int dx12=x1-x2;
int dy12=y1-y2;
int dx13=x1-x3;
int dy13=y1-y3;
int d=(abs(dx12) +abs(dx13) + abs(dy12) + abs(dy13));
int coeff = d/10000;
if(coeff<1) coeff=1;
int dx12=dx12/coeff;
int dy12=dy12/coeff;
int dx13=dx13/coeff;
int dy13=dy13/coeff;
int r12sq=dx12*dx12+dy12*dy12;
int r13sq=dx13*dx13+dy13*dy13;
int minR= r12sq>r13sq ? Math.sqrt(r13sq) : Math.sqrt(r12sq);
Here you can multiply these int variables without overflow.

Related

Sine approximation error in Java

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.

digit categorisation using Euclidean distance

I want to categorise digits which are represented in a 64 dimensional space which gives an 8X8 pixel character image. Each attribute is an integer from 0...16. I have 20 rows of 64 values plus one at the end which determines the category. The category is previously determined by UCI but I want to know how they got each particular category for each row. So they say they used Euclidean distance to determine the category.
My question is how do I apply Euclidean distance to 64 values? I tried to use following formula (pythagorean theorem) Math.sqrt(Math.pow(x2-x1)+Math.pow(y2-y1)) within a row but the result was too big and I do not know what that represents. For example for the first row I obtained 1612 which is the square root of 40.15
This is my code for the process:
enter code here
public static void main(String[]args)
{
int row[]= new int[64];
for(int z=0;z<64;z++)
{
row[z]=digits[0][z]; //get the first row and store it
}
double result = 0;
for(int z=0;z<64;z+=2)
{
double distance = Math.pow(row[z]-row[z+1],2);
result = result+distance; //add distance each time
System.out.print(result+", ");
}
}
The first row of digits is this:
0,0,5,13,9,1,0,0,0,0,13,15,10,15,5,0,0,3,15,2,0,11,8,0,0,4,12,0,0,8,8,0,0,5,8,0,0,9,8,0,0,4,11,0,1,12,7,0,0,2,14,5,10,12,0,0,0,0,6,13,10,0,0,0,0
I am not sure if this makes sense but if something is not clear please do ask.
Thanks in advance.
My question is how do I apply Euclidean distance to 64 values?
You do not. Distance is a measure between two objects, each of which can have 64 values, but you need two objects. In particular, euclidean distance is defined as
dist(x, y) = ||x-y||_2 = sqrt[ SUM_{i=1}^d (x_i - y_i)^2 ]
where d is the number of dimensions, and x_i means ith dimension of x.
So they say they used Euclidean distance to determine the category.
They said more than that, as the distance itself does not define anything besides... distance. Category on the other hand is an abstract object, which might be defined by some some characteristic point (centroid), then you assign a category with closest (in terms of given distance) centroid.

Which Method is More Accurate?

Suppose we implement the following two methods to calculate the nth multiple of a real number x.
public static double multiply( double x, int n )
{
return x * n;
}
public static double iterativeAdd( double x, int n )
{
double a = 0.0;
for( int b = 0; b < n; b++ )
{
a += x;
}
return a;
}
Assume that n is a legal int and that both x and the exact mathematical product of n and x are no less in absolute value than Double.MIN_VALUE (unless both are 0.0) and no greater in absolute value than Double.MAX_VALUE. Here's what I'm wondering: In general, which is closer to the exact value of the product of x and n: the double returned by multiply( x, n ) or the double returned by iterativeAdd( x, n ) and how do you know?
According to my knowledge, the first method will produce more accurate result because in the second method after each addition probability that some of the digits will be truncated and rounded are more then a single multiplier operation as the result will be calculated once and then the digits will be truncated.
Generally, for every floating point operation you do, your epsilon increases. This happens because floating point numbers have a fixed size in memory, limiting their precision. Each operation is rounded to the nearest value that a float can represent. This rounding accumulates after a while.
Both numbers will get you very close to the answer, but if you run both methods on a large and varied set of numbers, you will see that on average iterativeAdd() has a greater distance from the actual value.
Additionally, multiply() will be significantly faster on any machine, so there's no benefit to ever using iterativeAdd().
Both will return approximately the same value, however there is greater chance that the iterativeAdd() will return more inapproximate value, but the difference will be negligible.
Any single float operation results in some precision loss however small.
In multiply() you make use of the float operation only once but in iterativeAdd() you use it n times.
In general we should avoid using any function like iterativeAdd() as it is will take up a lot of processor time with n floating point operations.

Multiply, divide & square root without using arithmetic operators

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;
}

Math.atan() returning input

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.

Categories