ФОРМАТИРОВАНИЕ ЧИСЕЛ ОДИНАРНОЙ ДЛИНЫ СО ЗНАКОМ
До сих пор мы форматировали только числа двойной длины без знака Xoтя структура <#...#> применима именно к таким числам, попробуем воспользоваться ею и для других типов чисел, выполнив определенные манипуляции со стеком. Например, рассмотрим простейший вариант системного определения D. (оно выводит число двойной длины со знаком):
: D. ( d -- ) DUP >R DABS <# #S R> SIGN #> TYPE SPACE ;
Слово SIGN, которое должно располагаться внутри выражения форматного вывода, вставляет знак "-" в строку символов лишь в том случае, если верхний символ в стеке является отрицательным. Следовательно, мы должны сохранить копию верхней ячейки (содержащей знак) в стеке возвратов для дальнейшего использования.
Так как <# требует наличия лишь чисел двойной длины без знака, мы должны взять абсолютное значение нашего числа двойной длины со знаком с помощью слова DABS. Теперь расположение аргументов в стеке соответствует выражению форматного вывода. Затем #S осуществляет перевод цифр справа налево, после чего мы заносим в стек знак. Если этот знак отрицательный, то SIGN добавляет к форматированной строке минус1. Так как нам нужно, чтобы знак минус располагался слева, включаем SIGN справа в структуру <;#..#!>. В некоторых случаях, например в бухгалтерских расчетах, может потребоваться вывод отрицательных чисел в виде 12345-. В подобной ситуации мы должны поместить слово SIGN слева в выражение <# ...#:>, как показано ниже:<# SIGN #S #>
1 Для пользователей более ранних систем. Слово SIGN имеет свою историю. Первоначально в качестве аргумента этого слова выступал третий элемент стека. Таким образом, для того чтобы определить слово D., нужно было писать
: D. ( d -- ) SWAP OVER DABS <# #S SIGN #> TYPE SPACE ;
Выражение "SWAP OVER" помещает копию верхней ячейки (той, что со знаком) на дно стека. Чтобы упростить выражение форматного вывода, операцию ROT решено было перенести в определение слова SIGN.
Данное соглашение действовало в системах фиг-Форт и системах полиФорт, разработанных до введения Стандарта-83.
В системах Форт-79 и Форт-83, а также Форт-системах МУР и MMS используется соглашение о передаче знака через вершину стека, что в большей степени соответствует механизму передачи данных через стек.
Если вы располагаете старой версией, определите SIGN следующим образом:
: SIGN ( n -- ) 0< IF ASCII - HOLD THEN ;
Определим слово, которое выводило бы число двойной длины со знаком с десятичной точкой и двумя десятичными значениями после точки. Поскольку такая форма часто используется для представления какой-либо суммы в долларах и центах, назовем это cлово .$ и определим его следующим образом:: .$ ( d -- ) DUP >R DABS <# # # ASCII . HOLD #S R> SIGN ASCII S HOLD #> TYPE SPACE ;
Проверим его: 2000.00 .$ $2000.00
или даже так:2,000.00 .$ $2000.00
Рекомендуем вам сохранить определение .$, которое пригодится нам в дальнейшем в некоторых примерах.
Вы можете также описать форматы чисел одинарной длины. Например, если вы хотите использовать число одинарной длины без знака, то просто поместите в стеке перед словом <# нуль. Такое число одинарной длины легко превратить в число двойной длины, которое настолько мало, что его часть, содержащаяся в верхней по порядку ячейке, равна нулю,
Для представления числа одинарной длины со знаком вам достаточно поместить нуль в старшую по порядку ячейку. Но вы также должны сохранить копию числа со знаком для SIGN и, кроме того, оставить абсолютное значение этого числа во втором элементе стека. Все необходимые действия выполняет следующее выражение: ( n -- ) DUP >R ABS 0 <# #S R> SIGN #>
Ниже приводятся «стандартные» выражения, которые применяются для вывода различных видов чисел: СЛОВУ <# ПРЕДШЕСТВУЕТ ВЫВОДИМОЕ ЧИСЛО ВЫРАЖЕНИЕ 32-разрядное без знака (ничего) 31-разрядное плюс знак DUP >R DABS (чтобы сохранить знак в третьем элементе стека для SIGN) 16-разрядное без знака 0 (чтобы получить фиктивную, старшую по порядку, часть) 15-разрядное плюс знак DUP >R ABS 0 (чтобы сохранить знак)