Yone
Yone

Reputation: 2134

How could we calculate traveled distance, with big numbers‽

I am currently solving this kata: "How far I will go?"!

The description says:

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.

Input:
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

Answers (1)

Malt
Malt

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

Related Questions