Regularly spaced numbers between bounds without jot

Viewed 91

I want to generate a sequence of integer numbers between 2 included bounds. I tried with seq, but I could only get the following:

$ low=10
$ high=100
$ n=8
$ seq $low $(( (high-low) / (n-1) )) $high
10
22
34
46
58
70
82
94

As you can see, the 100 is not included in the sequence.

I know that I can get something like that using jot:

$ jot 8 10 100
10
23
36
49
61
74
87
100

But the server I use does not have jot installed, and I do not have permission to install it.

Is there a simple method that I could use to reproduce this behaviour without jot?

4 Answers

If you don't mind launching an extra process (bc) and if it's available on that machine, you could also do it like this:

$ seq -f'%.f' 10 $(bc <<<'scale=2; (100 - 10) / 7') 100
10
23
36
49
61
74
87
100

Or, building on oguz ismail's idea (but using a precision of 4 decimal places):

$ declare -i low=10
$ declare -i high=100
$ declare -i n=8
$ declare incr=$(( (${high}0000 - ${low}0000) / (n - 1) ))
$ 
$ incr=${incr::-4}.${incr: -4}
$ 
$ seq -f'%.f' "$low" "$incr" "$high"
10
23
36
49
61
74
87
100

You can try this naive implementation of jot:

jot_naive() {
  local -i reps=$1 begin=${2}00 ender=${3}00
  local -i x step='(ender - begin) / (reps - 1)'
  for ((x = begin; x <= ender; x += step)); do
    printf '%.f\n' ${x::-2}.${x: -2}
  done
}

You could use awk for that:

awk -v reps=8 -v begin=10 -v end=100 '
    BEGIN{
        step = (end - begin) / (reps-1);
        for ( f = i = begin; i <= end; i = int(f += step) )
            print i
    }
'
10
22
35
48
61
74
87
100

UPDATE 1 ::: fixed double-printing of final row due to difference less than tiny value of epsilon

  • to maintain directional consistency, rounding is performed based on sign of final :

    —- e.g. if final is negative, then any rounding is done as if the current step value (CurrSV) is negative, regardless of sign of CurrSV

———————————————

while i haven't tested every single possible edge case, i believe this version of the code should handle both positive and negative rounding properly, for the most part.

that said, this isn't a jot replacement at all - it only implements a very small subset of the steps counting feature instead of being a full blown clone of it:

{m,g}awk '
function __________(_) { 
    return -_<+_?_:-_ 
}
BEGIN {
   CONVFMT = "%.250g"; OFMT = "%.13f"
     _____ = (_+=_^=_______=______="")^-_^!_ 
} { 
      ____ = (((_=$(__=(___=$NF)^(_<_)))^(_______=______="")*___\
              )-(__=$++__))/--_
   _________ = (_____=(-(_^=_<_))^(________=+____<-____\
                           )*(_/++_))^(++_^_++-+_*_--+-_)
   if (-___<=+___) {
           _____=__________(_____)
       _________=__________(_________)
   }
   do { print    ______, 
              ++_______, int(__+_____), -____+(__+=____) 
   } while(________? ___<(__-_________) : (__+_________)<___)

   print ______, ++_______, int(___+_____), ___, ORS  

}' <<< $'8 -3 -100\n8 10 100\n5 -15 -100\n5 15 100\n11 100 11\n10 100 11'  

|

 1 -3 -3
 2 -17 -16.8571428571429
 3 -31 -30.7142857142857
 4 -45 -44.5714285714286
 5 -58 -58.4285714285714
 6 -72 -72.2857142857143
 7 -86 -86.1428571428572
 8 -100 -100 

 1 10 10
 2 23 22.8571428571429
 3 36 35.7142857142857
 4 49 48.5714285714286
 5 61 61.4285714285714
 6 74 74.2857142857143
 7 87 87.1428571428572
 8 100 100 

 1 -15 -15
 2 -36 -36.2500000000000
 3 -58 -57.5000000000000
 4 -79 -78.7500000000000
 5 -100 -100 

 1 15 15
 2 36 36.2500000000000
 3 58 57.5000000000000
 4 79 78.7500000000000
 5 100 100 

 1 100 100
 2 91 91.1000000000000
 3 82 82.2000000000000
 4 73 73.3000000000000
 5 64 64.4000000000000
 6 55 55.5000000000000
 7 47 46.6000000000000
 8 38 37.7000000000000
 9 29 28.8000000000000
 10 20 19.9000000000000
 11 11 11 

 1 100 100
 2 90 90.1111111111111
 3 80 80.2222222222222
 4 70 70.3333333333333
 5 60 60.4444444444445
 6 51 50.5555555555556
 7 41 40.6666666666667
 8 31 30.7777777777778
 9 21 20.8888888888889
 10 11 11 
Related