Skip to content

Commit

Permalink
Реализована библиотечная функция Random (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mazdaywik committed Nov 19, 2019
1 parent f211513 commit ff4de28
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
18 changes: 18 additions & 0 deletions autotests/random.ref
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
$ENTRY Go {
= <Prout <Random 10>>
<Len 3 <Random 3>>
<Len 2 <Random 2>>
<Len 1 <Random 1>>
<Len 1 <Random 0>>
}

Len {
3 s.1 s.2 s.3 = ;
3 s.1 s.2 = ;
3 s.1 = ;

2 s.1 s.2 = ;
2 s.1 = ;

1 s.1 = ;
}
86 changes: 85 additions & 1 deletion lib/Library.c
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,90 @@ R05_DEFINE_ENTRY_FUNCTION(Compare, "Compare") {
}


/**
64. <Random s.Len> == e.RandomDigits
e.RandomDigits ::= s.NUMBER+
|e.RandomDigits| == ((s.Len != 0) ? s.Len : 1)
*/
static r05_number random_digit_in_range(r05_number max);
static r05_number random_digit(void);

R05_DEFINE_ENTRY_FUNCTION(Random, "Random") {
struct r05_node *callable = arg_begin->next;
struct r05_node *pcount = callable->next;
r05_number count;

if (R05_DATATAG_NUMBER != pcount->tag || pcount->next != arg_end) {
r05_recognition_impossible();
}

count = pcount->info.number;
count = count > 0 ? count - 1 : 1;
count = random_digit_in_range(count) + 1;

r05_reset_allocator();
while (count > 0) {
r05_alloc_number(random_digit());
--count;
}

r05_splice_from_freelist(arg_begin);
r05_splice_to_freelist(arg_begin, arg_end);
}

static r05_number random_digit_in_range(r05_number limit) {
const r05_number MAX = ~0;
r05_number max_valid;
r05_number random;

if (limit == 0) {
return 0;
}

max_valid = MAX - MAX % limit;

do {
random = random_digit();
} while (random >= max_valid);

return random % limit;
}

/*
Метод Фибоначчи с запаздываниями.
См. D. E. Knuth, The Art of Computer Programming,
Volume 2, chapter 3.2.2, program A
*/
static r05_number random_digit(void) {
enum { cMinDelay = 24, cMaxDelay = 55 };

static int init = 0;
static size_t k = cMaxDelay - 1;
static size_t j = cMinDelay - 1;
static r05_number y[cMaxDelay];

r05_number result;

if (! init) {
r05_number seed = (r05_number) time(NULL);
size_t i;

for (i = 0; i < cMaxDelay; ++i) {
seed = seed * 1103515245 + 12345;
y[i] = seed;
}

init = 1;
}

result = y[k] = y[k] + y[j];
k = (k + cMaxDelay - 1) % cMaxDelay;
j = (j + cMaxDelay - 1) % cMaxDelay;

return result;
}


/**
66. <Write e.Expr> == []
*/
Expand Down Expand Up @@ -1126,7 +1210,7 @@ R05_DEFINE_ENTRY_FUNCTION(ListOfBuiltin, "ListOfBuiltin") {
ALLOC_BUILTIN(61, Compare, regular)
/* ALLOC_BUILTIN(62, DeSysfun, regular) */
/* ALLOC_BUILTIN(63, XMLParse, regular) */
/* ALLOC_BUILTIN(64, Random, regular) */
ALLOC_BUILTIN(64, Random, regular)
/* ALLOC_BUILTIN(65, RandomDigit, regular) */
ALLOC_BUILTIN(66, Write, regular)
ALLOC_BUILTIN(67, ListOfBuiltin, regular)
Expand Down

0 comments on commit ff4de28

Please sign in to comment.