Числа и тензоры

NewLang является языком с динамической типизацией и явное указание типа не влияет на размер памяти, занимаемой переменной. Информация о типах используется при преобразовании значаений, когда существующему объекту присваивается значение другого типа. Такая операция возможна только тогда, когда типы совместимы между собой и допускают автоматическое приведение. Это справедливо как во время парсинга/компиляции исходного теста, так и во время выполнения в режимах интерпретатора и/или скомпилированного файла.

Арифметические типы данных

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

  • Целые числа, например, -1, 0, 1, 2, 3 и т.д.
  • Числа с плавающей точкой: Например, 1.2, 3.14159 и т.д.
  • Комплексные числа: Это числа с действительной и мнимой частями, каждая из которых является числом с плавающей точкой. Например, 1 + 2j, 3.14 - 4j и т.д.
  • Рациональные числа: Числа с неограниченной точностью, которое можно представить в виде обыкновенной дроби, например: 1\1 это запись дроби \( {\frac {1}{1}} \), т.е. единицы, а -55\3, это запись дроби \( {\frac {-55}{3}} \) и т.д.

Целые числа

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

Проблемы без знаковых чисел (из интернета):
Во-первых, вычитание двух без знаковых чисел, например 3 и 5. 3 минус 5 равно 4294967294, т.к. -2 не может быть представлено как без знаковое число. Во-вторых, непредвиденное поведение может возникнуть при смешивании целочисленных значений со знаком и без знака. С++ может свободно преобразовывать числа со знаком и без знака, но не проверяет диапазон, чтобы убедиться, что вы не переполняете свой тип данных.

Имена типов для целых чисел соответствуют их разрядности в битах и кратны степени двойки: :Int8, :Int16, :Int32, :Int64. Для взаимодействия с нативным C++ кодом у каждого типа есть беззнаковый синоним (:Byte, :Word, :DWord и т.д.), который может применяется при обращении к нативным функциям при их перегрузке.

Логический тип

Отдельным типом идет логический тип :Bool, который может принимать значения только 0 или 1 (false/true соответственно), и в зависимости от выполняемой операции тоже может быть отнесен к целочисленным типам, так и не входить в их состав (данный подход интерпретации логического типа данных был взят из библиотеки Torch).

// Treat bool as a distinct "category," to be consistent with type promotion
// rules (e.g. `bool_tensor + 5 -> int64_tensor`). If `5` was in the same
// category as `bool_tensor`, we would not promote. Differing categories
// implies `bool_tensor += 5` is disallowed.
//
// NB: numpy distinguishes "unsigned" as a category to get the desired
// `bool_tensor + 5 -> int64_tensor` behavior. We don't, because:
// * We don't want the performance hit of checking the runtime sign of Scalars.
// * `uint8_tensor + 5 -> int64_tensor` would be undesirable.

Числа с плавающей запятой и комплексные числа

Числа с плавающей обеспечиват моксимальное представление примерно 17 значимых разрядов, с экспонентой в диапазоне от -308 до 308?

Комплексные числа с действительной и мнимой частями, каждая из которых является числом с плавающей точкой. Например, 1 + 2j, 3.14 - 4j и т.д. Имена типов так же соответствуют разрядности в битах и кратны степени двойки: :Float16, :Float32, :Float64, :Complex16, :Complex32, :Complex64 и говорят сами за себя.

Рациональные числа

Для вычислений с неограниченной точностью в NewLang используются рациональные числа. Это число, которое можно представить в виде обыкновенной дроби \( {\frac {m}{n}} \), где числитель m — целое число, а знаменатель n натуральное (целое число больше нуля). В качестве разделителя дроби используется обратная косая черта, т.е. 1\1 - рациональное число 1, -5\1 - рациональное числа -5 и т.д.

Скаляры, массивы и тензоры

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

Нужно ли днлать динамические массивы отдельными типами??? :Array (std::vector), :ArrayBool (std::vector), :ArrayInt8 (std::vector<int8_t>), :ArrayByte (std::vector<uint8_t>) …,, :ArrayInt16, :ArrayInt32, :ArrayInt64 ?

Переменые с типом массив могут быть созданны как ссылочные, так и по значению, тогда как переменные тензоры всегда создаются как ссылочные и их значение нежет быть присовоены переменной по значению ????????????

Различие между численой переменной и тензором нулевого размера

Переменная - число, это элементарный тип данных, непосредственно обработываемый на аппаратнойм уровне, тогда как тензор нулевого размера - объект (тензор) с присущими ему особеностями. Конвертирование числа в тензор нулевого размера и обратно производится автоматически, если их типы совместимы.

Индексация массивов и тензоров

Доступ к элементам массива или тензора происходит по целочисленному индексу, который начинается с 0. Для многомерного тензора, индексы элемента перечисляются в квадратных скобках через запятую. Поддерживается доступ к элементам через отрицательный индекс, который обрабатывается точно так же, как в Python (-1 последний элемент, -2 предпоследний и т.д.).

В качесте индекса тензора могут быть использованы диапазоны которые обработываются точно так же как и в Python, а так же значение :None и многоточие .... Значение :None, т.е. отсуствие индекса, означает произвольный размер тензора в одном конкретном измерении, тогда как многоточие ... обозначет произвольную размерность в любом количестве измерений (поэтому может встречаться в индексе тензора только однократно).

Литерал тензор в тексте программы записывается в квадратных скобках с обязательной завершающей запятой, т.е. [1, 2,] — это литерал одномерный тензор из двух чисел. После закрывающей скобки тип тензора может быть указан в явном виде. Если тип не указан, то он выводится автоматически на основании указанных данных и выбирается минимально возможный байтовый размер, который позволяет сохранить все значения без потери точности.

Примеры создания тензоров и преобразования их размерности можно посмотреть тут.