Автор Тема: Семантика SHORT(x) в Компонентном Паскале  (Прочитано 33168 раз)

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Семантика SHORT(x) в Компонентном Паскале
« : Декабрь 22, 2012, 03:49:36 pm »
Цитировать
PROCEDURE (wr: StdWriter) WriteChar (ch: CHAR);
VAR ... fw: Files.Writer;
BEGIN
    ...
    fw.WriteByte(SHORT(SHORT(ORD(ch))));
    fw.WriteByte(SHORT(SHORT(ORD(ch) DIV 256 - 128)));
    ...
END WriteChar;
Первый SHORT (правый) преобразует результат операции DIV к типу SHORTINT, второй - к типу BYTE. Если результат операции DIV оказался больше 127, то во время выполнения второго SHORT произойдёт ошибка. Для этого и понадобилось отнимать 128.
Решил проверить выделенное утверждение. Результат меня удивил.

Вот тестовый код:
Цитировать
PROCEDURE Do*;
VAR x: SHORTINT; b: BYTE;
BEGIN
    x := 1000;    (* явно больше MAX(BYTE) *)
    b := SHORT(x);  (* возникнет ли ошибка RunTime? *)
    Log.Int(b); Log.Ln;
END Do;
Результат: b = -24

В сообщении о языке написано:
Цитировать
Name             Argument type     Result type        Function
SHORT(x)       SHORTINT            BYTE                identity
Впрочем, наверное ничего удивительного нет. Дело видимо в том, что по умолчанию в компиляторе не все проверки включены. И то, что заявленное identity не выполняется, остаётся не замеченным.
Если же все проверки включить, то код из процитированной темы при выполнении вероятно выдаст ошибку.

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #1 : Декабрь 22, 2012, 04:05:21 pm »
Цитировать
    fw.WriteByte(SHORT(SHORT(ORD(ch))));
    fw.WriteByte(SHORT(SHORT(ORD(ch) DIV 256 - 128)));
...
Если же все проверки включить, то код из процитированной темы при выполнении вероятно выдаст ошибку.
Хочу уточнить. Ошибку может вызвать первая строчка. А вторая, благодаря "-128", - не приведёт к ошибке.
Очевидно, что первая строчка пишет (по замыслу авторов) младший байт кода ch, а вторая - старший байт. Ибо, как правильно подметил ilovb, операция x DIV 256 равносильна арифметическому сдвигу на восемь символов вправо.

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #2 : Декабрь 22, 2012, 04:21:37 pm »
Цитировать
allchecks - добавить в исполняемый модуль код, выполняющий дополнительные проверки (переполнение и выход за диапазон значений для целых чисел).
Секреты компилятора

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #3 : Декабрь 22, 2012, 04:24:33 pm »
Предлагаю исправленный вариант процедуры WriteChar() из модуля TextModels в Блэкбоксе:
Цитировать
    ...
    fw.WriteByte(SHORT(SHORT(ORD(ch) MOD 256 - 128)));
    fw.WriteByte(SHORT(SHORT(ORD(ch) DIV 256 - 128)));
    ...

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #4 : Декабрь 22, 2012, 04:29:34 pm »
Секреты компилятора
Эта статья написана мной  :)
Правда, указывать сей факт на Оберонкоре не сочли нужным...

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #5 : Декабрь 22, 2012, 04:44:15 pm »
Предлагаю исправленный вариант процедуры WriteChar() из модуля TextModels в Блэкбоксе:
Цитировать
    ...
    fw.WriteByte(SHORT(SHORT(ORD(ch) MOD 256 - 128)));
    fw.WriteByte(SHORT(SHORT(ORD(ch) DIV 256 - 128)));
    ...
А зачем? Какой в этом смысл?
Пусть будет переполнение.

ps И оно возникает кстати не на больших числах, а на отрицательных в данном случае
« Последнее редактирование: Декабрь 22, 2012, 04:47:50 pm от ilovb »

Илья Ермаков

  • Sr. Member
  • ****
  • Сообщений: 493
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #6 : Декабрь 22, 2012, 04:44:58 pm »
В итоге получается, что:

- если забыть про то, что SHORT должен, в идеале, генерировать авост при искажении значения, то можно и не делать -128. Будет однохренственный результат (SHORT просто отбросит старшие биты - и будет то же самое, что и SHORT от отрицательного числа).
- но если вспомнить про правильную семантику SHORT, то нужно делать -128, чтобы SHORT^2 для интервала 128..255 не повлёк авоста.

Я лично забыл про правильную семантику... и давно уже считал, что SHORT просто отбросит старшие биты.
Хы, век живи - век учись.

Илья Ермаков

  • Sr. Member
  • ****
  • Сообщений: 493
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #7 : Декабрь 22, 2012, 04:47:11 pm »
Эта статья написана мной  :)
Правда, указывать сей факт на Оберонкоре не сочли нужным...

Игорь, внизу указано авторство И. С. Горячева. Т.е. это ошибка?

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #8 : Декабрь 22, 2012, 05:10:05 pm »
Игорь, внизу указано авторство И. С. Горячева. Т.е. это ошибка?
Да, это ошибка.
Евгений Темиргалеев должен быть в курсе, потому что это он мне предложил тогда написать статью.

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #9 : Декабрь 22, 2012, 06:01:06 pm »
Предлагаю исправленный вариант процедуры WriteChar() из модуля TextModels в Блэкбоксе:
Цитировать
    ...
    fw.WriteByte(SHORT(SHORT(ORD(ch) MOD 256 - 128)));
    fw.WriteByte(SHORT(SHORT(ORD(ch) DIV 256 - 128)));
    ...

К сожалению, предложенный мной вариант не верен.  :)
Он хоть и позволяет избежать авоста при включенных проверках, но при этом даёт неверный результат. А если быть точным, то он даёт ошибку в старшем бите обоих байтов (и младшего, и старшего).

Правильный вариант (надеюсь  :) ) всё же такой:
Цитировать
    IF (ORD(ch) MOD 256) < 128 THEN
       fw.WriteByte(SHORT(SHORT(ORD(ch) MOD 256)));
    ELSE fw.WriteByte(SHORT(SHORT(ORD(ch) MOD 256 - 256)));
    END;
    IF (ORD(ch) DIV 256) < 128 THEN
       fw.WriteByte(SHORT(SHORT(ORD(ch) DIV 256)));
    ELSE fw.WriteByte(SHORT(SHORT(ORD(ch) DIV 256 - 256)));
    END;

Если же отключить все проверки (чтобы не мешали  :)  ), то для избежания ошибок данный фрагмент кода следует изложить в такой редакции:
Цитировать
    fw.WriteByte(SHORT(SHORT(ORD(ch))));
    fw.WriteByte(SHORT(SHORT(ORD(ch) DIV 256)));

Вроде получается так, что хоть при включенных проверках, хоть при выключенных, - данный кусок кода в Блэкбоксе требует правки.

Илья Ермаков

  • Sr. Member
  • ****
  • Сообщений: 493
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #10 : Декабрь 22, 2012, 06:03:42 pm »
Игорь, я постраюсь в ближайшее время прояснить вопрос.
У меня есть гипотеза, что "Иван Горячев" появилось из ника i-gor, но я не представляю, кто именно так ошибся.

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #11 : Декабрь 22, 2012, 06:17:21 pm »
Игорь, я постраюсь в ближайшее время прояснить вопрос.
Хорошо. Мне удалось отыскать сообщение Евгения Т.:
http://forum.oberoncore.ru/viewtopic.php?p=31860#p31860

PS: Кстати, та тема на Оберонкоре немного перекликается с данной темой.

igor

  • Sr. Member
  • ****
  • Сообщений: 438
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #12 : Декабрь 22, 2012, 06:35:07 pm »
Предлагаю исправленный вариант процедуры WriteChar() из модуля TextModels в Блэкбоксе:
А зачем? Какой в этом смысл?
Пусть будет переполнение.
Как это зачем? Вот, решите вы прогнать свой проект со всеми включенными проверками, для очистки совести, так сказать  :). А он возьмёт, да и срубиться на этих строчках кода.

К тому же, если вы решите перейти на другой компилятор, то где гарантия, что в нём "SHORT просто отбросит старшие биты"? Это особенность конкретной реализации, на которую закладываться не стоит.

ilovb

  • Hero Member
  • *****
  • Сообщений: 2538
  • just another nazi test
    • Просмотр профиля
    • Oberon systems
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #13 : Декабрь 22, 2012, 07:07:43 pm »
Ну да, неудобство в наличии. Если чесна я бы вшил это в язык (извлечение байтов)

Илья Ермаков

  • Sr. Member
  • ****
  • Сообщений: 493
    • Просмотр профиля
Re: Семантика SHORT(x) в Компонентном Паскале
« Ответ #14 : Декабрь 22, 2012, 07:21:49 pm »
В принципе, это цепляние к конкретной заоптимизированной реализации текстов.

А так для записи-чтения CHAR-ов предполагается использование Stores.Reader/Writer.
Ну или для более независимого от Stores способа - своего какого-либо Mappera.

В любом случае, Вы не будете ведь всякие преобразования форматов размазывать по коду.
У меня вот Unsigned-преобразования собраны в отдельном модуле...