I have this algorithm that works, but I want to change it to have a dynamic ratio in order to have the distance of values for the first positions higher than those ones for the lastest positions.
So for instance if prize money = 1000, total_prizes = 5, last_prize = 50 I got:
1) 350.00
2) 275.00
3) 200.00
4) 125.00
5) 50.00
TOTAL SUM: 1000.00
What I would like to see should be:
1) 475.00
2) 250.00
3) 150.00
4) 75.00
5) 50.00
TOTAL SUM: 1000.00
Instead of having between positions always a fixed value of 75. Have an increase distance approaching the first positions, in this case
from 5) to 4) 25
from 4) to 3) 75
from 3) to 2) 100
from 2) to 1) 225
Here the current code:
public static void main(String[] aa){
float ratio;
float first_prize;
float s=0;
float money = 1000;
int total_prizes = 5;
float last_prize = 50;
float prizes[] = new float[total_prizes+1];
first_prize=2*(money/total_prizes)-last_prize; //last member of the progresion
ratio=(first_prize-last_prize)/(total_prizes-1);
prizes[total_prizes]=last_prize;
for (int j = total_prizes-1; j >=1; j--) {
prizes[j]=prizes[j+1]+ratio;
}
for(int k=1;k<=total_prizes;k++){
System.out.printf("%d) %.2f\n",k,prizes[k]);
s+=prizes[k];
}
System.out.printf("TOTAL SUM: %.2f\n",s);
}
Inside the loop:
for (int j = total_prizes-1; j >=1; j--) {
//ratio here should be calculated dynamically based on position...
prizes[j]=prizes[j+1]+ratio;
}
Thanks! :)
If I understand you, what you want is to have the following conditions:
Fixed total sum. In this case 1000.
Approximately a geometric ratio r with n terms. In this case 1.75.
All "round" numbers. In this case to the nearest 25.
I would suggest that you solve it by first creating an exact geometric sequence, and then tweak it to be round numbers.
The first step is easy because all geometric series with n terms look like this:
x + r * x + r^2 * x + ... + r^(n-1) * x
= x * (1 + r + r^2 + ... + r^(n-1))
= x * (1 + r + r^2 + ... + r^(n-1)) * (r - 1) / (r - 1)
= x * ((r - 1) + (r^2 - r) + (r^3 - r^2) + ... + (r^(n) - r^(n-1)) / (r - 1)
= x * (-1 + (r - r) + (r^2 - r^2) + ... + (r^(n-1) - r^(n-1)) + r^n) / (r - 1)
= x * (r^n - 1) / (r - 1)
So in we want
1000 = x * (r^n - 1) / (r - 1)
= x * (1.75^5 - 1) / (1.75 - 1)
= x * (16.4130859375 - 1) / 0.75
= 20.55078125 x
That gives us the following starting solution.
48.6599505797377
85.154913514541
149.021098650447
260.786922638282
456.377114616993
After that it is a question of tweaking those numbers up and down to get the answer that you want. There are a lot of ways you can do that. One is simply to start with the smallest and move it to a rounded number, and redistribute among the others in proportion to their weights, and continue. That gives you the following sequence of partial answers.
48.6599505797377
85.154913514541
149.021098650447
260.786922638282
456.377114616993
50
85.034965034965
148.811188811189
260.41958041958
455.734265734266
50
75
150.537634408602
263.440860215054
461.021505376344
50
75
150
263.636363636364
461.363636363636
50
75
150
275
450
This is not exactly your desired answer. But it is pretty darned close and hopefully acceptable as a strategy.
UPDATE I had tried 1.75 because it was close to (475/50)^(1/4). When I tried 1.8 instead I got your exact desired answer.
Furthermore note that we do not need to produce all of those intermediate answers. Each time we only need the smallest term. Which is given by target * (r-1) / (r^n - 1). Every time you find the smallest term, you subtract that from the target, reduce n by one, and repeat.
Related
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.
I was asked this in an interview.
I was asked to compute the average of numbers x1,x2,x3,...xn
class Iterator {
bool hasNext;
int getNext();
}
// So it came down to something like this:
double average (Iterator & it) {
double average = 0;
double sum = 0;
int len = 0;
while (it.hasNext == true) {
sum += it.getNext();
}
if (len > 0)
average = sum / len;
}
The interviewer said the list size is unkown and it can be very big, so sum can overflow. He asked how do I solve the overflow problem, I answered by keeping track of how may times we exceed the max number and so forth, he said something about pushing into stack, the average and length, I never really understood his solution by pushing these 2 variables into some sort of list? Anyone has a clue?
I don't know about using a stack, but with some help from algebra, we can derive a formula for the new average, using the old average.
Let's say you have already averaged n - 1 items, and you have that average in oldAvg.
oldAvg = (x1 + x2 + .. + xn - 1) / (n - 1)
The new average would be represented by newAvg:
newAvg = (x1 + x2 + .. + xn - 1 + xn) / n
With some algebraic manipulation, we can represent the new average using the old average the number of items averaged, and the next item.
newAvg = (x1 + x2 + .. + xn - 1) / n + xn / n
= ((n - 1)/(n - 1)) * (x1 + x2 + .. + xn - 1) / n + xn / n
= oldAvg / n * (n - 1) + xn / n
This can avoid overflow by dividing by n before multiplying by n - 1. Then all you have to do is add in the next item, xn, divided by n.
The first loop would establish the average as equal to the first element, but each subsequent loop would use the formula above to derive the new average.
n++;
newAvg = oldAvg / n * (n - 1) + it.next() / n;
He was probably referring to the fact that you don't need all the terms to compute an average, you can instead keep track of a moving average. That can be used along with the number of terms so far considered to come up with the sum of the terms.
Since the total could be too large to store as a long, you'd want to use something like a BigInteger to hold the total.
If you simplify rgettman's formula further you will get following:
len++;
average = average + (it.next() - average) / len;
I'm trying to make a program that calculates the required score to level in a game and the equation works fine on my calculator but not when i try changing it to work with java.
the equation is 5,000 / 3 * (4n^3 - 3n^2 - n) + 1.25 * 1.8^(n - 60) for example level 49 you should need to have a total score of 772240000 points and the calculator gives this answer but my java program doesn't. here is the code i tried.
for (int i = 0; i <= 100; i++) {
double score = (double) ((5000 / 3) * (Math.pow(4 * i, 3) - Math.pow(3 * i, 2) - i) + (1.25 * Math.pow(1.8, i - 60)));
System.out.println("Level " + i + " requires " + (long) score);
}
This doesnt seem to work right and gives 12513130000 as the required points for lvl 49. If anyone can get it to work would you miind explaining what i did wrong.
You're messing up your Math.pow calls, but you can avoid some of them entirely:
double score = (double) ((5000 / 3) * (4 * i * i * i - 3 * i * i - i) + (1.25 * Math.pow(1.8, i - 60)));
Here's what's wrong: Math.pow(4 * i, 3) is actually (4i)^3 and not 4(i^3). To do the latter, you would need the following:
4 * Math.pow(i, 3)
I'm not entirely sure about the integer division part (you are casting it to double), but you may have to change 5000 / 3 to 5000.0 / 3.
Your problem is inside Math.pow - you're multiplying your index value by a scalar each time.
4 * Math.pow(i, 3)
And
3 * Math.pow(i, 2)
Should fix it.
Edit: And the integer division mentioned in other answers.
This easy program program computes an estimate of pi by simulating dart throws onto a square.
Сonditions: Generate a random floating-point number and transform it so that it is between -1 and 1.
Store in x. Repeat for y. Check that (x, y) is in the unit circle, that is, the distance between (0, 0) and (x, y) is <= 1.
After this, need to find the ratio hits / tries is approximately the same as the ratio circle area / square area = pi / 4. (square is 1 per 1).
Code:
public class MonteCarlo {
public static void main(String[] args)
{
System.out.println("Number of tries");
Random generator = new Random(42);
Scanner in = new Scanner(System.in);
int tries = in.nextInt();
int hits = 0;
double x, y;
for (int i = 1; i <= tries; i++)
{
// Generate two random numbers between -1 and 1
int plusOrMinus = generator.nextInt(1000);
if (plusOrMinus > 500) x = generator.nextDouble();
else x = -generator.nextDouble();
plusOrMinus = generator.nextInt(10000);
if (plusOrMinus > 5000) y = generator.nextDouble();
else y = -generator.nextDouble();
if (Math.sqrt((x * x) + (y * y)) <= 1) // Check whether the point lies in the unit circle
{
hits++;
}
}
double piEstimate = 4.0 * hits / tries;
System.out.println("Estimate for pi: " + piEstimate);
}
}
Testing output:
Actual output Expected output
-----------------------------------------------
Number of tries Number of tries
1000 1000
- Estimate for pi: 3.176 Estimate for pi: 3.312
Actual output Expected output
-----------------------------------------------------
Number of tries Number of tries
1000000 1000000
- Estimate for pi: 3.141912 Estimate for pi: 3.143472
Maybe, does exist other approaches to find this solution?
Any suggestions.
For generating the random double between -1 and 1, try:
generator.nextDouble() * 2 - 1
BTW: If you keep initializing your random with a static seed, you'll always get the same result. Otherwise, if you are concerned that your result is not good enough, keep in mind that the Monte Carlo is only an approximation. After all, it's based on random numbers, so the result will vary from the sample solution ;-)
A generalized solution to turn a Uniform(0,1) into a Uniform(a,b) (where a < b) is
(b - a) * generator.nextDouble() + a
As #winSharp93 pointed out, you should expect variation but you can quantify the margin of error as a statistical confidence interval. If you calculate
halfWidth = 1.96 * Math.sqrt(piEstimate * (4.0 - piEstimate) / tries);
then the actual value of pi should fall between piEstimate - halfWidth and piEstimate + halfWidth 95% of the time. You can see from the halfWidth calculation that the range containing pi will shrink (but not linearly) as the number of tries is increased. You can adjust the confidence level from 95% to other values by replacing 1.96 with an alternative scale value out of a Standard Normal table.
Product A costs $10 , B costs $3 and C costs $0.50.
A person bought 100 items for $100. How many of each item did the person buy.
I found the answer as-
94 * 0.5 = 47
1 * 3 = 3
5 * 10 = 50
But I am not able to implement it in java as the solution I got the result from Hit and Trial.
What will be the algorithm for solving this problem
Plain brute-force:
for (int i1 = 0; i1 <= 10; i1++) {
for (int i2 = 0; i2 < 34; i2++) {
int i3 = 100 - i2 - i1;
int total = i1 * 10 + i2 * 3 + i3 / 2;
if (total == 100 && i3 % 2 == 0)
System.out.println(i1 + " * 10 + " + i2
+ " * 3 + " + i3 + " * 0.5 = 100");
}
}
Gives two answers:
0 * 10 + 20 * 3 + 80 * 0.5 = 100
5 * 10 + 1 * 3 + 94 * 0.5 = 100
P.S. of course, it's not the optimal solution, but for just three items and 100 total amount - it's fine (and optimal from the point of time required to code it).
You need to implement your algorithm for solving these two equations
A + B + C = 100 -----------(1)
10A + 3B + 0.5C = 100 -----------(2)
From(2), we can figure out that:
C = 100 - A - B
Substitue this information in (2)
10A + 3B + 0.5 * ( 100 - A - B) = 100
This reduces to
19A + 5B = 100
Then you can deduct that:
B = 20 - (19A/5)
Now,try to find out (using an int loop) for what "whole" value of A, will B become a whole value ( as normally in such problems, you always buy whole commodities -like fruits no fractions)
You will find that when A=5, B=1.
Keep solving the equation this way, and replace A, B and C with Java variables and you will be able to proivide a solution.
Both solutions can be found very easily. ring bearer already gave almost the entire way of doing this. ring bearer ended with:
B = 20 - (19A/5)
We know something else, though:
A, B, and C are all non-negative integer values.
This means 19A/5 has to be (1) an integer (else B would not be an integer), and (2) at most 20 (else B would be negative). This means for (1), that A has to be a multiple of 5, and for (2), that A has to be at most 5.
Also note that the requirement 19A/5 <= 20 can be rewritten as:
19A <= 100
There are only two values for A that satisfy this: 0 and 5. A very fast way to find all solutions then would be to do something like:
for (A = 0; 19*A <= 100; A += 5)
{
// Show the solution for this value of A (with B = 20 - 19A/5 and C = 100 - A - B).
}
This is a variant of the knapsack problem and you can look for a dynamic-programming based solution, which cab be better than brute force (in terms of computational complexity). A simple search yielded links like this