Skip to content

Instantly share code, notes, and snippets.

@giordi91
Created September 29, 2018 20:39
Show Gist options
  • Save giordi91/ae258be869fec7e8c27c3d8357d09a3d to your computer and use it in GitHub Desktop.
Save giordi91/ae258be869fec7e8c27c3d8357d09a3d to your computer and use it in GitHub Desktop.

Revisions

  1. giordi91 created this gist Sep 29, 2018.
    85 changes: 85 additions & 0 deletions bisect root finder
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,85 @@
    #pragma once
    #include <limits>

    namespace cpp_tools {
    namespace numerical {

    template <typename T> using singleVariableFunction = float (*)(T xValue);
    struct ErrorReport {};

    template <typename T>
    inline bool ensureRangeSign(T startRange, T endRange,
    singleVariableFunction<T> function) {
    T yStart = function(startRange);
    T yEnd = function(endRange);
    return (!((yStart > 0) & (yEnd > 0))) & (!((yStart < 0) & (yEnd < 0)));
    }

    template <typename T>
    inline bool rootValueMeetsAccuracyRequirements(T startRange, T endRange,
    int accuracy) {
    float denominator = powf(10.0f, accuracy);
    float thresholdFloat = 1.0f / denominator;
    return abs(endRange - startRange) < thresholdFloat;
    }

    template <typename T>
    inline T processFinalResultRounding(T startRange, T endRange,
    singleVariableFunction<T> function,
    ErrorReport *report) {
    T midRange = (startRange + endRange) * 0.5f;

    T midRangeFloor = (std::floorf(midRange*1000.0f)) / 1000.0f;
    T midRangeCeil= (std::ceilf(midRange*1000.0f)) / 1000.0f;

    T midRangeFloorCeil = (midRangeFloor+ midRangeCeil) * 0.5f;

    bool lowSplit = ensureRangeSign(midRangeFloor, midRangeFloorCeil, function);
    return lowSplit ? startRange : endRange;
    }

    template <typename T>
    T singleBisectRootFinder(T startRange, T endRange, singleVariableFunction<T> function,
    int accuracy, int maxIteration = 100,
    ErrorReport *errorReport = nullptr) {
    const T nanValue = std::numeric_limits<T>::quiet_NaN();
    if (!ensureRangeSign<T>(startRange, endRange, function)) {
    return nanValue;
    }

    T midRange = (startRange + endRange) * 0.5f;
    // lets start the iteration
    T currentValue = function(midRange);

    if (rootValueMeetsAccuracyRequirements(startRange, endRange, accuracy)) {
    return processFinalResultRounding(startRange, endRange, function, errorReport);
    }

    bool lowSplit = ensureRangeSign(startRange, midRange, function);
    bool highSplit = ensureRangeSign(midRange, endRange, function);
    startRange = lowSplit ? startRange : midRange;
    endRange = highSplit ? endRange : midRange;

    int iteration = 1;
    while (true & (iteration < maxIteration)) {

    if (rootValueMeetsAccuracyRequirements(startRange, endRange, accuracy)) {
    return processFinalResultRounding(startRange, endRange, function, errorReport);
    }

    midRange = (startRange + endRange) * 0.5f;
    // lets start the iteration
    currentValue = function(midRange);

    bool lowSplit = ensureRangeSign(startRange, midRange, function);
    bool highSplit = ensureRangeSign(midRange, endRange, function);
    startRange = lowSplit ? startRange : midRange;
    endRange = highSplit ? endRange : midRange;
    iteration++;
    }

    T returnValue = midRange;
    return returnValue;
    }
    } // namespace numerical
    } // namespace cpp_tools