ilib-common
Version:
Common utility functions for ilib. iLib is a cross-engine library of internationalization (i18n) classes written in pure JS
132 lines (121 loc) • 4.16 kB
JavaScript
/*
* SearchUtils.js - Misc search utility routines
*
* Copyright © 2013-2015, 2021-2022 JEDLSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @module SearchUtils
*/
/**
* Binary search a sorted array for a particular target value.
* If the exact value is not found, it returns the index of the smallest
* entry that is greater than the given target value.<p>
*
* The comparator
* parameter is a function that knows how to compare elements of the
* array and the target. The function should return a value greater than 0
* if the array element is greater than the target, a value less than 0 if
* the array element is less than the target, and 0 if the array element
* and the target are equivalent.<p>
*
* If the comparator function is not specified, this function assumes
* the array and the target are numeric values and should be compared
* as such.<p>
*
*
* @static
* @param {*} target element being sought
* @param {Array} arr the array being searched
* @param {?function(*,*)=} comparator a comparator that is appropriate for comparing two entries
* in the array
* @return the index of the array into which the value would fit if
* inserted, or -1 if given array is not an array or the target is not
* a number
*/
export function bsearch(target, arr, comparator) {
if (typeof(arr) === 'undefined' || !arr || typeof(target) === 'undefined') {
return -1;
}
var high = arr.length - 1,
low = 0,
mid = 0,
value,
cmp = comparator || bsearch.numbers;
while (low <= high) {
mid = Math.floor((high+low)/2);
value = cmp(arr[mid], target);
if (value > 0) {
high = mid - 1;
} else if (value < 0) {
low = mid + 1;
} else {
return mid;
}
}
return low;
};
/**
* Returns whether or not the given element is greater than, less than,
* or equal to the given target.<p>
*
* @private
* @static
* @param {number} element the element being tested
* @param {number} target the target being sought
*/
bsearch.numbers = function(element, target) {
return element - target;
};
/**
* Do a bisection search of a function for a particular target value.<p>
*
* The function to search is a function that takes a numeric parameter,
* does calculations, and returns gives a numeric result. The
* function should should be smooth and not have any discontinuities
* between the low and high values of the parameter.
*
*
* @static
* @param {number} target value being sought
* @param {number} low the lower bounds to start searching
* @param {number} high the upper bounds to start searching
* @param {number} precision minimum precision to support. Use 0 if you want to use the default.
* @param {?function(number)=} func function to search
* @return an approximation of the input value to the function that gives the desired
* target output value, correct to within the error range of Javascript floating point
* arithmetic, or NaN if there was some error
*/
export function bisectionSearch(target, low, high, precision, func) {
if (typeof(target) !== 'number' ||
typeof(low) !== 'number' ||
typeof(high) !== 'number' ||
typeof(func) !== 'function') {
return NaN;
}
var mid = 0,
value,
pre = precision > 0 ? precision : 1e-13;
do {
mid = (high+low)/2;
value = func(mid);
if (value > target) {
high = mid;
} else if (value < target) {
low = mid;
}
} while (high - low > pre);
return mid;
};