0
 public static void main(String[] args) {
    double s = 0; //Position
    double v = 100; //Velocity
    double g = 9.81; //Gravitational Force

    for(double time = 0.01; time < 100; time = time + 0.01){
       double DELTA_T = 0.01;
        s = s + (v * DELTA_T);
        v = v - (g * DELTA_T);

        if(time % 1 == 0) { //I want to print this out, but it seems to end the program with no output
            System.out.println("Seconds: " + time);
            System.out.println("Position: " + s);
            System.out.println("Velocity: " + v);
        }
    }
}

I want to output the calculations when (time % 1 == 0). But when I run this, it doesn't print anything out. When I remove the if statement, and leave in the print statements, it will print.

I was wondering what is wrong with my if statement and how would I go about trying to print "s", "v", and "time" every time (time % 1 == 0)

Nexevis
  • 4,647
  • 3
  • 13
  • 22
poop
  • 57
  • 6
  • 3
    @Code-Apprentice: You're gonna need to justify why this was reopened. This is a ***classic*** pitfall of floating-point math. – Makoto Mar 03 '20 at 20:29
  • So every time the loop occurs, "time" will be incremented by 0.01. So when "time" loops 100 times, "time" will equal 1. 1 % 1 = 0 because there will be no remainder. So when 1 % 1 = 0, it should print out the print statements. – poop Mar 03 '20 at 20:29
  • @Makoto That isn't the problem here. The problem is using the modulus operator to test whether a floating point number is integral. – David Conrad Mar 03 '20 at 20:30
  • @DavidConrad: So we're just gonna ignore the part where the OP also adds 0.01 to their number and hopes that'll get them to 100? – Makoto Mar 03 '20 at 20:31
  • 1
    The modulus operator would work here if not for floating point imprecision. For example, `1.5 % 1 == 0.5` and `1.0 % 1 == 0`, but the value of `time` here is going to be `1.0000000000000007` instead of `1.0`. – kaya3 Mar 03 '20 at 20:32
  • @Makoto Absolutely. It will certainly go over 100 at some point, and that isn't the problem here, even though it isn't a good way to implement the loop. – David Conrad Mar 03 '20 at 20:32
  • I just put (time < 100) in the for loop as a placeholder value to end the loop when time = 100. Is that what is wrong with my code? – poop Mar 03 '20 at 20:32
  • @poop No, although the time will never be equal to 100 since 0.01 is not exactly representable as binary floating point. But it will *exceed* 100 at some point. – David Conrad Mar 03 '20 at 20:33
  • @poop If I understand correctly, you want to print when `time` is a whole number, which should be every 100 iterations. You should use an `int` to count this instead of using `double` as you are now. See my answer below. – Code-Apprentice Mar 03 '20 at 20:34
  • 2
    @DavidConrad: There's also the part where if we add 0.01 to a number, hoping that it will go odd, too. That's, uh, an obvious call out to certain floating point numbers not being exactly representable. I'm unconvinced that this isn't a dupe. – Makoto Mar 03 '20 at 20:35
  • @Makoto The answer to the dupe doesn't talk about modulus and thus would not address the central problem OP is having here. That's pretty much the definition of 'not a duplicate.' – David Conrad Mar 03 '20 at 20:36
  • 2
    The answer to the dupe applies perfectly; if you change the condition to `time % 1 < 0.01` instead of using `==` to compare it, then you'll see the correct results. Your solution in this case also appears in a [highly-upvoted answer](https://stackoverflow.com/a/2607316/12299000) to the dupe: *"decimal representation errors can be avoided by scaling."* – kaya3 Mar 03 '20 at 20:37
  • @Makoto I reopened the question in order to address the specifics here. I agree that the issues with floating point math are the issue and that particular question is related, but I don't think the OP can easily get to a working solution from the information posted there. – Code-Apprentice Mar 03 '20 at 20:38
  • At the very least the title should be changed, it is literally completely meaningless. – Nexevis Mar 03 '20 at 20:38
  • Ah thank you @Code-Apprentice. That solution helped me out. I should have been using integers rather than doubles. I guess I need to read up on floating point imprecision as well. Thank you all for helping. – poop Mar 03 '20 at 20:40
  • @Code-Apprentice: You can do the same epsilon-bound comparison as shown in the answer and have the same solution. Don't assume the OP isn't capable of deducing something like this on their own since they had all of thirty seconds to process it. – Makoto Mar 03 '20 at 20:41

2 Answers2

-1

The problem here is most likely because you are comparing equality of floating point values. See Is floating point math broken? for an introduction to the problems we encounter with floating point math and equality comparison.

For your specific problem, I suggest that you use an integer counter that represents hundredths of a second. Then you can do your comparison with integers instead:



 public static void main(String[] args) {
    double s = 0; //Position
    double v = 100; //Velocity
    double g = 9.81; //Gravitational Force

    for(int time = 1; time < 10000; time++) {
        double DELTA_T = 0.01;
        s = s + (v * DELTA_T);
        v = v - (g * DELTA_T);

        if(time % 100 == 0) { //I want to print this out, but it seems to end the program with no output
            System.out.println("Seconds: " + time);
            System.out.println("Position: " + s);
            System.out.println("Velocity: " + v);
        }
    }
}

This will solve your printing problem. However, you will most like see that s and v will not have the correct values. This is because you are accumulating errors in the floating point math over each iteration. You should calculate these directly from time on each iteration, rather than the way you are doing it now.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • It probably doesn't matter much, but you've changed the number of times the loop will execute since it used to start at 0.01, not 0. Starting from 1 would be closer to the original intent of the code. – David Conrad Mar 03 '20 at 20:34
  • 1
    @DavidConrad Good point. The OP will have to determine if that is an off-by-one error or not. – Code-Apprentice Mar 03 '20 at 20:36
-1

Your time variable precision is ruining your modulo check. You need to multiply and cast to an int get a good result:

public static void main(String [] args {
    double s = 0; //Position
    double v = 100; //Velocity
    final double g = 9.81; //Gravitational Force
    final double DELTA_T = 0.01;

    for(double time = 0.01; time < 100; time += 0.01){
        s += (v * DELTA_T);
        v -= (g * DELTA_T);

        System.out.println(time);
        if (((int) (time * 100)) % 100 == 0) { 
            System.out.println("Seconds: " + time);
            System.out.println("Position: " + s);
            System.out.println("Velocity: " + v);
        }
    }
}
Ryan
  • 1,762
  • 6
  • 11