Mapping (x,y) to single number value - java

I want a function to map the (x,y) value to a single number value and corresponding reverse mapping in Java.
For example (2,34) should map to some value 100 and if we have 100 we should be able to find (2,34).

Well, if you have a maximum value for one of them, then yes. Say y is limited to 0...9999, then could can do:
int num = x * 10000 + y;
(assuming of course that the result will fit in the type - you can possibly upgrade to a wider type like long if necessary). Then, to go back:
int x = num / 10000;
int y = num % 10000;

If you've got an upper limit (say 100 is the higher for x in (x,y)), then you could associate any n to a pair of values (x,y) with this function: n = x * 100 + y.
If you don't have any limit things get more difficult. A way to associate a number belonging to R, to a number of R^2 is that of enumerating diagonals. Look at this example, it's a matrix where the (x,y) cell contains the n associated to it:
1 2 4 7 11 ..
3 5 8 12 ..
6 9 13 ..
10 ..
..

Remember, primitive numbers are just a bunch of raw bits. If your numbers are 32-bit integers (int), you could conveniently pack two of them into one 64-bit integer (long). Something like this:
int a = 3;
int b = 4;
long c = ((long) a) << 16 | b;
...
a = (int) (c >> 16);
b = (int) (c & 0xffff);

You should take a look at HashMap.
Something like HashMap<Integer, List<Integer>> seems to work well for your case.

public class hash {
public static void main(String args[]) throws IOException
{
HashMap<List<Integer>,List<Integer>> g=new HashMap<List<Integer>,List<Integer>>();
List<Integer> xys=new ArrayList<Integer>();
List<Integer> ss=new ArrayList<Integer>();
System.out.println("Enter the coordinates in (x,y)");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("x");
int n1=Integer.parseInt(reader.readLine());
System.out.println("y");
int n2=Integer.parseInt(reader.readLine());
xys.add(n1);
xys.add(n2);
int d=(int)(Math.pow(xys.get(0),xys.get(1)));
ss.add(d);
g.put(xys,ss);
g.put(ss,xys);
List<Integer> r= g.get(ss);
List<Integer> r1=g.get(xys);
System.out.print("Hash for the value (x,y) mapping");
System.out.print(r1);
System.out.print("Hash for the value N, reverse mapping");
System.out.println(r);
}
}

You can keep them as a String.
String a = "(2,34)";
String b = "100";
Map<String, String> m = new HashMap<String, String>();
m.put(a, b);
m.put(b, a);
/*print*/
System.out.println(m.get(a));
System.out.println(m.get(b));

What is the background for this requirement?
If the range of x, y values is unlimited, then there is no way to do this in a unique way (so that you can always reverse the process).
If the range of the numbers is limited, then you could do the following: Suppose that x and y are int values both in the range 0 to 99. Then you calculate the result by: z = 100 * x + y. The reverse would be: x = z / 100 and y = z % 100.

An alternative strategy based on paxdiablo's answer is to use the decimal point, so you would put the x component before the decimal place and the y component after it.
This can entail some messy string handling, but doesn't have the limitation that you need to be able to bound one of your coordinates.

Related

Java - How to do floor division?

I know that in Python you can do floor division like this:
5 // 2 #2
The // is used for something totally different in Java. Is there any way to do floor division in Java?
You can do
double val = 5 / 2;
int answer = Math.floor(val);
OR
int answer = Math.floorDiv(5, 2);
If you were to call System.out.println(answer); the output would be
2
You can easily use Math.floorDiv() method.
For example:
int a = 15, b = 2;
System.out.println(Math.floorDiv(a, b));
// Expected output: 7
If you're using integers in the division and you cast the solution to another integer (by storing the result in another integer variable), the division is already a floor division:
int a = 5;
int b = 2;
int c = 5/2;
System.out.println(c);
>> 2
As khelwood stated, it also works with negative values but the rounding is done towards 0. For example, -1.7 would be rounded to -1.
use floorDiv()
int x = 10;
int y = 3;
System.out.println(Math.floorDiv(x,y));

Java math equation solver [not normal equations]

I need a method in java which returns a solve for an equation this equation without code is like this :
get a number(Z)
and an angle(C) in radians
then find the value of X which is the solution for this equation:
a = Integer( z*cos(c) ) // temp must be integer
//now we have the value of a
// we put it in b
b = a
//now we look for the value of x that solves this equation
b =? Integer( X/cos(C) ) // X also must be integer
X = ?? // we must get X the solves the equation above
Example: consider
Z = 15
C = 140 // full angles will be casted ..it will be rooted to ~-0.0629*PI
temp = Integer( 15*cos(140) // -2.96 )
temp <-- -2 //after parsing to integer
-2 = Integer ( X )/cos(140)
what is X ?
I tried to implement this method in java but most of the times it stuck finding a result
this code doesn't find a direct solution like i want it tests numbers till it gets it but in many of times it can't find a result and keeps looping to the infinity . Also it is so slow in finding the result and i call that function more than 500,000 times in the program
int Rounding(int z, int c){
int offset = 20 ;
int x;
int test = (int) ( z*Math.cos(c) - offset );
int solution;
while(true){
solution = (int) ( test/Math.cos(c) );
if(solution == z){
x = solution;
break;
}else{
test++;
}
/*
if(solution > z){
offset ++;
solution = (int) ( z*Math.cos(c) - offset );
}
*/
}
return x;
}
/*Note : the function will return x only when it solves this : */
int returned_Z = (int) ( x/Math.cos(c) )
// returned_Z must be equal to z
After that that variable x will be stored in a file ...
then when the file opens this variable x will be returned to z with this function :
int returning(int x, int c){
int z = (int) ( x/Math.cos(c) );
return z;
}
From your posting, we have
temp = Integer( 15*cos(140) // -2.96 )
Find X such that
temp = Integer ( X/cos(140) )
We can solve this for X without the integer conversions.
X = 15 / cos^2(140)
or, in general
X = Z / cos^2(C)
This will give you an exact solution for X; you may apply the integer intermediate requirement if needed for some other purpose.
Update per OP comment
You have a defined mathematical relationships between X, temp, and Z. Truncating the intermediate result breaks some of that relationship. In short, if you restrict X to integers, you cannot guarantee that you get exactly Z when you apply the inverse operations.
In particular, you have a transcendental function cos; you cannot dictate that it will be the ratio of your integers temp and X or X and Z. There do exist point solutions for cos that are known rational numbers, but very few.
If I misunderstand the problem -- I realize that we have some translation problem -- then please update your question to specify the correct problem.
Actually the eqn has infinite number of solutions. Say temp = 2. And you write:
2 = Integer ( ( X )/cos(140) )
If we take Integer() for all real numbers in the range 2.0 <= num < 3.0, it results in 2. That's why infinite number of solutions possible. For example, if we take 2.5 from the range:
2 = Integer (2.5) is true
so we can write,
x / cos(140) = 2.5
=> x = 2.5 * cos(140)
= −1.915111108
If we take another 2.3 from the range:
x = −1.761902219
Since there infinite number of real numbers in the range 2.0 <= num < 3.0, the number of solutions is infinite too.
So you can't just expect a single solution for x. If you do, then use:
int Rounding(int z, int c){
int test = ( z*Math.cos(c) );
int x = (int) ( test*Math.cos(c) );
return x;
}
This will give you a correct answer. But as I said before, there are infinite number of solutions for x.

java StdDraw formula for ratio [duplicate]

How do I map numbers, linearly, between a and b to go between c and d.
That is, I want numbers between 2 and 6 to map to numbers between 10 and 20... but I need the generalized case.
My brain is fried.
If your number X falls between A and B, and you would like Y to fall between C and D, you can apply the following linear transform:
Y = (X-A)/(B-A) * (D-C) + C
That should give you what you want, although your question is a little ambiguous, since you could also map the interval in the reverse direction. Just watch out for division by zero and you should be OK.
Divide to get the ratio between the sizes of the two ranges, then subtract the starting value of your inital range, multiply by the ratio and add the starting value of your second range. In other words,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
This evenly spreads the numbers from the first range in the second range.
It would be nice to have this functionality in the java.lang.Math class, as this is such a widely required function and is available in other languages.
Here is a simple implementation:
final static double EPSILON = 1e-12;
public static double map(double valueCoord1,
double startCoord1, double endCoord1,
double startCoord2, double endCoord2) {
if (Math.abs(endCoord1 - startCoord1) < EPSILON) {
throw new ArithmeticException("/ 0");
}
double offset = startCoord2;
double ratio = (endCoord2 - startCoord2) / (endCoord1 - startCoord1);
return ratio * (valueCoord1 - startCoord1) + offset;
}
I am putting this code here as a reference for future myself and may be it will help someone.
As an aside, this is the same problem as the classic convert celcius to farenheit where you want to map a number range that equates 0 - 100 (C) to 32 - 212 (F).
https://rosettacode.org/wiki/Map_range
[a1, a2] => [b1, b2]
if s in range of [a1, a2]
then t which will be in range of [b1, b2]
t= b1 + ((s- a1) * (b2-b1))/ (a2-a1)
In addition to #PeterAllenWebb answer, if you would like to reverse back the result use the following:
reverseX = (B-A)*(Y-C)/(D-C) + A
Each unit interval on the first range takes up (d-c)/(b-a) "space" on the second range.
Pseudo:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
How you handle the rounding is up to you.
if your range from [a to b] and you want to map it in [c to d] where x is the value you want to map
use this formula (linear mapping)
double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
Where X is the number to map from A-B to C-D, and Y is the result:
Take the linear interpolation formula, lerp(a,b,m)=a+(m*(b-a)), and put C and D in place of a and b to get Y=C+(m*(D-C)). Then, in place of m, put (X-A)/(B-A) to get Y=C+(((X-A)/(B-A))*(D-C)). This is an okay map function, but it can be simplified. Take the (D-C) piece, and put it inside the dividend to get Y=C+(((X-A)*(D-C))/(B-A)). This gives us another piece we can simplify, (X-A)*(D-C), which equates to (X*D)-(X*C)-(A*D)+(A*C). Pop that in, and you get Y=C+(((X*D)-(X*C)-(A*D)+(A*C))/(B-A)). The next thing you need to do is add in the +C bit. To do that, you multiply C by (B-A) to get ((B*C)-(A*C)), and move it into the dividend to get Y=(((X*D)-(X*C)-(A*D)+(A*C)+(B*C)-(A*C))/(B-A)). This is redundant, containing both a +(A*C) and a -(A*C), which cancel each other out. Remove them, and you get a final result of: Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
TL;DR: The standard map function, Y=C+(((X-A)/(B-A))*(D-C)), can be simplified down to Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
int srcMin = 2, srcMax = 6;
int tgtMin = 10, tgtMax = 20;
int nb = srcMax - srcMin;
int range = tgtMax - tgtMin;
float rate = (float) range / (float) nb;
println(srcMin + " > " + tgtMin);
float stepF = tgtMin;
for (int i = 1; i < nb; i++)
{
stepF += rate;
println((srcMin + i) + " > " + (int) (stepF + 0.5) + " (" + stepF + ")");
}
println(srcMax + " > " + tgtMax);
With checks on divide by zero, of course.

Find closest value to determined multiplicated value

I have two values. One is static and equals 24
int A = 24;
and I have entries list :
[0, 21, 45, 76, 98]
All of occurences comes in loop and I want to get closest value which divides on A :
0 - 24
21 - 24
45 - 48
76 - 72
98 - 96
How to calculate this?
Using java8 you can stream the array or list and map that
public static void main(String[] args) {
int a = 24;
List<Integer> mL = Arrays.asList(0, 21, 45, 76, 98);
Map<Integer, Integer> m = mL.stream().collect(Collectors.toMap(Integer::intValue, x -> {
int r = a * (int) Math.round(x / (double) a);
return r == 0 ? a : r;
}));
System.out.println(m);
}
the output will be a map where the key is the values to analyse and the values are the closest delta to it
{0=24, 98=96, 21=24, 76=72, 45=48}
You could divide each value by a using floating point division, round it to the closest int and then multiply it back again by a:
int a = 24;
int[] values = new int[]{0, 21, 45, 76, 98};
int[] result =
Arrays.stream(values).map(v -> a * (int) Math.round(v / (double) a)).toArray();
To find the largest multiple x of a number n which is less than a given number a, you can use some arithmetic:
int x = n - n % a;
Now if you want to get the nearest multiple, whether larger or smaller than a, you can use an if statement:
if (a - x > (x + n) - a)
x = x + a
For a list of numbers, just loop over them or use the Stream API.
Assuming that the arrays are also integers, the correct approach for rounding an integer a to the nearest multiple of integer n is as follows:1
(a + n/2) / n * n
How this works
Hopefully the a / n * n approach should be familiar as an approach to get floor-like behaviour, due to the way integer maths works. The n/2 is a bias to give you round-like behaviour instead.2
Things to be aware of
Exact ties are rounded upward.
Inputs within n / 2 of the maximum representable value will cause this to fail.
Comparison with other answers
The floating-point approaches aren't guaranteed to give the right answer for all input values, due to the limitations of floating-point arithmetic.
Using double may work if the inputs are ints (although I'm not sure what the proof is). But it certainly won't be sufficient for longs.
This integer approach may be equivalent to #CodeApprentice's answer, I'm not sure. But this approach avoids the conditional.
1. The boilerplate stream/loop code to get this to work for multiple input values is left as an exercise for the reader.
2. And for completeness, if you use a bias of n-1, you get ceil-like behaviour!
One approach is to take the remainder and see if you need to add or substract from the given number to get closest number that divides. If remainder is less then half of A then substract remainder from the number otherwise add to it the difference between remainder and A. Also as a quick exit check if number is less then A the closest one is A itself.
public static int[] closest(int a, int[] b){
int[] result = new int[ b.length ];
int halfOfA = a/2;
for (int i = 0; i < b.length; i++){
if ( b[i] <= a ){
result[i] = a;
}else{
int rem = b[i] % a;
if (rem < halfOfA) result[i] = b[i] - rem;
else result[i] = b[i] + (a - rem);
}
}
return result;
}
You can do like this :
iterate until your are as near as possible of the value (when distance is less than A/2
private static int closestTo(int a, int i) {
int res = a;
while (Math.abs(res - i) > (a / 2.0) && res< i + a) {
res += a;
}
return res;
}
And use like
public static void main(String[] args) {
int A = 24;
int[] tab = new int[]{0, 21, 45, 76, 98};
for (int i : tab) {
System.out.println(i + " - " + closestTo(A, i));
}
}

Generate random numbers between two numbers

public class TestSample {
public static void main(String[] args) {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
double ran = Math.random();
}
}
I don't want to use Random r = new Random(); class. Is there any other way to generate random numbers. I am just struck with what logic could be applied to generate random numbers between two numbers.
It's really easy... you only need to figure out which is the minimum value and what is the difference between the two numbers (let's call it diff). Then, you can scale the Math.random value (between 0 and 1) by multiplying by diff (now its range is between 0 and diff). Then, if you add the minimum value, your range is between min and min + diff (which is the other value)
int min = min(a,b);
int max = max(a,b);
int diff = max - min;
int result = min + diff * Math.random();
Consider using this code:
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
double ran = Math.random();
double random;
if(a < b)
random = (b-a)*ran + a;
else
random = (a-b)*ran + b;
This will work for a >= 0 and b >= 0 if you consider using negative number the logic sligtly changes
If you are expecting a double result, the simplest approach is
int a =
int b =
double result = (a-b)*Math.random() + b;
It doesn't matter which is greater as you get the same distribution.
However, if you want a random integer between 'a' and 'b' is a bit more complex.
int a =
int b =
int result = Math.floor((Math.abs(a-b)+1) * Math.random()) + Math.min(a, b);
The reason the result is different is that a random double between 0 and 1 will be just less than 1 i.e. [0.0, 1.0) However a random integer between 1 and 6 usually includes 1, 2, 3, 4, 5, 6 equally. As a decimal this is the round down of [0.0 ... 7.0)
You may get white noise from your microphone, and take any number from there. After that you may take any number from the given data, and do with it what you want. The example of getting data from the microphone can be found here.

Categories

Resources