From 4206374f370afe25cb35777d1fe6fe0d298a59ef Mon Sep 17 00:00:00 2001 From: Ole Tange Date: Sat, 15 Aug 2020 23:48:47 +0200 Subject: [PATCH] binsearch: Initial version. --- Makefile | 29 ++++++----- binsearch/binsearch | 122 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 14 deletions(-) create mode 100755 binsearch/binsearch diff --git a/Makefile b/Makefile index 33a94eb..8d672a4 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,20 @@ -CMD = blink 2grep 2search burncpu drac duplicate-packets em encdir \ - field forever fxkill G gitnext gitundo goodpasswd histogram \ - mtrr mirrorpdf neno off parsort pdfman pidcmd pidtree \ - plotpipe puniq ramusage rand rclean rina rn rrm seekmaniac \ - shython sound-reload splitvideo stdout swapout T teetime \ - timestamp tracefile transpose upsidedown vid \ +CMD = binsearch blink 2grep 2search burncpu drac duplicate-packets em \ + encdir field forever fxkill G gitnext gitundo goodpasswd \ + histogram mtrr mirrorpdf neno off parsort pdfman pidcmd \ + pidtree plotpipe puniq ramusage rand rclean rina rn rrm \ + seekmaniac shython sound-reload splitvideo stdout swapout T \ + teetime timestamp tracefile transpose upsidedown vid \ w4it-for-port-open whitehash wifi-reload wssh ytv yyyymmdd -all: blink/blink.1 2search/2grep.1 2search/2search.1 \ - burncpu/burncpu.1 drac/drac.1 encdir/encdir.1 field/field.1 \ - G/G.1 gitnext/gitnext.1 gitundo/gitundo.1 \ - goodpasswd/goodpasswd.1 histogram/histogram.1 \ - mirrorpdf/mirrorpdf.1 neno/neno.1 off/off.1 parsort/parsort.1 \ - pdfman/pdfman.1 pidcmd/pidcmd.1 pidtree/pidtree.1 \ - plotpipe/plotpipe.1 puniq/puniq.1 rand/rand.1 rina/rina.1 \ - rn/rn.1 rrm/rrm.1 seekmaniac/seekmaniac.1 shython/shython.1 \ +all: binsearch/binsearch.1 blink/blink.1 2search/2grep.1 \ + 2search/2search.1 burncpu/burncpu.1 drac/drac.1 \ + encdir/encdir.1 field/field.1 G/G.1 gitnext/gitnext.1 \ + gitundo/gitundo.1 goodpasswd/goodpasswd.1 \ + histogram/histogram.1 mirrorpdf/mirrorpdf.1 neno/neno.1 \ + off/off.1 parsort/parsort.1 pdfman/pdfman.1 pidcmd/pidcmd.1 \ + pidtree/pidtree.1 plotpipe/plotpipe.1 puniq/puniq.1 \ + rand/rand.1 rina/rina.1 rn/rn.1 rrm/rrm.1 \ + seekmaniac/seekmaniac.1 shython/shython.1 \ sound-reload/sound-reload.1 splitvideo/splitvideo.1 \ stdout/stdout.1 teetime/teetime.1 timestamp/timestamp.1 \ tracefile/tracefile.1 transpose/transpose.1 T/T.1 \ diff --git a/binsearch/binsearch b/binsearch/binsearch new file mode 100755 index 0000000..a0d7017 --- /dev/null +++ b/binsearch/binsearch @@ -0,0 +1,122 @@ +#!/bin/bash + +: <<'=cut' +=encoding utf8 + +=head1 NAME + +binsearch - do binary search to find a numeric limit + + +=head1 SYNOPSIS + +B I + + +=head1 DESCRIPTION + +B runs I with a single number. It returns highest +value that I succeeds for. + + +=head1 EXAMPLES + +=head2 Test a bash function + + . $(which binsearch) + singleecho() { + /bin/echo $(perl -e 'print "x"x'$1) >/dev/null + } + binsearch singleecho + + +=head1 AUTHOR + +Copyright (C) 2020 Ole Tange, +http://ole.tange.dk and Free Software Foundation, Inc. + + +=head1 LICENSE + +Copyright (C) 2012 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +at your option any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + + +=head1 SEE ALSO + +B(1) + +=cut + + +# Example: find the max line length +# +# singleecho() { +# /bin/echo $(perl -e 'print "x"x'$1) >/dev/null +# } +# +# multiecho() { +# /bin/echo $(perl -e 'print "x "x'$(($1/2)) ) >/dev/null +# } +# +# binsearch singleecho + +binsearch() { + _binsearch() { + low=$1 + high=$2 + # echo $low-$high + if [ $low -gt $(($high - 2)) ]; then + return + fi + shift + shift + middle=$(( ( $low + $high ) / 2 )) + if eval "$@ $middle" ; then + low=$middle + else + high=$middle + fi + _binsearch $low $high "$@" + } + + low=1 + # If function(1) = false: run 'not function()' instead + if eval "$@ $low" ; then + not='' + else + not='!' + fi + # exponential search for the first value that is false + # low = previous value (function($low) == true) + # high = low * 2 (function($high) == false) + high=$low + while eval "$not" "$@ $high" 2>/dev/null ; do + low=$high + high=$(( $high*2 )) + done + # echo "low: $low high: $high not: $not" + _binsearch $low $high "$not $@" 2>/dev/null + echo $low +} + +if [ -z "$@" ] ; then + # source the bash function + # . $(which binsearch) + true +else + # binsearch command + binsearch "$@" +fi