Native Vim Random number script

Try something like

function Rand()
    return str2nr(matchstr(reltimestr(reltime()), '\v\.@<=\d+')[1:])
endfunction

. I know no better option then using some of the time functions (there are two of them: reltime() and localtime(), but the latter is updated only each second). I would prefer to either avoid random numbers or use pyeval('random.randint(1, 10)') (preceded by python import random), because shell is slow and I don’t trust time-based solutions.

Note: documentation says that format of the item returned by reltime() depends on the system, thus I am using reltimestr(), not doing something with reltime()[1] which looks like if it contains nanoseconds.


Based on others' answers and other resources from the internet, I have written two functions to generate a random integer in the given range [Low, High].

Both the two functions receive two arguments: Low and High and return a random number in this range.

Combine Python and Vim script

The first function combines Python and Vim script.

" generate a random integer from range [Low, High] using Python
function! RandInt(Low, High) abort
" if you use Python 3, the python block should start with `python3` instead of
" `python`, see https://github.com/neovim/neovim/issues/9927
python3 << EOF
import vim
import random

# using vim.eval to import variable outside Python script to python
idx = random.randint(int(vim.eval('a:Low')), int(vim.eval('a:High')))

# using vim.command to export variable inside Python script to vim script so
# we can return its value in vim script
vim.command("let index = {}".format(idx))
EOF

return index
endfunction

Pure Vim script

The second function I propose uses pure vim script:

function! RandInt(Low, High) abort
    let l:milisec = str2nr(matchstr(reltimestr(reltime()), '\v\.\zs\d+'))
    return l:milisec % (a:High - a:Low + 1) + a:Low
endfunction

Use luaeval() (Neovim only)

The third way to generate random number is to use lua via luaeval().

" math.randomseed() is need to make the random() function generate different numbers 
" on each use. Otherwise, the first number it generate seems same all the time.
luaeval('math.randomseed(os.time())')
let num = luaeval('math.random(1, 10)')

If you want to generate random number in non-serious occasions, you may use the these methods as a starter.


I've recently played around with random numbers in Vim script myself. Here are some resources that I found in the process.

No Vim script

By all means, use an external random number generator if you can. As a rule, they are better and faster than anything that could be done in Vim script.

For example, try

  • :python import random; print random.randrange(1, 7)
  • :echo system('echo $RANDOM')
  • another scripting language, for example Ruby

Libraries

Vim script libraries. These hopefully strive to provide decent quality RNG implementations.

  • vital.vim is an excellent and comprehensive library created by the vim-jp user group. Their random number generator sports an impressive array of functionality and is the best pure Vim script RNG I know of. vital.vim uses an Xorshift algorithm. Check it out!

    Rolling a die with vital.vim:

    let Random = vital#of('vital').import('Random')
    echo Random.range(1, 7)
    
  • vim-rng is a small random number generator plugin. It exports a couple of global functions that rely on a multiply-with-carry algorithm. This project seems to be a work in progress.

    Rolling a die with rng:

    echo RandomNumber(1, 6)
    
  • magnum.vim is my own little big integer library. I've recently added a random number generator that generates integers of any size. It uses the XORSHIFT-ADD algorithm.

    Rolling a die with magnum.vim:

    let six = magnum#Int(6)
    echo magnum#random#NextInt(six).Add(magnum#ONE).Number()
    
  • Rndm has been around for much longer than the other libraries. Its functionality is exposed as a couple of global functions. Rolling a die with Rndm:

    echo Urndm(1, 6)
    

Discussion and snippets

Finally, a few links to insightful discussion and Vim script snippets.

  • ZyX's reltime snippet on this page.

  • loreb's vimprng project on GitHub has an impressive number of RNG implementations in Vim script. Very useful.

  • This old mailing list discussion has a couple of Vim script snippets. The first one given by Bee-9 is limited to 16 bit but I found it quite effective. Here it is:

    let g:rnd = localtime() % 0x10000
    
    function! Random(n) abort
      let g:rnd = (g:rnd * 31421 + 6927) % 0x10000
      return g:rnd * a:n / 0x10000
    endfunction
    
  • Another script, found in a person named Bart's personal config files.

  • Episode 57 on Vimcasts.org discusses Vim's 'expression register' and refers to random number examples throughout. Refers to this Stackoverflow question and ZyX's snippet. Recommended.

  • The Vim wiki on wikia has an article 'Jump to a random line' that has a few resources not mentioned yet.

Tags:

Vim

Random