Last active
April 27, 2022 18:51
-
-
Save literallylara/d4b43517060638395e5dc6acfb1fc43f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Performs a recursive binary search upon the interval [min,max] | |
* where `getDirection()` determines the direction of the current value | |
* in relation to the reference value. | |
* | |
* Due to the properties of this algorithm, | |
* reaching the solution will always take less than `⌈log₂(max-min)⌉` steps. | |
* | |
* @author Lara Sophie Schütt (@literallylara) | |
* @license MIT | |
* | |
* @param {Number} opts.min | |
* The minimum, or left side of the interval | |
* @param {Number} opts.max | |
* The maximum, or right side of the interval | |
* @param {Number} [opts.bias=1] | |
* The bias that defines the maximum allowed offset from the target value | |
* @param {Boolean} [opts.round=false] | |
* Whether or not to round the value including the argument to `getDirection()` | |
* @param {Number} [opts.maxSteps=Infinity] | |
* Tne maximum number of recursive calls this function is allowed to make | |
* @param {Function} opts.getDirection | |
* The return value of this function determines the direction of the | |
* current value in relation to the reference value: | |
* - ` 0` - currentValue = referenceValue | |
* - `-1` - currentValue < referenceValue | |
* - `+1` - currentValue > referenceValue | |
* | |
* It receives one argument representing the best guess for the target value | |
* and is called once per iteration | |
* @returns {{ | |
* value: Number, | |
* steps: Number, | |
* aborted: Boolean, | |
* below: Boolean | |
* }} | |
* | |
* - `value` - The target value ± bias / 2 | |
* - `steps` - The amount of steps it needed to converge to `value` | |
* - `aborted` - Whether or not the recursive loop was aborted due to reaching `maxSteps` | |
* - `dir` - The direction of the current value in relation to the reference value (see `getDirection()`) | |
*/ | |
export function binarySearch({ | |
min, | |
max, | |
bias = 1, | |
round = false, | |
maxSteps = Infinity, | |
getDirection | |
}) | |
{ | |
const mid = (min + max) / 2 | |
const value = round ? mid + 0.5 | 0 : mid | |
const steps = arguments[1] || 0 | |
const abort = steps === maxSteps | |
const dir = getDirection(value) | |
if (abort || dir === 0 || max - min < bias) | |
{ | |
return { value, steps, aborted: abort, dir } | |
} | |
else if (dir < 0) | |
{ | |
arguments[0].min = mid | |
return binarySearch(arguments[0], steps + 1) | |
} | |
else | |
{ | |
arguments[0].max = mid | |
return binarySearch(arguments[0], steps + 1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Examples:
Find the index for a value in a sorted array:
Guess a number between 0 and 1 million: