Reputation: 2134
I am currently solving this kata: "How far I will go?"!
The description says:
Input:You have recently discovered that horses travel in a unique pattern - they're either running (at top speed) or resting (standing still).
Here's an example of how one particular horse might travel:
The horse Blaze can run at 14 metres/second for 60 seconds, but must then rest for 45 seconds.
After 500 seconds Blaze will have traveled 4200 metres.
Your job is to write a function that returns how long a horse will have traveled after a given time.
totalTime - How long the horse will be traveling (in seconds)
runTime - How long the horse can run for before having to rest (in seconds)
restTime - How long the horse have to rest for after running (in seconds)
speed - The max speed of the horse (in metres/second)
I have already done the calculus by hand:
Given: speed = 14, runTime = 60, restTime = 45, totalTime = 500
-> To calculate how much time does the horse run we calculate the following:
totalTime / (runTime + restTime) = 500 / (60 + 45) = 500 / 105 = 4.76... roundUp(totalTime) = 5
totalRunTime = 5 * runTime = 5 * 60 = 300
--> To calculate how much distance has the horse traveled:
x = speed * totalRunTime = 14 * 300 = 4200
I have translated it as the following code:
public class Kata {
public static int travel(int totalTime, int runTime, int restTime, int speed) {
int totalRunTime = 0;
if(totalTime < runTime){
totalRunTime = totalTime;
}else{
totalRunTime = (int)Math.ceil( (double)totalTime/(runTime + restTime) ) * runTime;
}
return speed * totalRunTime;
}
}
When we run the basic tests it gives the expected output:
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;
public class KataTest {
@Test
public void exampleTests() {
assertEquals(4200, Kata.travel(500, 60, 45, 14));
assertEquals(1120, Kata.travel(1000, 10, 127, 14));
assertEquals(1000, Kata.travel(100, 10, 0, 10));
assertEquals(1000, Kata.travel(100, 10, 0, 10));
assertEquals(450, Kata.travel(25, 50, 120, 18));
}
}
However when we test it with the advanced examples, with bigger numbers, it shows unaccurate results.
For example:
Given: speed = 6, runTime = 34, restTime = 180, totalTime = 99094; the expected output is 94524, however the code I posted gives us 94656
I have written the trace by hand to understand what my code does:
-> To calculate the total time this horse runs:
totalTime / (runTime + restTime) = 99094 / (34 + 180) = 99094 / 214 = 463.05... roundUp(totalTime) = 464
totalRunTime = 464 * runTime = 464 * 34 = 15776
--> To calculate how far has the horse traveled:
x = speed * totalRunTime = 6 * 15776 = 94656
So then the test which fails is:
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.runners.JUnit4;
public class KataTest {
@Test
public void biggerTests() {
assertEquals(84954920, Kata.travel(35869784, 90, 100, 5));
}
}
I have the intuition that the code has to be improved in the conversion from double to int or in the rounding with Math.ceil, but I don't know why or how to solve it. Here is the line I think we could improve:
totalRunTime = (int)Math.ceil( (double)totalTime/(runTime + restTime) ) * runTime;
I have also read:
Upvotes: 1
Views: 181
Reputation: 30305
The problem isn't with the rounding.
Let's look at the example travel(35869784, 90, 100, 5)
.
According to your formula 35869784/(100+90) = 188788.336
, rounding up gives us 188789, multiplying by runTime
, and by speed
gives us 84,955,050 meters while the right answer is 84,954,920. This isn't a rounding problem. The formula is wrong.
Why? Consider the run after the last rest. The horse already ran 188,788 full iterations of 90s + 100s, during which it covered a distance of 84,954,600 meters over 35,869,720 seconds. After those "full" runs, the horse now has only 64 seconds left to run, which is less than runTime
!
How far does the horse run in 64 seconds? 320 meters. So the total is 84,954,600 + 320 = 84,954,920
meters.
Upvotes: 2