TheAlgorithms/Java · error · IllegalArgumentException

Time step must be positive.

Error message

Time step must be positive.

What it means

Thrown by DampedOscillator.stepEuler when dt <= 0. The Euler integration step advances the state by dt; a non-positive time step produces no forward progress (dt = 0 yields the identical state) or reverses integration (dt < 0), both of which corrupt a time-marching simulation. This is the second guard, checked after the state-array validation.

Source

Thrown at src/main/java/com/thealgorithms/physics/DampedOscillator.java:87

        double omegaD = Math.sqrt(Math.max(0.0, omega0 * omega0 - gamma * gamma));
        return amplitude * Math.exp(-gamma * time) * Math.cos(omegaD * time + phase);
    }

    /**
     * Performs a single integration step using the explicit Euler method.
     * State vector format: [x, v], where v = dx/dt.
     *
     * @param state the current state [x, v]
     * @param dt    the time step (seconds)
     * @return the next state [x_next, v_next]
     * @throws IllegalArgumentException if the state array is invalid or dt is non-positive
     */
    public double[] stepEuler(double[] state, double dt) {
        if (state == null || state.length != 2) {
            throw new IllegalArgumentException("State must be a non-null array of length 2.");
        }
        if (dt <= 0) {
            throw new IllegalArgumentException("Time step must be positive.");
        }

        double x = state[0];
        double v = state[1];
        double acceleration = -2.0 * gamma * v - omega0 * omega0 * x;

        double xNext = x + dt * v;
        double vNext = v + dt * acceleration;

        return new double[] {xNext, vNext};
    }

    /** @return the natural (undamped) angular frequency (rad/s). */
    public double getOmega0() {
        return omega0;
    }

    /** @return the damping coefficient (s⁻¹). */

View on GitHub (pinned to fdfb9a395b)

Solutions

  1. Pass a strictly positive dt (e.g. 1e-3 or 1e-4 for stiff systems).
  2. In a time-marching loop, clamp the final step: double step = Math.min(dt, tEnd - t); only call stepEuler when step > 0.
  3. Validate dt at the boundary where the integration schedule is configured.

Example fix

// before
double[] next = osc.stepEuler(state, tEnd - t);
// after
double step = tEnd - t;
if (step <= 0) break;
double[] next = osc.stepEuler(state, step);
Defensive patterns

Strategy: validation

Validate before calling

double step = dt;
if (step <= 0) {
    throw new IllegalStateException("integration step resolved to non-positive dt");
}
double[] next = osc.stepEuler(state, step);

Prevention

When it happens

Trigger: Calling stepEuler(state, 0) or stepEuler(state, negativeValue). Commonly happens when dt is computed as an end-minus-start difference that resolves to zero, or when a step counter runs past the loop bound producing a negative remainder.

Common situations: Adaptive step code that undershoots to dt = 0 at the final step, a loop where (tEnd - t) becomes negative in the last iteration, or a config default of 0.

Related errors


AI-assisted analysis of TheAlgorithms/Java@fdfb9a395b (2026-08-13). Data as JSON: /api/errors/a666d43b9ef8b987. Report an issue: GitHub.