Тест на мужчину или мальчика - Man or boy test
Тест « мужчина или мальчик» был предложен компьютерным ученым Дональдом Кнутом как средство оценки реализаций языка программирования ALGOL 60 . Цель теста состояла в том, чтобы отличить компиляторы, которые правильно реализовали « рекурсию и нелокальные ссылки », от компиляторов , которые этого не сделали.
Существует довольно много трансляторов ALGOL60, которые были разработаны для правильной обработки рекурсии и нелокальных ссылок, и я подумал, что, возможно, небольшая тестовая программа может оказаться полезной. Поэтому я написал следующую простую процедуру, которая может отделить компиляторов-мужчин от компиляторов-мальчиков.
Пример Кнута
В АЛГОЛЕ 60 :
begin real procedure A(k, x1, x2, x3, x4, x5);
value k; integer k;
real x1, x2, x3, x4, x5;
begin real procedure B;
begin k := k - 1;
B := A := A(k, B, x1, x2, x3, x4)
end;
if k ≤ 0 then A := x4 + x5 else B
end;
outreal(A(10, 1, -1, -1, 1, 0))
end;
Это создает дерево кадров вызова B, которые ссылаются друг на друга и на содержащиеся кадры вызова A , каждый из которых имеет свою собственную копию k, которая изменяется каждый раз, когда вызывается связанный B. Попытка проработать это на бумаге, вероятно, бесполезна, но для k = 10 правильный ответ -67, несмотря на то, что в исходной статье Кнут предположил, что это будет -121. В обзорной статье Чарльза Линдси, упомянутой в ссылках, содержится таблица для различных начальных значений. Даже современные машины быстро исчерпывают пространство стека для больших значений k , которые приведены в таблице ниже ( OEIS : A132343 ).
k | |
---|---|
0 | 1 |
1 | 0 |
2 | −2 |
3 | 0 |
4 | 1 |
5 | 0 |
6 | 1 |
7 | −1 |
8 | −10 |
9 | −30 |
10 | −67 |
11 | −138 |
12 | −291 |
13 | −642 |
14 | −1446 |
15 | −3250 |
16 | −7244 |
17 | −16 065 |
18 | −35 601 |
19 | −78 985 |
20 | −175 416 |
21 год | −389 695 |
22 | −865 609 |
23 | −1 922 362 |
24 | −4 268 854 |
25 | −9 479 595 |
26 год | −21 051 458 |
Объяснение
В этой программе используются три функции Algol, которые может быть сложно правильно реализовать в компиляторе:
- Определения вложенных функций : поскольку B определяется в локальном контексте A , тело B имеет доступ к символам, которые являются локальными для A - в первую очередь k , который он изменяет, но также x1 , x2 , x3 , x4 и x5 . Это просто в потомке Algol Паскаля , но невозможно в другом главном потомке C (без ручного моделирования механизма с помощью оператора адреса C, передавая указатели на локальные переменные между функциями).
-
Ссылки на функции : B в рекурсивном вызове
A(k, B, x1, x2, x3, x4)
- это не вызов B , а ссылка на B , которая будет вызываться только тогда, когда k больше нуля. Это просто в стандартном Pascal ( ISO 7185 ), а также в C. Некоторые варианты Pascal (например, более старые версии Turbo Pascal ) не поддерживают ссылки на процедуры, но когда набор функций, на которые можно ссылаться, известен заранее (в этом программа это только B ), это можно обойти. -
Дуализм констант / функций : параметры от x1 до x5 в A могут быть числовыми константами или ссылками на функцию B -
x4 + x5
выражение должно быть подготовлено для обработки обоих случаев, как если бы формальные параметры x4 и x5 были заменены соответствующим фактическим параметром ( call по имени ). Вероятно, это больше проблема в языках со статической типизацией, чем в языках с динамической типизацией, но стандартный обходной путь - переинтерпретировать константы 1, 0 и -1 в основном вызове A как функции без аргументов, которые возвращают эти значения.
Однако тест не об этом; они всего лишь предварительные условия для того, чтобы тест был хоть сколько-нибудь значимым. Что тест о ли различных ссылках на B решимость к правильному экземпляру B - тот , который имеет доступ к тем же А -локальным символам , как B , создавшей ссылке. Компилятор "мальчик" мог бы, например, вместо этого скомпилировать программу так, чтобы B всегда обращался к самому верхнему кадру вызова A.
Смотрите также
Рекомендации
Внешние ссылки
- Примеры тестов "мужчина или мальчик" на многих языках программирования