· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.BOOKS —› Бентли "Жемчужины программирования"

Посл.отвђт Сообщенiе


Дата: Окт 3, 2003 07:47:09

Дж.Бентли "Жемчужины программирования" 2-е изд. - СПб.: Питер, 2002.
ISBN 5-318-00715-5

Автор замечаний к данному изданию - Аркадий Белоусов.
Его работы вы можете найти на alglib.dore.ru.
Они будут интересны для начинающих в области низкоуровнего
кодирования.

----------------------
- стр.29, задача 1: "если оперативная память ограничена парой сотен
килобайт"; стр.31: "лишь несколько сот байт оперативной памяти".

- стр.31: "Однако поле применения двоичного поиска не ограничивается быстрым
поиском в отсортированных массивах. Рой Вейл применил этот метод для
нахождения некорректной строки во входном файле, содержащем более 1000
строк. ... узнать о её наличии можно было, лишь обработав файл некоей
программой и получив некорректный ответ ... Попробуйте догадаться, как
удалось Вейлу найти ошибку за десять попыток?" - как тут применим
двоичный поиск?

- стр.34: "22 (!)" - должно быть "22!" (см. примечание на стр.104 про O(n!)).

- стр.242, задача 2: у меня подозрение, что здесь выпало решение - идут
ссылки на первый и другие варианты, но собственно решения нет.

- стр.243: "x[0..p-i]" - должно быть "x[0..p-i-1]".

- стр.36: о каких "временных файлах" идёт в задаче 4? Также, не понятно,
с чего говорится про двукратнаю разницу обмена и реверсирования. Алгоритм
реверсирования каждый элемент читает/пишет дважды, а алгоритм обмена это
делает однократно только в случае сдвига на n/2. Иначе количество обменов
больше: `br' меняется с `a', а потом он же меняется с `bl'. В случае
сдвига на единицу количество обменов растёт почти до 2n, хотя в среднем
это значение меньше. Как верно отметил сам Бентли, здесь та же
характеристика, что и у вычитательного (евклидовского) алгоритма НОД.

- стр.39, листинг 3.2: linenum следует переименовать в notstart, "linenum>0"
заменить на "notstart" и "linenum++" на "notstart=1", в противном случае
при количестве строк большем разрядности int (например, на 16-битной
платформе) в какой-то момент linenum опять станет равной 0.

* стр.58: "cantbe(m, n)" - должно быть "cantbe(m, n-1)".

- стр.61, задача 1: предлагается удостовериться, что программа не содержит
ошибок времени исполнения, но они там есть - в функции двоичного поиска
середина вычисляется как (l+u)/2, но это выражение даст переполнение
когда позиции искомого элемента > max(n)/2. Выражение, не подверженное
этой болезни - l+(u-l)/2 (ограничение: u должно быть >= l).

- стр.62, задача 5: не сказано, что предложенное рекуррентное соотношение
является функцией Аккермана.

- стр.62, задача 7: "y[i]+1" - должно быть "y[i+1]".

- стр.63, задача 9: "итеративная версия [вычисления n-й степени числа за
логарифмическое время] достаточно сложна" - это далеко не так.

- стр.71: "n=1..100 позволяет проверить случай с пустым массивом" - должно
быть "n=0..100".

- стр.72: ticks, а не clicks; умножить на 1e9, а не разделить; "344,5
наносекунд", а не "тиков".

- стр.72: "_Полное_ время выполнения _всех_ тестов" - должно быть "Среднее
время выполнения каждого теста".

- стр.90-91: "5000 дней" в таблицах (четыре раза) - должно быть "5000 год".

- стр.91: "Увеличение n на 1 увеличивает время выполнения на 12%" - с чего
увеличение на 1 должно увеличивать на 12% (в 1.12 раз)?

- стр.97: "Illiteracy and Ins Consequences" - наверное, "Its"?

- стр.102: "for(i = m; i >= l; i--)" - при беззнаковом i и l=0 будет ошибка.

- стр.105, рис.8.2: обратный порядок наименований (снизу вверх должны идти
"наносекунда", "микросекунда" и т.д., а не наоборот).

- стр.111: "В решении 2.3 ... содержащий ... % n" - нет там модуля, там уже
оператор if вместо модуля.

- стр.113: "Мы полагаем, что массив уже выделен, поэтому имеется возможность
временно затереть значение x[n]" - нужно не предполагать, а знать. Факт:
в тестовой программе search.c (где n идёт после x) при указании n=MAXN
второй и третий варианты последовательного поиска работают неправильно.

- стр.117: "Она учитывает возможность автоматической оптимизации,
обеспечиваемой при компиляции" - каким образом ручная оптимизация
(убирание лишних переменных и вынос общих операторов "за скобки")
учитывает "автоматическую оптимизацию"?

- стр.121, задача 10: "кэширование" - должно быть "хэширование".

- стр.253, задача 12: "i >= 0; i--" в заголовке цикла - то же замечание,
что и по стр.102. Так эта проблема обходится (без потери эффективности):

i = n;
while (i > 0) {
i--;
...

- стр.126: "используется массив из 200 указателей и 200 записей, каждая из
которых содержит целое и два указателя... указатели займут 800 байт" -
записей 2000, в них по 2 целых и 1 указателю; указатели займут 8000 байт
(4 байта*2000 записей). Либо следует сказать так: "массив из 200 указателей
(... займут 800 байт) и 2000 записей, каждая из которых содержит...".

- стр.126: "стрелки указывают на те элементы, индексы которых хранятся в
нижнем массиве" - не нижнем массиве (нижний - firstincol), а "в массиве
row". "Точки в столбце i" - должно быть либо "Номера строк и номера самих
точек из столбца i", либо "Точки из столбца i описываются в массивах...".

- стр.127: "в 1-байтовых беззнаковых целых (_char_)" - должно быть
"unsigned char".

- стр.127: "объём памяти до 6400 байт" - должно быть 6402=(2+1)*2000+2*201.

- стр.127: "Можно и вовсе избавиться от массива row, помещая соответствующую
координату точки в _её запись_ [должно быть в "структуру данных точки"]
... Это уменьшает занимаемый объём до 4400 байт" - перенос номеров строк
из отдельного массива в структуры занимаемой памяти не уменьшает. "могли
бы добавить в структуру данных точки обе её координаты и достигли бы
максимального уменьшения объёма" - опять же, общий "объём" не уменьшится,
а поиск усложнится, поэтому эти формулировки как минимум сбивают с толку.

- стр.127: "Даже если не добавлять в структуру точки эти поля, объём памяти
структуры можно уменьшить до 4000 байт" - должно быть "объём памяти
_индексирующей_ структуры".

- стр.127: "нет необходимости в массиве row, если есть массив col, потому
что к последнему мы обращаемся только через массив firstincol" - фраза
не понятна и к тоиу же массив col нигде не описан, не считая его
упоминания также на стр.129.

- стр.135, задача 5: "на каждый из элементов приходилось несколько битов
(_одна десятичная цифра_"; стр.253, решение: "функция позволяла получить
ответ приближённо, а недостающая точность достигалась прибавлением _одной
десятичной цифры, бравшейся из массива_" - где здесь сокращение памяти?

- стр.146: "более робастные" - использование малораспространённых терминов
ухудшает качество (читабельность, понимаемость) текста. Возможно, здесь
лучше использовать (вместо или вместе) слова типа "надёжные", "сильные".

* стр.148: "if u-l > cutoff" - должно быть "if u-l < cutoff".

- стр.149: "Функция qsort состоит из 15 строк быстрой сортировки и 5 строк
сортировки вставкой" - это описание qsort4 (а не сишной qsort).

- стр.150: "при получении статистических данных (минимум, максимум, среднее,
медиана и мода распределения)" - я знаю первые три функции и догадываюсь,
что такое "медиана" (либо половина суммы минимума и максимума, либо
средний элемент последовательности после сортировки); но что такое "мода
распределения"?

- стр.151: "стабильность (элементы с одинаковыми ключами должны оставаться в
исходном порядке" - в переводах Кнута и Вирта использовано слово
"устойчивость".

- стр.155: "вероятность ... становится нулевой, как только m чисел уже
набрано" - не "m", а "n"; не "нулевой", а "бесконечной"; больше набрать
нельзя не из-за вероятности, а потому-что не из чего будет выбирать.

- стр.156: "В этом алгоритме нет выделенных элементов" - это как?

- стр.157: "метод ... уменьшает время выполнения до O(m log m). ... К
сожалению, этот метод работает за время O(n)" - противоречие.

* стр.157: "Предположим, что n=10_000_000, а m=2^31" - перепутаны n и m.

- стр.256, задача 2: "m целых ... затем вернуть i, i+1, ... при
необходимости округляя их к нулю" - как можно "округлять" целые? И
возвращать нужно не "i, i+1 ...", а "i%n, (i+1)%n ...".

- стр.236, задача 12.4: "задача сборщика билетов" - на стр.257 использовано
название "задача коллекционера".

* стр.257, задача 7: нужно убрать "или выводить значение n+1-i, а не само i".

- стр.160, задача 11: "карты с ... точками, под которыми ... числа" -
наверное, лучше не "точки", а "позиции"?

- стр.169: "BITSPERWORD = 32" - это называется "плохой, непортабельный
стиль". Характеристики типа надо не предполагать, а вычислять. И хотя
C/C++ для этого неудобны, однако там есть заголовок limits.h и следует
использовать выражение "sizeof(int)*CHAR_BIT".

- стр.169: "1 + hi/BITSPERWORD" - опять неточное выражение (в случае hi
кратного BITSPERWORD это выражение на единицу больше точного). Должно
быть: "(hi+BITSPERWORD-1)/BITSPERWORD".

- стр.171: "1 + maxval/bins" - опять неточное выражение.

- стр.171: "Таблица 8.2" - должно быть "13.2".

- стр.173, задача 5: "решении задачи 9" - должно быть "2".

- стр.177: "Кучи" - heapsort обычно переводится как "пирамидальная
сортировка" и heap здесь - это пирамида, а не куча. Аналогично дальше -
"свойство формы" звучит несколько необычно.

- стр.179: "Избежать проблем в языке C проще всего, объявив массив x[n+1] и
забыв о нулевом элементе" - проблем нет и без потери места. Вот как
должны выглядеть при этом индексы:

root = 1-1 = 0
left(i) = 2*(i+1)-1 = 2*i+1
right(i) = 2*(i+1)+1-1 = 2*i+2 = 2*(i+1)
parent(i) = (i+1)/2-1 = (i-1)/2

- стр.184: "с помощью двоичного поиска за время O(n)" - наверное, O(log n)?
Также в этом абзаце неясно, о каком типе структур речь, но "двоичный
поиск" и "перемещение элементов", наверное, означают "упорядоченную
последовательность" (см. предыдущий абзац на предыдущей странице)?

- стр.185: "Функции insert и extractmin на куче ... за время O(n)" -
наверное, O(log n)?

- стр.186: "упорядоченную последовательность элементов, увеличивающуюся
слева направо" - слева направо последовательность будет _отсортирована_, а
_увеличивается_ она справа налево.

- стр.188: "Свойства формы и порядка ... форму инварианта - они являются
инвариантными свойствами" - это была попытка поиграть словами?

- стр.189, задача 2: "за время O(n)" - наверное, O(n log n)? [Должен ли я
напоминать о существовании доказательство того, что алгоритмы на базе
сравнений не могут быть лучше O(n log n)?]

- стр.261, задача 2: "maxheap()" - наверное, "heap()"? "строит кучу за
время O(n)" - наверное, O(n log n)?

- стр.192, табл.15.1: "unto", "thou" - в Библии используются такие "слова"
или где-то более длинные слова оказались обрезаны до четырёх знаков?

- стр.200: "добавим к нему k символов \0" - достаточно только 1 символ \0,
особенно с отдельной функцией skip() (см. ниже).

- стр.200: перепутаны word[6] и word[7] на рисунке.

- стр.201, листинг 15.11: "выбираем одну, на которую указывает p" - должно
быть "выбираем одну и запоминаем её адрес в p" (в первом варианте можно
решить, будто выбор происходит на основании значения p).

- стр.201, листинг 15.12: нигде не описана функция skip().

- стр.204, задача 9: "даны два _текста_" - должно быть "строки" (см. также
решение на стр.264).

- стр.264, задача 9: "при сканировании массива используйте исключающее ИЛИ"
- каким образом? "строка начинается до границы раздела" - какого раздела?

- стр.264, задача 14: "n-" - должно быть "n--".

* стр.264, задача 14: пропущено имя "p" в заголовке "hash(char *)".

- стр.212: "Схема алгоритма слияния набросана в задаче 14.4.4" - должно быть
"14.4.г".

- стр.214: "значения счётчика программы (задача 10.8)" - должно быть "10.7".

- стр.214: "В разделе 8.1 показано уменьшение времени выполнения программы
за счёт помещения ... в кэш" - в этом разделе про кэш ничего не говорится.

- стр.215: "В задаче 2.8 описана проблема выбора k-го минимума" - в этой
задаче не описана эта проблема.

- стр.215: "упоминаются в задачах ... 14.4.3" - должно быть "14.4.в".

- стр.215: "схема инициализации разреженных векторов ... применяется в
разделе 11.3" - этот раздел посвящён только qsort.

- стр.216: "В задаче 3.7 показана схема алгоритма оценки линейных
рекуррентных соотношенией" - нет там такого.

- стр.216: "в задачах 11.1 и 14.4.b" - должно быть "14.4.б".

- стр.217: "длина в ... милях", "вес ... в фунтах", "длина ... в футах" -
вообще-то мы живём в России и (обобщая) в Европе, в которых (не считая
старожилов Британии) принята метрическая система. Впрочем, в Америке она
тоже принята, хотя из-за... не будем уточнять чего амерканцев и не
заменила ещё имперскую систему. Я хочу сказать, что если в беллетристике
ещё допустимо использование авторских единиц в качестве экзотики и
колорита, что обычно не сильно влияет на художественную ценность
произвдения (хотя и жутко раздражает, что я не могу с ходу понять, что
скрывается за той или иной количественной харакеристикой персонажа или
объекта), то для технической литературы это обычно не допустимо. Не говоря
уже о неоднозначности: мили бывают разные, имперские и американские
единицы тоже отличаются... Позор.

- стр.220: "int thisp = (int)p" - должно быть "(ptrdiff_t)p" или хотя бы
"(long)p".

- стр.220: "с именем структуры в качестве первого аргумента и тем же именем
в кавычках" - во-первых, для этого достаточно использовать первый аргумент
с префиксом #, во-вторых, этот префикс уже использован в timemod.c.

- стр.221: "fi = i" - во-первых, эта инструкция должна быть частью только
тех инструкций, которые пользуются переменной fi; во-вторых, в этом коде
не выполняется "выравнивания" на границу тика перед началом теста, поэтому
измерение в M(op) с тем большей погрешностью, чем больше значение trials.

- стр.224: "В решении 10.6 сдвиг и логические операции заменены обращением к
таблице" - всё наоборот. Точнее, там арифметические операции заменены
обращением к таблице, которое уже заменено логическими операциями.

- стр.225: "В главе 13 маркеры применяются" - нет их там.

- стр.225: "В решении 14.4 маркер ставится" - должно быть "14.1".

- стр.225: "Дорогостояющую логическую операцию можно заменить на
эквивалентную её алгебраическую, которая будет вычисляться быстрее" -
полная "дичь". Всё наоборот - если сложение и вычитание ещё сравнимы с со
_всеми_ логическими операциями, то уж умножение и деление намного хуже. И
если на старых процессорах сдвиг на значение больше единицы был не самой
быстрой операцией, то уж во всяком случае быстрее умножений и делений.

- стр.226: "В решении 9.6 приведена схема проверок, порядок которых может
быть изменён" - там _нет_ схем проверок, порядок которых можно менять.

- стр.226: "В решении 9.6 описана реализация ... функции" - должно быть
"функций", во множественном числе.

- стр.231: см. моё замечание про BITSPERWORD на стр.169.

- стр.232: "// CHECK !" - похоже, забыли убрать служебную информацию.


Дата: Окт 8, 2003 09:13:04

Про звёздочки и палочки.
Я на 100% не уверен.
Но по-моему знаком "-" Аркадий пометил ошибки,
которые отрыл сам, а знаком "*" те которые уже
опубликованны на оригинальном (не нашего издания) сайте
книги. http://netlib.bell-labs.com/cm/cs/pearls/errata.html
Эти ошибки имееют тем не менее ценность и в данном
топике, поскольку страницы оригинального издания и русского
не совпадают. У Аркадия поставлены страницы где эти ошибки
встречаются именно в русском издании.


Дата: Окт 8, 2003 18:07:42

стр. 235
Глава 8
...
7. Сложение с плавающей точкой не всегда коммутативно.

Должно быть ... не всегда ассоциативно.


Дата: Окт 10, 2003 08:26:14

стр. 23. Постановка задачки по сортировке файла.
Цитата:

Если мы отведём под каждое число 7 байт,
в доступном мегабайте оперативной памяти поместится 143000 номеров.

Комментарий:
поместится на самом деле полными 149796 номеров.
далее цитата:

Если использовать 32х битное представление целых чисел,
в тот же мегабайт поместится уже 250000 номеров.

Комментарий:
конечно же поместится 262144 номера.
Дальше оценки проверять нет смысла, неточность её распространяется
на все остальные куски где это значение используется.


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.209