--- Module for generating integer values -- @module lqc.generators.int -- @alias new local Gen = require 'lqc.generator' local random = require 'lqc.random' local abs = math.abs --- Helper function for picking a random integer, bounded by min and max. -- @param min minimum value -- @param max maximum value -- @return function that can generate an integer (min <= int <= max) local function pick_bounded(min, max) local function do_pick() return random.between(min, max) end return do_pick end --- Helper function for finding number closest to 0. -- @param a number 1 -- @param b number 2 -- @return number closest to 0 local function find_closest_to_zero(a, b) return (abs(a) < abs(b)) and a or b end --- Helper function for shrinking integer, bounded by min and max. (min <= int <= max) -- @param min minimum value -- @param max maximum value -- @return shrunk integer (shrinks towards 0 / closest value to 0 determined -- by min and max) local function shrink_bounded(min, max) local bound_limit = find_closest_to_zero(min, max) local function do_shrink(previous) if previous == 0 or previous == bound_limit then return previous end if previous > 0 then return math.floor(previous / 2) end return math.ceil(previous / 2) end return do_shrink end --- Picks a random integer, uniformy spread between +- sample_size / 2. -- @param sample_size Number of times this generator is used in a property; -- used to guide the optimatization process. -- @return random integer local function pick_uniform(sample_size) local value = sample_size / 2 return random.between(value - sample_size, value) end --- Shrinks an integer by dividing it by 2 and rounding towards 0. -- @param previous previously generated integer value -- @return shrunk down integer value local function shrink(previous) if previous == 0 then return 0 end if previous > 0 then return math.floor(previous / 2) end return math.ceil(previous / 2) end --- Creates a generator for generating an integer between min and max. -- @param min minimum value -- @param max maximum value -- @return generator that generates integers between min and max. local function integer_between(min, max) return Gen.new(pick_bounded(min, max), shrink_bounded(min, max)) end --- Creates a generator for generating a positive integer between 0 and max. -- @param max maximum value -- @return generator that generates integer between 0 and max. local function positive_integer(max) return Gen.new(pick_bounded(0, max), shrink) end --- Creates a generator for generating an integer uniformly chosen -- between +- sample_size / 2. -- @return generator that can generate an integer local function integer() return Gen.new(pick_uniform, shrink) end --- Creates a new integer generator. -- @param nr1 number containing first bound -- @param nr2 number containing second bound -- @return generator that can generate integers according to the following strategy: -- - nr1 and nr2 provided: nr1 <= int <= nr2 -- - only nr1 provided: 0 <= int <= max -- - no bounds provided: -numtests/2 <= int <= numtests/2 local function new(nr1, nr2) if nr1 and nr2 then return integer_between(nr1, nr2) end if nr1 then return positive_integer(nr1) end return integer() end return new