Commit fbc89b70 authored by Jason Rhinelander's avatar Jason Rhinelander

Stepper: added a max_step (defaulting for 0.5)

The default max_step means whatever is being stepped increases by (at
most) 50% and decreases by (at most) 33% in a single step.  Without
this, initial conditions far off the equilibrium have a tendency to
massively overshoot the equilibrium.
parent cac1b218
......@@ -119,6 +119,7 @@ class Stepper final {
static constexpr double default_initial_step = 1.0/32.0;
static constexpr int default_increase_count = 4;
static constexpr double default_min_step = std::numeric_limits<double>::epsilon();
static constexpr double default_max_step = 0.5;
static constexpr bool default_relative_steps = true;
/** Constructs a new Stepper object.
......@@ -142,6 +143,9 @@ class Stepper final {
* machine epsilon (i.e. the smallest value v such that 1 + v is a value distinct from 1),
* which is the smallest value possible for a step.
* \param max_step is the maximum step size that can be taken. The default is equal to 0.5,
* corresponding to an an increase of 50% or a decrease of 33% (when `rel_steps` is true).
* \param rel_steps specifies whether the steps taken are relative to the current value, or
* absolute changes. The default (relative steps) is suitable for things like prices and
* quantities, when relative changes are more important than absolute values; specifying
......@@ -153,6 +157,7 @@ class Stepper final {
Stepper(double initial_step = default_initial_step,
int increase_count = default_increase_count,
double min_step = default_min_step,
double max_step = default_max_step,
bool rel_steps = default_relative_steps);
/** Called to signal that a step increase (`up=true`) or decrease (`up=false`) should be
......@@ -180,6 +185,9 @@ class Stepper final {
/// The minimum (relative) step size allowed, specified in the constructor.
const double min_step;
/// The maximum (relative) step size allowed, specified in the constructor.
const double max_step;
/** If true, steps are relative; if false, steps are absolute.
* For example, a relative step size of 1/10 results in a step to either 11/10 or 10/11 for
#include <eris/algorithms.hpp>
namespace eris {
Stepper::Stepper(double step, int increase_count, double min_step, bool rel_steps)
: increase(increase_count), min_step(min_step), relative_steps(rel_steps), step_size(step) {}
Stepper::Stepper(double step, int increase_count, double min_step, double max_step, bool rel_steps)
: increase(increase_count), min_step(min_step), max_step(max_step), relative_steps(rel_steps), step_size(step) {}
double Stepper::step(bool up) {
bool first_time = same == 0;
......@@ -16,11 +16,16 @@ double Stepper::step(bool up) {
step_size /= 2;
if (step_size < min_step) step_size = min_step;
else if (same >= increase) {
else if (same >= increase and step_size < max_step) {
// We've taken several steps in the same direction, so double the step size
step_size *= 2;
if (step_size > max_step) step_size = max_step;
// We just doubled the step size, so, in terms of the new step size, only half of the
// previous steps count as increasing steps:
// previous steps count as increasing steps. This could be slightly off if we had to
// correct to the max_step size, but in that case the value of same won't matter anyway,
// since we won't be increasing step size any more.
same /= 2;
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment