Программирование на Athanor - 1 (операции над числами)

Цикл: "Программирование на Athanor": Часть 1 (Числовые данные и операции над ними)
11 декабря 2025, четверг 16:30
trilirium для раздела Блоги

Числовые скаляры и операции над ними

Скалярными значениями (скалярами) в Athanor называются числа и строки. Это – простейшие типы данных из всех доступных в языке. Общее свойство всех скаляров – их неизменяемость (иммутабельность). Говоря проще, сами числа и строки изменять нельзя (но можно создавать и присваивать новые).

Простейший вид числовых значений – литералы. Их синтаксис, в общем, типичен для большинства языков программирования. Вот некоторые примеры допустимых числовых литералов:

  • 10
  • 123321
  • 122.344
  • 3.141592653
  • 6.022e23

Первые два литерала – целые, остальные – плавающие. Целочисленные литералы в тексте программы могут задаваться не только в десятичной форме. Если перед литералом стоит префикс '\x' – литерал шестнадцатиричный; префикс '\o' – он восьмеричный; префикс '\b' – он двоичный.

Скалярные операции, как правило, имеют операндами один или два скалярных значения, и возвращают скаляр в качестве результата. Каждая из операций имеет или операторную (синтаксическую, более удобную и привычную глазу) форму, или же (внутреннюю) функциональную форму. По типу своих операндов – эти операции можно разделить на числовые и строковые.

Кроме того, все операции языка (они же функторы) можно классифицировать по количеству операндов (их арности): они могут быть с одним операндом (унарные), с двумя операндами (бинарные), с тремя операндами (тернарные), вообще не иметь операндов (нульарные) или иметь их произвольное количество (таких тоже есть довольно много).

Вот основные бинарные скалярные операции для числовых операндов:

A + B
add (A,B)
сумма A и B
A - B
sub (A,B)
разность A и B
A * B
mul (A,B)
произведение A и B
A / B
div (A,B)
частное A и B
A % B
idiv (A,B)
целочисленное деление A на B
A %% B
irem (A,B)
остаток от целого деления A на B


А вот важнейшие унарные скалярные операции:

- A
neg (A)
арифметическое отрицание A
+ A
abs (A)
абсолютная величина (модуль) A
~ A
not (A)
битовое дополнение A
(битовое «НЕ»)


В языке также определены отдельные специальные операции для максимума и минимума из двух операндов:

A ?< B
min (A,B)
меньшее из значений A и B
A ?> B
max (A,B)
большее из значений A и B


Для целых чисел также определены операции сравнения, побитовые логические операции и сдвиги:

A & B
and (A,B)
битовое «И» для A и B
A | B
or (A,B)
битовое «ИЛИ» для A и B
A ~ B
xor (A,B)
битовое исключающее «ИЛИ» для A и B
A << B
shl (A,B)
сдвиг A на B битов влево
A >> B
shr (A,B)
сдвиг A на B битов вправо

Внимание: для операции xor используется именно синтаксис "A ~ B" – но не "A ^ B", как в C или Perl!

Бинарные операции сравнения являются предикатами: они возвращают в качестве результата значение 0, если условие ложно, или 1, если оно истинно.

A < B
lt (A,B)
A меньше B?
A <= B
A ~> B
le (A,B)
A меньше или равно B?
A > B
gt (A,B)
A больше B?
A >= B
A ~< B
ge (A,B)
A больше или равно B?
A == B
eq (A,B)
A равно B?
A <> B
A ~= B
ne (A,B)
A не равно B?

(На последнее также важно обратить внимание: запись "A != B" в языке не поддерживается! Однако, вполне допускается "A ~> B" вместо "A <= B"; "A ~< B" вместо "A >= B" и "A ~= B" вместо "A <> B".)

Отдельная операция (компаратор) сравнивает свои операнды на упорядоченность:

A <?> B
cmp (A,B)
Взаимная упорядоченность A и B 

Она возвращает в качестве результата -1 (если A < B), +1 (если A > B) или 0 (если операнды равны). Она весьма полезна, например, для использования в операциях сортировки, которые будут рассмотрены позднее.

Наконец, для числовых значений также определен ряд стандартных математических функций. Специальной синтаксической записи для них не предусмотрено, только функциональная:     

floor (X)
округление X вниз (до ближайшего целого)
ceil (X)
округление X вверх (до ближайшего целого)
sqr (X)
квадратный корень из X
exp (X)
экспонента от X
log (X)
натуральный логарифм от X
exp_by (X,Y)
возведение X в степень Y
log_by (X,Y)
логарифм Y по основанию X
pi (X)
значение числа «пи», умноженное на X
sin (X)
синус X
cos (X)
косинус X
tan (X)
тангенс X
asin (X)
арксинус X
acos (X)
арккосинус X
atan (X)
арктангенс X
sinh (X)
гиперболический синус X
cosh (X)
гиперболический косинус X
tanh (X)
гиперболический тангенс X

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

Предусмотрено еще несколько функторов без аргументов (нульарных), возвращающих полезные константы:

min_int ()
наименьшее целое число
max_int ()
наибольшее целое число
nan ()
NaN («не-число», или арифметическая неопределенность)
inf_pos ()
положительная бесконечность
inf_neg ()
отрицательная бесконечность

В языке также доступен генератор равномерно распределенных (псевдо)случайных чисел:

rand (N)
Возвращает случайное неотрицательное число, меньшее N
randomize (Seed)
Инициализирует генератор СЧ начальным значением Seed.

В обеих операциях операнд может быть опущен. Если он не задан в rand() – возвращается произвольное неотрицательное целое. Если он не задан в randomize() – значение Seed также выбирается относительно случайным образом (обычно, на основе текущего времени). Генерируемая последовательность чисел весьма условно "случайна", и вряд ли подходит для "серьёзных" применений (например, криптографических).

Хотя мы говорили о "числовом" типе, на самом деле их два: целый и плавающий. Внутренне они всегда различаются! В большинстве случаев, это не особо принципиально, так как в языке действуют неявные приведения (коерсии) между числовыми типами. Операции, требующие исключительно целые операнды (такие, как битовые и сдвиги) – автоматически приводят плавающие операнды к целому типу; требующие только плавающие операнды (например, все математические) – обобщают целые операнды до плавающих. Некоторые бинарные операции (add, sub, mul, min, max) – выполняются как целые (и возвращают целый результат) только когда оба операнда целые. В противном случае операнды рассматриваются как плавающие, и результат будет такой же. Наконец, в языке предусмотрены и явные приведения:

  • int (N): явно привести операнд N к целому типу
  • float (N): явно привести операнд N плавающему типу

Приведение целых значений к плавающим вполне тривиально, при обратном – не только теряется дробная часть, но и принудительно ограничивается диапазон, от min_int() до max_int().

Наконец, для проверки принадлежности значения к числовым типам, предусмотрены и логические функторы-предикаты (как и многие другие предикаты в языке, они начинаются с префикса is_):

  • is_int (X): истина (1), если X – целое значение (иначе 0)
  • is_float (X): истина (1), если X – плавающее значение (иначе 0)
  • is_num (X): истина, если X – любое число (целое или плавающее)

Теги