mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 19:03:45 +00:00
Estimated hours taken: 2 The following change was made by Peter Moulder <pmoulder@csse.monash.edu.au>. extras/quickcheck/tutes/*.html: Many HTML fixes. (Previously there were enough problems that it made more sense to read them as plain text files than with a web browser.) The files now pass through weblint (cleanly) and tidy (only `table lacks "summary" attribute' warnings remain). A small number of textual changes, and also a couple of <!-- XXX ... --> comments where I suspect the text should be changed.
214 lines
6.5 KiB
HTML
214 lines
6.5 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<title>QuickCheck</title>
|
|
</head>
|
|
<body>
|
|
<p>
|
|
Files :
|
|
<a href="use51.m">use51.m</a>
|
|
<br>
|
|
<a href="index.html">Back to main</a>
|
|
|
|
<H1> QuickCheck Tutorial 5 </H1>
|
|
<h2> Generators - Basic </h2>
|
|
|
|
<p>
|
|
The invariant function is of the form
|
|
<pre>
|
|
:- func Invariant_Function_X(T, T1, T2 ...) = property
|
|
:- mode Invariant_Function_X(in, in, in ...) = out.
|
|
</pre>
|
|
Quickcheck generates random values for each input argument at run time.
|
|
The following types have default generators:
|
|
<ul>
|
|
<li> int
|
|
<li> char
|
|
<li> float
|
|
<li> string
|
|
<li> some functions (more detail in Tutorial 8)
|
|
<li> any type defined as a discriminated union, provided
|
|
that all types in the body of the definition have
|
|
default/custom generators
|
|
<li> any type defined as being equivalent to a type with a
|
|
default/custom generator
|
|
</ul>
|
|
|
|
<p>
|
|
There is no code written to handle equivalent types. But it works
|
|
as if the compiler replaced all the equivalent types with their real type
|
|
before compiling.
|
|
|
|
<p>
|
|
The default generator for int is rand_int/2, which has distribution:
|
|
<table>
|
|
<tr>
|
|
<td> 50%
|
|
<td> even distribution in the range [-100, 100]
|
|
<tr>
|
|
<td> 50%
|
|
<td> even distribution in the range (-2^31, 2^31)
|
|
<br>(This will probably change to [int__min_int, int__max_int] in
|
|
a future version.)
|
|
</table>
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
|
|
:- func rand_int(rnd, rnd) = int.
|
|
:- mode rand_int(in, out) = out is det.
|
|
rand_int(BS0, BS) = Int :-
|
|
Temp = rand_allint(BS0, BS1) rem 2,
|
|
(if Temp = 0
|
|
then
|
|
irange(-100, 100, Int, BS1, BS)
|
|
else
|
|
Int = rand_allint(BS1, BS)
|
|
).
|
|
|
|
:- func rand_allint(rnd, rnd) = int.
|
|
:- mode rand_allint(in, out) = out is det.
|
|
rand_allint(BS0, BS) = Int :-
|
|
next(1, Sign, BS0, BS1),
|
|
next(31, TempInt, BS1, BS),
|
|
( Sign > 0 ->
|
|
Int = TempInt
|
|
;
|
|
Int = -TempInt
|
|
).
|
|
</pre></tr></table>
|
|
Default for char is rand_char/2, with even spread over
|
|
char__to_int(Char, X) where X is (-1000, 1000).
|
|
<!-- Maybe insert `∩ {I : some[C] char__to_int(C, I)}' or English comment. -->
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
|
|
:- func rand_char(rnd, rnd) = char.
|
|
:- mode rand_char(in, out) = out is det.
|
|
rand_char(RS0, RS) = Char :-
|
|
Int = rand_allint(RS0, RS1) rem 1000,
|
|
(if char__to_int(Char0, Int)
|
|
then
|
|
Char = Char0,
|
|
RS = RS1
|
|
else
|
|
Char = rand_char(RS1, RS)
|
|
).
|
|
</pre></tr></table>
|
|
Default for float is rand_float/2, which has roughly even
|
|
distribution over all discrete values for a 32-bit float.
|
|
If machine is less then 32bits, overfloat occurs. It should still
|
|
cover all possible values, but may alter distribution.
|
|
If machine is more than 32bits, rand_float/2 will miss some values
|
|
but retains even distribution.
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
|
|
:- func rand_float(rnd, rnd) = float.
|
|
:- mode rand_float(in, out) = out is det.
|
|
rand_float(BS0, BS) = Flt :-
|
|
next(31, Mant0, BS0, BS1),
|
|
next(1, Sign, BS1, BS2),
|
|
( Sign > 0 ->
|
|
Mant = Mant0
|
|
;
|
|
Mant = -Mant0
|
|
),
|
|
next(7, Exp, BS2, BS3),
|
|
next(1, ExpSign, BS3, BS),
|
|
Flt0 = float(Mant) * pow(2.0, Exp),
|
|
( ExpSign > 0, Flt0 \= 0.0 ->
|
|
Flt = 1.0/Flt0
|
|
;
|
|
Flt = Flt0
|
|
).
|
|
</pre></tr></table>
|
|
Default for string is rand_string/2, each element is generated by
|
|
rand_char/2.
|
|
<table summary="The probability of the string having length i is 0.9^i * 0.1.">
|
|
<tr>
|
|
<td>0.9^0 * 0.1
|
|
<td>chance being string length == 0
|
|
<tr>
|
|
<td>0.9^1 * 0.1
|
|
<td>chance being string length == 1
|
|
<tr>
|
|
<td>0.9^2 * 0.1
|
|
<td>chance being string length == 2
|
|
<tr>
|
|
<td>...etc...
|
|
</table>
|
|
So the mean string length is Sum(0.1* 0.9^N * N) where N ← {0, infinity},
|
|
which converges to 9.
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
|
|
:- func rand_string(rnd, rnd) = string.
|
|
:- mode rand_string(in, out) = out is det.
|
|
rand_string(RS0, RS) = X :-
|
|
gen(Charlist, [], [ {type_of(['A']), [{10,[]},{90,[]}]} ],
|
|
[], RS0, RS),
|
|
string__from_char_list(Charlist,X).
|
|
</pre></tr></table>
|
|
Note that the default generator for stirng actually uses the default generator
|
|
for discriminated union (indirectly).
|
|
|
|
<p>
|
|
use51.m gives an illustration of generating int, char, float, string.
|
|
|
|
<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
|
|
:- module use51.
|
|
|
|
:- interface.
|
|
|
|
:- type marks == int.
|
|
|
|
:- use_module io.
|
|
|
|
:- pred main(io__state, io__state).
|
|
:- mode main(di, uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int, char, float, string, list.
|
|
:- import_module qcheck.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
main -->
|
|
qcheck(qcheck__f(junk), "just to show the inputs", 5, [], []).
|
|
|
|
:- func junk(marks, char, float, string) = property.
|
|
junk(A, B, C, D) =
|
|
{A,B,C,D} `>>>` [yes].
|
|
</pre></tr></table>
|
|
There are a few thing to note about use51.m :
|
|
<pre>
|
|
qcheck(qcheck__f(junk), "just to show the inputs", 5, [], []).
|
|
</pre>
|
|
The 3rd argument is an int, which specifies how many times to run. In this
|
|
example 5 tests are run , but the default is 100. The other auguments will
|
|
be described later.
|
|
<pre>
|
|
junk(A, B, C, D) =
|
|
{A,B,C,D} `>>>` [yes].
|
|
</pre>
|
|
the invariant function doesn't do any testing, it always succeeds. But
|
|
`>>>` collects all the inputs.
|
|
A Sample output
|
|
<pre>
|
|
Test Description : just to show the inputs
|
|
Number of test cases that succeeded : 5
|
|
Number of trivial tests : 0
|
|
Number of tests cases which failed the pre-condition : 0
|
|
Distributions of selected argument(s) :
|
|
1 {-50, '4', -3.55475907854864e+25, "\241r\371~~\316\002LJ~\204\246"}
|
|
1 {27, '\342', -311727734390784., "\377g.\001"}
|
|
1 {1389908257, '8', 2.63071847153664e+15, "\342"}
|
|
1 {-90973704, '<', -2.10559053720692e-22, ""}
|
|
1 {-896549770, 's', 7.72155851221736e+30, "[\230m\304\2561\254Q"}
|
|
</pre>
|
|
The char and string output doesn't look pretty, since most are not printable,
|
|
eg: \342, \254
|
|
|
|
|
|
</body>
|
|
</html>
|