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.
Related
My task is to implement the cos(x) function withou using Math. library and with the taylor polynom, my code looks like this:
public class Cosinus {
public static void main(String[] args) {
/*if(args.length == 0){
System.out.println("ERROR: Geben Sie ein Argument für x ein!");
return;
}*/
double x = 5;
double summand1 = (x*x) / 2;
double summand2 = (x*x*x*x) / (2*3*4);
double summand3 = (x*x*x*x*x*x) / (2*3*4*5*6);
double summand4 = (x*x*x*x*x*x*x*x) / (2*3*4*5*6*7*8);
double summand5 = (x*x*x*x*x*x*x*x*x*x) / (2*3*4*5*6*7*8*9*10);
double summand6 = (x*x*x*x*x*x*x*x*x*x*x*x) / (2*3*4*5*6*7*8*9*10*11*12);
double summand7 = (x*x*x*x*x*x*x*x*x*x*x*x*x*x) / (2*3*4*5*6*7*8*9*10*11*12*13*14);
//double summand8 = (x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x) / (2*3*4*5*6*7*8*9*10*11*12*13*14*15*16);
//double summand9 = (x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x) / (2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18);
//double summand10 = (x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x) / (2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20);
double cosinusFunktion = (((((((1 - summand1) + summand2) - summand3) + summand4) - summand5) + summand6) - summand7);
System.out.println(cosinusFunktion);
}
}
For x = 1, 2, 3, and 4 Y is between 1 and -1
but with x = 5 it goes too -4 and if the x are even getting bigger this continues too 1287918274.
I cant solve this task but tthe task says it is enough to implement this funktion iwth the taylor polynom and the first 11 summand. I tried this too, but then even with x = 1 the bounds are broken. How can i solve this, so x = 42.5 is in bound of -1 and 1?
Tried more summands to make the result more excact, but the bounds get broken even more.
tried implement the periodicity of x-2*PI, but I dont know where to put it and results get messed up eeven more.
you are getting an integer overflow for the factorial in the summand7 line
as a simple fix you can change the line to:
double summand7 = (x*x*x*x*x*x*x*x*x*x*x*x*x*x) / ((double) 2*3*4*5*6*7*8*9*10*11*12*13*14);
The Taylor expansion will always blow up for larger inputs. However, since:
sin(x) = sin(x + n*2*pi) // for any integer n
You can simply pre-process you input with a modulus function to prevent your output from blowing up.
I can't test compile right now, but if memory serves, you would add one of the following lines prior to computing your first summand:
x = x%(Math.PI*2)
Or, if you can't use Math
x = x%((double)3.14159265358979323846*2)
I want to calculate the increase of percentage of a variable from type int while using another variable from type int for the percentage (50 percent).
thanks in advance for anyone who is willing to help.
`
int a = 3;
int percentage = 3 / 2;
// here I get 3 instead of 4 which is the required answer.
a = a * percentage;
System.out.println(a);
// but here I get the required answer normally.
a = 3;
a = a * 3 / 2;
System.out.println(a);
`
"Percentage" is just a weird of "this value that generally is between 0 and 1 should be rendered by multiplying by 100 and adding a % symbol afterwards". In other words, it's purely a way to display a thing. 50% means 0.5.
int cannot represent 0.5. double sort of can (double and float aren't perfectly accurate). In addition / is integer division if both the left and right side are ints. So, we need to do a few things:
int a = 3;
double b = 1.0 * 3 / 2; // without that 1.0 *, it wouldn't work
System.out.println(b); // prints "1.5"
double c = a * b;
System.out.println(c); // prints 4.5.
int d = ((int) (a * b) + 0.1);
System.out.println(d); // prints 4
Because doubles aren't entirely accurate, and (int) rounds down, adding a small delta (here, 0.1) is a good idea. Otherwise various values will surprise you and go wrong (say, your math ends up at 3.99999999, solely because double is not perfectly accurate, then casting that to int gets you a 3).
Polynomial: a0x^0 + a1x^1 +a2x^2 + a3x^3 + ... + anx^n
Array: array_a[] = {a0, a1, a2, a3 ... an};
I wrote a function to calculate this polynomial in Java:
public double cal(double x) {
double y = 0.0;
for (int index = array_a.length - 1; index >= 0; index--) {
y = array_a[index] + y * x;
}
return y;
}
This seems 5 times faster than the loop y += array_a[index] * Math.Pow(x, index);
But I wondering if there is a better way to compute this polynomial?
** For anyone thinks it's a different calculation: I did test the function above. It does the same thing with y += array_a[index] * Math.Pow(x, index); and they compute the same result.
Thanks.
This is Horner's method. If you only want to calculate it once per polynomial, this is the most efficient algorithm:
… Horner's method requires only n additions and n multiplications, and its storage requirements are only n times the number of bits of x. …
Horner's method is optimal, in the sense that any algorithm to evaluate an arbitrary polynomial must use at least as many operations. Alexander Ostrowski proved in 1954 that the number of additions required is minimal. Victor Pan proved in 1966 that the number of multiplications is minimal.
If you need to evaluate the polynomial extremely many times and the degree is very high, then there are methods to transform the representation of the polynomial (preconditioning) so that the number of multiplication is reduced to ⌊n/2⌋ + 2. This seems not very practical though, at least I've never seen this in the wild. I've found an online paper that describes some of the algorithms if you are interested.
Also mentioned in the paper, due to the CPU architecture it might be more efficient if you evaluating even and odd terms separately so they can be placed in parallel pipelines:
public double cal(double x) {
double x2 = x * x;
double y_odd = 0.0, y_even = 0.0;
int index = array_a.length - 1;
if (index % 2 == 0) {
y_even = array_a[index];
index -= 1;
}
for (; index >= 0; index -= 2) {
y_odd = array_a[index] + y_odd * x2;
y_even = array_a[index-1] + y_even * x2;
}
return y_even + y_odd * x;
}
The JIT/compiler might be able to do this conversion for you or even use SIMD to make it very fast automagically. Anyway, for this kind of micro-optimization, always profile before committing to a final solution.
I keep getting "syntax error on tokens please delete these tokens" on pretty much all of my System.out.println text after the first instance of System.out.println. I don't know what this means or how to fix it? I'm a very new beginning so there might be multiple mistakes in this code. I'm also getting "Syntax error on token ""doubled is"", invalid AssignmentOperator" and """squared is"", invalid AssignmentOperator" errors as well. This is an assignment for a class with the end result supposed to be
the opposite of n is y
n doubled is y
one-half of n is y
n squared is y
the reciprocal of n is y
one-tenth of n is y and y squared is z
n minus the last digit of n is y
the sum of n and n+1 and n+2 is y
Thank you!
import java.util.Scanner;
public class Arithmetic {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter an integer: ");
int n = scanner.nextInt();
int opposite = n*-1;
System.out.println("The opposite of" n "is" opposite);
int twoTimes = n*2;
System.out.println(n "doubled is" twoTimes);
int half = n/2;
System.out.println("half of "n "is" half);
int square= n*n;
System.out.println(n "squared is" square);
int reciprocal= 1/n;
System.out.println("the reciprocal of" n "is" reciprocal);
double fraction = n*.10;
double fractionTwo = fraction*fraction;
System.out.println("one-tenth of" n "is" fraction "and" fraction "squared is" fractionTwo);
// int lastDigit =
// System.out.println();
int sum= n+1;
int sumTwo= n+2;
int sumTotal= sum + sumTwo;
System.out.println("the sum of" n "and" sum "and" sumTwo "is" sumTotal);
}
}
**also if anybody would like to help me figure out the "n+1"/"n+2" formula and how to format that in code that would be appreciated!
There's a few mistakes with this code.
You're not concatenating correctly on any of your print to consoles.
System.out.println("The opposite of" n "is" opposite);
should be:
System.out.println("The opposite of" + n + "is" + opposite);
When we want to combine Strings we use the + sign.
int reciprocal= 1/n; will not work;
it should be double reciprocal= 1.0/n; assuming that n is an int.
"n+1"/"n+2" would simply be: double result = (n + 1.0) / (n + 2.0); assuming that n is an int.
That's not how you concatenate (link) two strings!
This code, and other similar ones,
System.out.println(n "doubled is" twoTimes);
are wrong.
I think you want to link n, "doubled is" and twoTimes together, right?
Right now you are linking them with spaces. But space characters in Java doesn't concatenate strings. So that's why the compiler complained.
In Java, + is both used to do addition and concatenation of strings! So you should change the above to:
System.out.println(n + "doubled is" + twoTimes);
But wait! Where have your spaces gone? This is because + doesn't automatically adds a space for you, you need to add it yourself.
System.out.println(n + " doubled is " + twoTimes);
Alternatively, you can use String.format to format your string. This
/* Explanation: n will be "inserted" to the first %d and twoTimes will
be inserted to the second %d. And %d basically means "express the thing in
decimal"*/
String.format("%d doubled is %d", n, twoTimes)
is the same as
n + " doubled is " + twoTimes
Regarding your formula question:
In Java, there are two different number types, int and double. (There are actually a lot more, but they're irrelevant) int and double do different things when they are divided. And they have different literals.
5 is an int literal, 5.0 is a double literal. See? Numbers without decimal places are ints and those with decimal places are called doubles.
So what's wrong with your formula? Let's first take a look at what the is the result of dividing int and double
int / int: 1 / 5 = 0
int / double: 1 / 5.0 = 0.2
double / int: 1.0 / 5 = 0.2
double / double: 1.0 / 5.0 = 0.2
int / 0: 1 / 0 = Exception!
double / 0: 1.0 / 0 = NaN
In your code:
int reciprocal= 1/n;
and other similar lines, you are doing division of int. So that's why the above code doesn't work. What you should do is change one of the numbers to a double! And also change the type to double.
double reciprocal = 1.0 / n;
------ ---
changes here as well!
I wrote a program to calculate the PI number with Leibniz formula:
[
I wrote a for-loop with type of initialization is "int" , the loop works fine but when i changed the initialization type to "long" the result is changed. This only happens when the loop times over a billion. This makes the "int - loop" calculates PI more accurate than "long - loop". I don't know why this happens. Please help me to understand this issue. Thanks! and here is my code.
public static void main(String[] args) {
double result1 = 0;
double result2 = 0;
double sign = 1;
for (int i = 0; i <= 1607702095; i++) {
result1 += sign/(2 * i + 1);
sign *= -1;
}
sign = 1;
for (long j = 0; j <= 1607702095; j++) {
result2 += sign/(2 * j + 1);
sign *= -1;
}
System.out.println("result1 " + result1 * 4);
System.out.println("result2 " + result2 * 4);
System.out.println("pi " + Math.PI);
}
And the result is:
result1 3.141592653576877
result2 3.1415926529660116
pi 3.141592653589793
Actually, your first loop would have int overflow in the calculation of (2 * i + 1) when i is large enough, so I wouldn't rely on the output of it.
The second loop, on the other hand, produces a more correct output, since (2 * j + 1) doesn't overflow, since it performs long multiplication.
This makes the "int - loop" calculates PI more accurate than "long - loop"
That's probably just a coincidence, since the calculations in the int loop overflow.
Because you are getting overflow at the line
result1 += sign/(2 * i + 1);
Where the value of 2*i cross the max integer value
int range is -2,147,483,648 to 2,147,483,647 but when you do 2*i for greater value it crosses that range.
Better to be stick with long and that gives you correct output.
2 * i when i is close to the end of your loop will overflow the max value for an int which is 2147483647.
Using a long that operation doesn't overflow.
The correct procedure is using a long type. Probably because values are added and removed around the correct PI for some strange behavior the overflows momentarily compute to a value closer to the right PI.
I suppose that change the limit of the for loop of few values will change the final result to a value that is more far from the right PI.
You have integer overflow.
The max capacity of a signed int is (2^31)-1, or 2,147,483,647.
(1,607,702,095 * 2) is 3215404190, which is bigger than 2,147,483,647.
When you change i to a long you increase the capacity of i to (2^63)-1.
Noticed everyone is pointig the integer overflow, but you might want a solution. (If you already have one, please ignore the following :) )
Having the overflow in the (2 * i + 1) part of the code, you should max the i in the for loop to (Integer.MAX_VALUE / 2 - 1), which results in:
for (int i = 0; i <= (Integer.MAX_VALUE / 2 - 1); i++) {
result1 += sign/(2 * i + 1);
sign *= -1;
}
You can also do that to the long part with (Long.MAX_VALUE / 2 - 1) but it will be running for a VERY LONG time.