Examples

notice

These are examples of how far you can push this application. Most of them require considerable knowledge of mathematics and programming. Don't get scared off, normal usage of ised looks more like it's demonstrated in tutorial.

radix conversion

To convert a number to another base, one must compute residuals after repetitive division by radix. Converting 54631 to binary:

$ ised '54631/2^~[32]%2'
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 1 0 1 0 1 1 0 0 1 1 1

It's easier to read if we remove leading zeroes. To find first nonzero, we use operator ? and take the first element of the result.

$ ised '@2{54631/2^~[32]%2};$2<<{-?$2_0}'
1 1 0 1 0 1 0 1 0 1 1 0 0 1 1 1

Conversion for all radices up to 10. We remove spaces by changing delimiter with --d.

$ ised --d '\n' '[2 10]' | ised --d '""' --l - '@2{54631/i{$1^~[32]}%$1};$2<<{-?$2_0}'
1101010101100111
2202221101
31111213
3222011
1100531
315163
152547
82841
54631

random numbers

ised can generate random numbers, which allows us to perform simple montecarlo simulations. Let's first see how are the generated numbers distributed. Beware, operator #_ only counts exact duplicates of numbers. To perform bin-counting we must first round the numbers. A better way is to use #__, which performs binning automatically.

$ ised '#_{[10]}i{10*ran(1. 100000)}' ten bins: roughly uniform distribution
9945 10059 9794 10076 10085 9984 9987 10146 10041 9883
$ ised '#_[10]iran(10. 100000)' well, this is exactly the same
9897 10069 10115 10028 9874 10115 9929 9996 10051 9926
$ ised '#_[10]ran(10 100000)' if fed integers, ran automatically generates integer numbers
9892 10135 9824 10131 9897 10084 9960 9987 10074 10016
$ ised '#_[10]i{10*sqtran(1. 100000)}' if we take sqrt, distribution is linear
999 2975 4948 6966 9042 11162 13026 14959 16883 19040
$ ised '#__[0 0.1 1]{sqtran(1. 100000)}' better way; first and last elements count outliers
0 1026 2863 4970 7058 8988 10899 12849 15052 16939 19356 0
$ ised '#_[2]ran(2 1000000)' million coin flips
500520 499480
$ ised --F 'yes' --D 'no' '{0 0.}_ran2' abuse of notation :)
no or is it?
$ ised --F 'yes' --D 'no' '@0{ran2};{?$0}*0. {?{1-$0}}*0' just to show how ? can be used to simulate if statement
yes

Explanation of last two examples: floats and integers use different print formats. So, if we yield float (0.) in case of 1 and int (0) in case of 0, we can select which print routine will be used. We assigned two different strings to print formats.

Here's more elaborate example. It calculates probability distribution of moment of inertia, if point mass is placed randomly into cylinder with height "h" and unit radius. The script takes "N": number of samples, "h": height of cylinder and "binsize" width of bin for histogram.

This example illustrates how ised can be used in bash for floating point math and stand-alone to produce plottable data.

#!/bin/bash
if [ $# -lt 2 ]; then
echo "$0 <N> <h> <binsize>"
exit 1
fi
diag=$(ised "{$2}^2+1")
(
echo 'set xlabel "J"; plot "-" pt 6 ps 1.5 lc rgb "black" t "transverse moment of inertia"';
ised --d '\n' "@0{$1}@1d{$2}@2d$3@3d$diag;" \
'@4{$1*{ran(2.$0)-1}};@5{sqtran(1.$0):*cosran(2*pi$0)};@6{$4^2:+$5^2};{#_{[$3/$2]}i{$6/$2}}/{$2*$0}' | ised --l - "\$0*$3 \$1";
echo e
) | gnuplot -persist - 2&>/dev/null

When called with these arguents:

$ plotbins.sh 100000 2 0.05

the script produced this graph:

integration and differentiation

It is possible to use ised to integrate arbitrary algebraic function numerically. There's no need for loops as integration is simply cummulative summation, which is achieved with constructor (). We choose a integration step, calculate a function on equally spaced interval and output the function and it's integral with --t option.
Differentiation is achieved by offsetting array by one and substract from original array. This example outputs integral and derivative of sine function on range (0,pi):

ised> @0{0.05} we choose step
0.05
ised> @1{[0 $0 pi]}; integration range
ised> @2{sin$1}; function values
ised> @3{$0*(0 $2 #$1)}; compute integral with starting point 0
ised> @4{{{$2<<-1}:-$2}/$0}; differentiate the same function
ised> --d "\t" declare tab as separator
ised> --t '$1;$2;$3;$4' output x, sin(x), its integral and derivative
0 0 0 0.999583
0.05 0.0499792 0 0.997085
0.1 0.0998334 0.00249896 0.992094
0.15 0.149438 0.00749063 0.984624
0.2 0.198669 0.0149625 0.974693
0.25 0.247404 0.024896 0.962325
0.3 0.29552 0.0372662 0.947552
...
2.8 0.334988 1.93344 -0.950203
2.85 0.287478 1.95019 -0.964574
2.9 0.239249 1.96457 -0.976534
2.95 0.190423 1.97653 -0.986053
3 0.14112 1.98605 -0.993107
3.05 0.0914646 1.99311 -0.99768
3.1 0.0415807 1.99768

Of course we can use any function or even load the values from a file, without modifying other steps.

Since version 2.2.0, new features are avaliable, which make differentiation and integration easier to implement. Corresponding steps in above code can be changed to:

...
ised> @3{$0*(0 $2 -1)}; count -1 means iterate once over all increments
ised> @4{$2**pm/$0}; differentiation is convolution with {1 -1}
...

When you only need definite integral of a function, there's no need to compute values for entire domain. We just use operator @+ to add the values:

$ ised '@0{0.05};@1[0 $0 pi];$0*@+{sin$1}'
1.99976

inverting functions

To solve an equation of type f(x)=y without use of derivatives, we usually use bisection. This method can be implemented in ised as one-liner. We use some arbitrary lines and feed them to --l evaluation to simulate a loop.

Let's calculate inverse of x!=3 (factorial of which number equals 3?). We initialize by remembering right-side of equation (3) and initial bracket for bisection (1,5). Then there's midpoint calculation, comparison of values and storing new bracket boundaries.

$ ised --d '\n' "(0 15)" | ised '@2{3}@3{1}@4{5};' --l - '@5{{$3+$4}/d2};@6{$5!>$2};@{3+$6}$5' here we see whole process
3
2
2.5
2.25
2.375
2.4375
2.40625
2.39062
2.39844
2.40234
2.4043
2.40527
2.40576
2.40601
2.40588
$ ised --d '\n' "(0 15)" | ised '@2{3}@3{1}@4{5};' --l - '@5{{$3+$4}/d2};@6{$5!>$2};@{3+$6}$5;' '$5 $5!' now we just output the result and confirmation
2.40588 3.00004
$ ised --d '\n' "(0 15)" | ised '@2{3}@3{1}@4{5};' --l - '@5{{$3+$4}/d2};@6{exp($5)*$5>$2};@{3+$6}$5;' '$5 exp($5)*$5' another example: x*exp(x)=3
1.04993 3.0001

Similarly, we can implement iteration. Negative solution of 2^x=x^2 can be shown to be a=-s^s^s^s^..., s=1/sqrt(2). This constant is built-in as operator aa.

$ ised --d '\n' "(1/sqt2 15)" | ised '@2{1/sqt2};' --l - '@2{$1^$2};' '-$2 aa'
-0.766665 -0.766665
$ ised --d '^' "(1/sqt2 15)" | ised --f - we can just generate the code by changing separator to ^
0.766665

Since version 2.3.0, termination from inside the code is possible. The iteration can be stopped when it converges. The loop can now be infinite, which is possible using GNU core utility yes. The memory slot $0 after the loop contains the number of iterations.

$ yes 0 | ised '@2{3}@3{1}@4{5};' --l - '@5{{$3+$4}/d2};@6{$5!>$2};@{3+$6}$5 Q{100 abs{$5!-$2}<1e-10};' '$0 $5 $5!' we want accuracy 1e-10
35 2.40587 3 achieved in 35 iterations

L-systems

The fact that operator $ reads many memory slots at once if its argument is an array, and ised's feature that it concatenates and flattens all the arrays, make iterated application of replacement rules a trivial procedure. Memory contents serve as substitution rules and repetitive application of $ operator serves as replacement iteration.
A typical L-system example is substitution A to AB, B to A:

ised> @0{0 1}; 0 serves as A, 1 serves as B. This is rule "A to AB"
ised> @1{0}; rule "B to A"
ised> $$$$$0 five applications of the rule on A state
0 1 0 0 1 0 1 0 0 1 0 0 1 result is ABAABABAABAAB

If L-system generates drawing rules for a fractal, we can without much additional work convert the generated string to xy coordinates. Click on the images to see the ised scripts that generated the coordinates.

producing plottable data

ised's transparent handling of arrays makes it very easy to generate data for plotting of functions, curves and more complex geometric structures. Parametrization of trefoil knot is a one-liner.

ised '@1[0 pi/100 2*pi];' --t '@2{2+cos{3*$1}}:*cos{2*$1};$2:*sin{2*$1};sin{3*$1}' > trefoil.dat

Example visualization with gnuplot:

With a bit more effort, the knot can be visualized as a tube-like surface. First and second derivative of the curve is first generated, then it is used to generate normal and binormal and spaced by empty lines using a trick involving switch --p. Then --t is used to convert each line into a long column describing the circular (or any other) cross section of the knot surface. Instead of piping one ised into another, --o switch enables storage of intermediate files, so the entire procedure can be done in a single script. Click on the image to see the ised script that generated the data.

bulk evaluation

The most common use of calculators is evaluation of physical, mathematical or financial expressions. In most cases, we must apply the same formula on larger set of data. If we don't opt for specialised software, ised is a good alternative to repetitive input of data into the classical desktop calculator.

Let's assume we have been measuring average speed of a vehicle on a fixed distance (e.g. d=100m). We measure the time at two spots (t1,t2). The average velocity is therefore v=d/(t2-t1).

ised> @1{0.237853 0.236133 0.0497423 0.145806 0.135682 0.231851 0.169376 0.0481285}; starting times (t1)
ised> @2{3.63055 3.87316 3.72171 3.87247 3.35336 3.56304 3.38296 3.34266}; finishing times (t2)
ised> 100/{$2:-$1} velocities in meters per second
29.4751 27.495 27.2334 26.8337 31.0783 30.0193 31.1179 30.3533
ised> @+{$-1}/#$-1 compute average (using history value $-1)
29.2007
ised> avg$-2 easier way to get average (using the result two lines above with history $-2)
29.2007
ised> {$-1}*{3.6 1/0.44704} convert to both km/h and mph
105.123 65.3201

There's no need to use memory, it's just more transparent for this tutorial. If the data set is small, we can just throw the numbers in:

ised> {31155 24505 19900 31000}*0.66657779 convert 4 car prices from dollars to euros
20767.2 16334.5 13264.9 20663.9
ised> {S$-1}_{0 -1} sort and select the cheapest and the most expensive
13264.9 20767.2

CPU load calculation

In linux operating systems, CPU load can be calculated by measuring difference of cumulative usage at two different times. To get percentage, user time must be divided by sum of all times. This can easily be accomplished with ised.

#!/bin/bash
{
sed -n '1 s/^[a-z ]*//p' /proc/stat | ised --l - '@+$1 $1_0'
sleep 0.1
sed -n '1 s/^[a-z ]*//p' /proc/stat | ised --l - '@+$1 $1_0'
} | ised --a - --F '%.2f%%' '@3{$2:-$1};100*{$3_1/d$3_0}'

To change averaging time, just change sleep time. This only works for single CPU, but can readily be modified for the general case.

quadratic equation

We could calculate both roots of quadratic equation separately, but there's no need for that. ised provides operator pm which acts as both plus and minus at once.
Solving quadratic equation this way is redundant now, as ised has built-in polynomial solver since version 2.2.2.

ised> @1{2}@2{3}@3{-4} prepare some values
2 3 -4 we will solve equation 2x^2+3x-4
ised> {-$2+pm*sqt{$2^2-4*$1*$3}}/{2*$1} both solutions
0.850781 -2.35078
ised> $1*$-1^2:+$2*$-1:+$3*$-1^0 confirm results (note component-wise addition and use of last result $-1)
0 0
ised> pm what pm actually is
1 -1
ised> pz${3 2 1} builtin solver works just as well
0.850781 -2.35078
ised> px${3 2 1}$-1 builtin polynomial evaluator
-4.44089e-16 -0 polynomial evaluator may have some rounding issues
ised> @1{2}@2{3}@3{4} now for equation with no real roots
2 3 4
ised> {-$2+pm*sqt{$2^2-4*$1*$3}}/{2*$1} no change here: we just changed values in memory
nan nan obviously no real roots
ised> pz${3 2 1} builtin solver returns empty array

series and sequences

ised's ability to handle arrays means formulas for general terms of series can yield all values at once. Let's compute some Taylor series for x=2.5.

ised> @0{15} choose number of terms
15
ised> @1{2.5} choose some other value for x
2.5
ised> @+{$1^[$0]:/[$0]!} exp$1 exponential series and comparison with exact value
12.1825 12.1825
ised> (0 pm mp $0) we find a way to generate factors for sine series
0 1 0 -1 0 1 0 -1 0 1 0 -1 0 1 0
ised> @+{(0 pm mp $0):*$1^[$0]:/[$0]!} sin$1 sine series and exact value
0.598473 0.598472
ised> @+{(1 -2 2 $0):*$1^O[$0]:/{O[$0]}!} sin$1 the same, but by selecting odd terms by operator O
0.598473 0.598472
ised> @+{(1 -2 2 $0):*$1^E[$0]:/{E[$0]}!} cos$1 cosine: the same, just select even terms
-0.801144 -0.801144
ised> (1 -2 2 $0) just to see what we did there
1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1

We can also generate sequences if we know the general term. For primes, we just remove all values that are products of some two numbers.

ised> @0{20} how many terms
20
ised> @1 {0.5*{1+sqt5}} precompute golden section
1.61803
ised> r{{$1^[1 $0]:-(-$1)^-[1 $0]}/sqt5} Fibonacci sequence (note rounding to convert to integers)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
ised> @+{[$0]^3} {@+[$0]}^2 interesting equality of sums
36100 36100
ised> @0{10} now less terms
10
ised> $0!/{[0 $0]!:*~[0 $0]!} binomial coefficients
1 10 45 120 210 252 210 120 45 10 1
ised> {1 1}**{1 1}**{1 1}**{1 1} definition of binomial coefficients
1 4 6 4 1
ised> 4c[0 4] built-in function for binomial coefficients
1 4 6 4 1
ised> @2[2 100];$2\{$2*$2} primes up to 100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Recursively defined sequences cannot be evaluated directly because ised doesn't implement programmable loops and recursion. But we can achieve recursion by using --l directive. Whatever we give as input, ised will evaluate the same line for each line of input. As the memory persists between evaluations, we can use it as variables in recursion. We just have to avoid $0 and $1 as these two spots are being used for storage of current line and line number. We'll use ised to fill nonsense lines into our recursive algorithm for Fibonacci numbers. Remember that these values are never used. We initialize memory with initial values of recursive formula before starting the recursion.

$ ised --t "(0 10)" | ised '@{2 3}{1}' --l - '@3{$2+@2{$3}}' memory assignment is a little complex
1
2
3
5
8
13
21
34
55
89
144
$ ised --t "(0 10)" | ised '@{2 3}{1}' --l - '@4{$2+$3};@2{$3};@3{$4}' longer but clearer implementation
...

abusing functions

Ability to define functions enables everything, from simple avoiding of repetition, to actual programming. Let's first look at defining plain functions.

ised> @1{: x_0*{sin x_1 cos x_1} :} conversion from polar to cartesian coordinates
1 returns function id
ised> @2{: @=x atn{x_1/x_0} :} conversion back to polar
2 id's are unique
ised> $1::{1 pi/4} apply the function
0.707107 0.707107
ised> {$1 $2}::{1 pi/4} function composition
1 0.785398 there and back again
ised> {:x^2:}::{1 2 3} immediate evaluation
1 4 9
ised> ( {:x^2:} 4 )::{1 2 3} squared 4 times
1 65536 43046721
ised> Q{2051} list function ids
1 2 3 4 there are 4 functions out there
ised> Q{2004} get memory list
1 2 we saved two function id's

Hailstone sequence is a sequence of integers where the next term of n is n/2 for even n and 3*n+1 for odd n. The sequence ends when you reach 1. An interesting problem is finding how many terms a sequence starting at a particular number has. To implement this in ised, we will use functions and system calls.

ised> @1{: {x/2 3*x+1}_{x%2} :}; function that finds the next term
ised> @2{: @0{$0+1}*{} x :}; increments $0 silently and leaves x intact
ised> @3{: Q{103 -{x==1}} x :}; break if x==1, otherwise return to 0th function
ised> @0{1}; reset step counter
ised> ${1 2 3}::27 compute the sequence for 27
1 the iteration stops at 1
ised> $0 how many steps?
112
ised> @4{: @10{$10 x}*{} x:}; this function appends x to $10
ised> ${1 2 4 3}::27; appending before loop test!
ised> $10 this contains the sequence now
82 41 124 62 31 ... 20 10 5 16 8 4 2 1

This shows that although the code is short, it is quite elaborate and requires care to keep track of everything. The operator ::: simplifies this for one class of problems: numerical iterations that converge to the result. One example of such iteration is the power tower mentioned earlier, that converges to the result of the equation 2^x=x^2. Before, this was solved using a nasty trick with operator --l.

ised> {:{sqt2/2}^x:}:::1 power tower
0.766665 result
ised> -aa the same
0.766665
ised> {:1+1./x:}:::{1 5 20} converges to the golden ratio
1.61803 1.61803 1.61803 from all initial approximations
ised> @0{0};{:@0{$0+1}*{} x+1./$0!:}:::{0} series for number e
1.71828
ised> $0 how many steps did we need?
19
ised> {:atanx:+[10]*pi:}:::[10] calculates first 10 zeros of x=tan(x)
0 4.49341 7.72525 10.9041 14.0662 17.2208 20.3713 23.5195 26.6661 29.8116 simultaneously

Quite useful trick that we used twice was suppressing the unwanted returning of input while saving to memory by multiplying it with an empty array {}. This is necessary because the functions are chained and function that works with memory still needs to pass through the argument unscratched. This can be avoided if everything is done in memory and the arguments are just scrap.

number theory

ised has some basic functions for performing number theory calculations.

ised> @2[2 50];$2\{$2*$2} slow and dirty calculation
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 primes up to 50
ised> X[2 50] built-in Miller-Rabin primality test
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 the same
ised> F@*X[2 50] factorization retrieves the factors
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
ised> F10101 a composite number
3 7 13 37 prime factors
ised> ?{0==10101%[10101]} [10101]} % divisors of above number
1 3 7 13 21 37 39 91 111 259 273 481 777 1443 3367
ised> phi{7 77 777 7777} Euler Totient function
6 60 432 6000
ised> @1{3 12}/gcd$1 reducing a fraction
1 4 3/12 equals 1/4
ised> gcd{45 60 30} lcm{45 60 30} works for multiple arguments
15 180 greatest common divisor and least common multiple
ised> F{123456789123456789} large numbers are not a problem
3 3 7 11 13 19 3607 3803 52579
ised> max{pm**X[10000]} max prime gap up to 10000
36