Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.77/22: Рейтинг темы: голосов - 22, средняя оценка - 4.77
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30

Избыточное копирование объекта при реализации оператора умножения и оператора присваивания

21.03.2016, 18:43. Показов 5652. Ответов 84
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть класс работы с матрицами. Есть операция умножения матриц, описанная как оператор класса. В данном коротком примере я просто моделирую ситуацию. Реальное наполнение класса принципиальной разницы не играет, нужно просто понимать, что оператор умножения будет иметь большой код, оператор присваивания в реализации тоже будет не пустым. Эти места в примере засвечены комментариями

C++
#include <cstdio>
 
class Matrix
{
  private:
    // внутренние данные матрицы
 
  public:
    Matrix ();
    Matrix (const Matrix&);
    ~Matrix ();
 
    Matrix& operator=(const Matrix& a);
    Matrix operator*(const Matrix& a) const;
};
 
Matrix::Matrix ()
{
  printf ("Matrix ()\n");
};
 
Matrix::Matrix (const Matrix&)
{
  printf ("Matrix (const Matrix&)\n");
};
 
Matrix::~Matrix ()
{
  printf ("~Matrix ()\n");
};
 
Matrix& Matrix::operator=(const Matrix& a)
{
  printf ("operator=(const Matrix&)\n");
 
  // тут как бы код, копирущий данные из "a" в "this"
 
  return *this;
}
 
Matrix Matrix::operator*(const Matrix& a) const
{
  printf ("operator*(const Matrix&)\n");
 
  Matrix result;
 
  // тут как бы код, умножающий "a" и "this" и записывающий
  // данные в "result"
 
  return result;
}
 
Matrix a, b, c;
 
int main (void)
{
  printf ("------------------\n");
  a = b * c;
  printf ("------------------\n");
}
Исполнение:

Code
$ g++-4.8 t.cc
$ ./a.out
Matrix ()
Matrix ()
Matrix ()
------------------
operator*(const Matrix&)
Matrix ()
operator=(const Matrix&)
~Matrix ()
------------------
~Matrix ()
~Matrix ()
~Matrix ()
Нас интересует только фрагмент печати внутри функции main (т.е. между палками)

Посмотрим на ассемблерный код. Компилирую с опцией -fno-inline, чтобы оставаться с короткой программой и не разводить геморрой по борьбе с inline'ом со стороны компилятора. В общем случае тела операторов класса Matrix будут в отдельном файле и НЕ будут доступны для inline'а. Опцию -fno-exceptions подаю, чтобы было меньше мусора в коде

Code
$ g++ t.cc -O2 -fno-inline -fno-exceptions
$ cat t.s
...
    leal    -9(%ebp), %ebx
    subl    $32, %esp
    movl    %ebx, (%esp)
    movl    $c, 8(%esp)
    movl    $b, 4(%esp)
    call    _ZN6MatrixmlERKS_  <- operator*
 
    subl    $4, %esp
    movl    %ebx, 4(%esp)
    movl    $a, (%esp)
    call    _ZN6MatrixaSERKS_  <- operator=
...
Таким образом мы видим, что построился код, схематично эквивалентный следующему примеру на Си. На всякий случай напоминаю, что с точки зрения семантики C++ выражение "a = b * c" трактуется как "a.operator= (b.operator* (c))"

C
typedef struct { /* внутренности */ } Matrix;
 
extern void operator_assign (Matrix *this, const Matrix *value);
extern void operator_mul (Matrix *result, const Matrix *this, const Matrix *operand2);
 
Matrix a, b, c;
 
int main (void)
{
  Matrix tmp;
 
  operator_mul (&tmp, &b, &c); /* tmp = b.operator* (c) */
  operator_assign (&a, &tmp);  /* a.operator= (tmp) */
}
Мы видим, что в этом коде делается ненужное действие в виде лишнего оператора присваивания. Для умножения матриц эффективный код на Си выглядел бы как

C
operator_mul (&a, &b, &c);
т.е. без заведения промежуточной переменной и дополнительного копирования (которое представляет собой ненужные накладные расходы)

Вопрос. Как правильно написать текст на C++, чтобы получить код, эквивалентный вышеприведённой эффективной реализации на C? Оставаясь при этом в объёме стандарта C++98. Оставляя исходник в понятном и читабельном виде, без использования извращений типа семиэтажных шаблонов и т.п.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
21.03.2016, 18:43
Ответы с готовыми решениями:

Неправильная работа оператора присваивания после работы оператора суммирования
Доброго времени суток. У меня есть класс вектор class TVector {//ewde public: TVector(); //Vector(Vector &amp;v); ...

От каких ошибок страхует Const при перегрузке оператора присваивания
Здравствуйте. Вопрос имею теоретический. В классе A перегружается оператор присваивания, объявление выглядит так: const A operator =...

Почему при перегрузке оператора присваивания, возвращаемое значение не константно?
Почему при перегрузке оператора присваивания, возвращаемое значение - someClass &amp; operator=(const someClass&amp; rhl), а не const...

84
22.03.2016, 15:02
Студворк — интернет-сервис помощи студентам

Не по теме:

Renji, если вы используете матрицу 2x2, которая заполняется сразу("за раз"),
и таких матриц много - имеет смысл использовать соответствующую возможным значениям
матрицы строгую адресацию, соответствующую количеству матриц. причём адресацию с запасом,
позволяющим адресовать непрерывный "диапазон" одинаковых значений. одно или двумерный

0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
22.03.2016, 15:26
Evg,
Цитата Сообщение от Evg Посмотреть сообщение
a = a * a;
Как здесь обойтись без дополнительной памяти? Требовать, чтобы слева и справа не было одних и тех же матриц?
1
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
22.03.2016, 15:46  [ТС]
Цитата Сообщение от Nosey Посмотреть сообщение
ничего вам не напоминает ASM vs C ?
Нет, не напоминает. Хотя бы потому, что опять-таки условные 90% тех, кто считает, что умеет программировать на ассемблере, попросту не смогут написать код перемножения матриц на ассемблере, чтобы он был быстрее, чем из-под компилятора Си

Цитата Сообщение от Nosey Посмотреть сообщение
Приведите примеры, желательно с тестами показывающие разницу, другого способа убедиться что С++ подход в результате не хуже я не знаю
Зачем? Делать мне больше нечего, как тебя в чём-то переубеждать? За конкретным примером далеко ходить не надо, он написан в первом посте данной темы. И пока до сих пор никто не привёл код на Си++, который бы работал столь же быстро, как и эквивалентный "эффективный" код на Си

Цитата Сообщение от Kastaneda Посмотреть сообщение
Вместо
a = b * c;
написать
(a = b) *= c;
понятно, что нужно реализовать *=
При таком подходе изменяется значение b. Что делает пример совсем не эквивалентным

Цитата Сообщение от avgoor Посмотреть сообщение
Как здесь обойтись без дополнительной памяти?
Да, тут соглашусь с претензией, она справедлива в том числе и для реализации функции operator_mul. Но для эффективной реализации мы действительно можем потребовать, чтобы dst не совпадал ни с одним из src. Я не специалист по математике, возможно, что есть алгоритмы, которые действительно требуют аккумулировать значение и работать операциями вида a *= b. Если задача требует подобных операций, то память, необходимую для вычисления произведения матриц, можно нормально выделять локально в стеке практически бесплатно (в отличие от динамической памяти, выделяемой всякими new). Хотя в таком варианте получится уже далеко не Си++ , потому что придётся работать с указателями, а не с ссылками

Во всяком случае твоя претензия помогла мне интуитивно понять, почему "стандартными средствами C++" мою постановку задачи В ОБЩЕМ СЛУЧАЕ не решить без промежуточного копирования
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
22.03.2016, 15:55
Цитата Сообщение от Evg Посмотреть сообщение
Я не специалист по математике, возможно, что есть алгоритмы, которые действительно требуют аккумулировать значение и работать операциями вида a *= b. Если задача требует подобных операций, то память, необходимую для вычисления произведения матриц, можно нормально выделять локально в стеке практически бесплатно (в отличие от динамической памяти, выделяемой всякими new). Хотя в таком варианте получится уже далеко не Си++ , потому что придётся работать с указателями, а не с ссылками
Зависит много от чего. Например: размерность матрицы - это поле класса или параметр шаблона? Может это вообще разреженые матрицы итд.
В общем случае - тут тернарная операция, и реализовать ее как две бинарных - не получится.
Исходя из вышесказанного: Matrix::inplace_mul(const Matrix& l, const Matrix& r) так, наверное.
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
22.03.2016, 15:56
Цитата Сообщение от Evg Посмотреть сообщение
При таком подходе изменяется значение b
???
C++
1
2
3
4
5
6
7
8
Matrix& Matrix::operator=(const Matrix& a)
{
  printf ("operator=(const Matrix&)\n");
 
  // тут как бы код, копирущий данные из "a" в "this"
 
  return *this;
}
operator = вернет ссылку на a, для которого уже будет вызвать *=. b тут меняться не будет.
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
22.03.2016, 16:04
Evg, В принципе можно возвращать из operator* кортеж {Matrix*, Matrix*} и в operator=(std::tuple реализовать умножение. В общем возвращать прокси.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
22.03.2016, 16:26  [ТС]
Цитата Сообщение от Kastaneda Посмотреть сообщение
operator = вернет ссылку на a, для которого уже будет вызвать *=. b тут меняться не будет
Ну да, моск заклинило. Но лишнее присваивание a=b таки будет исполнено (перед тем, как выполнить умножение). Ибо

Цитата Сообщение от avgoor Посмотреть сообщение
В общем случае - тут тернарная операция, и реализовать ее как две бинарных - не получится
-----------------

Цитата Сообщение от avgoor Посмотреть сообщение
Исходя из вышесказанного: Matrix::inplace_mul(const Matrix& l, const Matrix& r) так, наверное.
Ну это эквивалентно примеру на Си. Т.е. уже известный вариант решения

Цитата Сообщение от avgoor Посмотреть сообщение
Evg, В принципе можно возвращать из operator* кортеж {Matrix*, Matrix*} и в operator=(std::tuple реализовать умножение
Но это уже C++11. Я тут не знаю, как всё это описать синтаксически, а потому не смогу себе родить исходник для анализа построенного кода. Но идею понял. Правда подозреваю, что перестанут работать выражения типа "a = b * c + d" или вызовы функций типа "foo (a * b)". Т.е. вариант с кортежами ограничивает написание кода лишь выражениями в одну операцию с обязательным qприсваиванием
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
22.03.2016, 16:33
Цитата Сообщение от Evg Посмотреть сообщение
Т.е. вариант с кортежами ограничивает написание кода лишь выражениями в одну операцию с обязательным qприсваиванием
Кортеж для примера был. Имелось ввиду class MatrixMul, MatrixPlus... Дальше можно извратиться с шаблонами построить на них синтаксический парсер и надеятся, что компилятор схлопнет все это в эффективный код
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
22.03.2016, 16:40
Цитата Сообщение от Evg Посмотреть сообщение
Но лишнее присваивание a=b таки будет исполнено (перед тем, как выполнить умножение)
Ну да, тогда извращаться.
Имхо - проще написать в С стиле, чем С++, но который без поллитры не разберешь.
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
22.03.2016, 16:43
Nosey, а ты зачем считаешь кол-во инструкций? Типа меньше инструкций - быстрее программа?

Цитата Сообщение от Evg Посмотреть сообщение
вся неэффективность растёт из
сказочных ограничений (типа С++98, с ООП и тп).

Цитата Сообщение от Evg Посмотреть сообщение
Потому что у многих в подсознании заложено в первую очередь то, что программа должна иметь как можно меньше букв в исходнике, а вовсе не потреблять как можно меньше количество тактов при исполнении
Что один, что другой подход - крайности какие-то.

Цитата Сообщение от Evg Посмотреть сообщение
которую получается написать эффективно только в "некультурном" стиле
А что такое "некультурный стиль" в С++?
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
22.03.2016, 16:48
ct0r, Как показывает практика, когда речь заходит о перемножении матриц - минимум тактов не крайность, а необходимость.
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
22.03.2016, 16:57
Цитата Сообщение от avgoor Посмотреть сообщение
Как показывает практика, когда речь заходит о перемножении матриц - минимум тактов не крайность, а необходимость.
Я кэш-миссы даже считал, и префетчинг делал, чтоб их сократить. Да, если это узкое место, то приходится "вылизывать".
1
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
22.03.2016, 17:01
Цитата Сообщение от Kastaneda Посмотреть сообщение
Я кэш-миссы даже считал, и префетчинг делал, чтоб их сократить.
Аналогично.
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
22.03.2016, 17:05
Цитата Сообщение от avgoor Посмотреть сообщение
Как показывает практика, когда речь заходит о перемножении матриц - минимум тактов не крайность, а необходимость.
А причем тут практика и перемножение матриц? Там про подсознание.
0
 Аватар для Nosey
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
22.03.2016, 17:06
Цитата Сообщение от Evg Посмотреть сообщение
Зачем? Делать мне больше нечего, как тебя в чём-то переубеждать? За конкретным примером далеко ходить не надо, он написан в первом посте данной темы.
Потешно А ты его запускал свой конкретный пример?
Ну ладно, открывай ротик, закладываю :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "math/Math.h"
#include <iostream>
#include <vector>
 
const size_t c = 100000000;
 
ru::math::Matrix4 fcpp(const ru::math::Matrix4& mat1)
{
    ru::math::Matrix4 mat2 { 20, 30, 40 };
    return mat1 * mat2;
}
 
ru::math::Matrix4 mat1 { 10, 20, 30 };
ru::math::Matrix4 mat2 { 20, 30, 40 };
ru::math::Matrix4 mat3;
 
void fc(const ru::math::Matrix4* mat1)
{
    ru::math::Matrix4::operator_mul(&mat3, mat1, &mat2);
}
 
int main(void)
{
    std::vector<float> resVec;
    resVec.reserve(c);
    size_t i = c;
 
    clock_t startCpp = clock();
    while (--i)
    {
        resVec.push_back(fcpp(mat1).det());
    }
    clock_t endCpp = clock();
 
    std::cout << resVec.size() << " " << endCpp - startCpp << std::endl;
 
    resVec.clear();
    i = c;
 
    clock_t startC = clock();
    while (--i)
    {
        fc(&mat1);
        resVec.push_back(mat3.det());
    }
    clock_t endC = clock();
    std::cout << resVec.size() << " " << endC - startC << std::endl;
}
Реализация оператора умножения:
C++
1
2
3
4
5
6
            Matrix4 operator*(const Matrix4 &m) const
            {
                Matrix4 ret;
                operator_mul(&ret, this, &m);
                return ret;
            }
Вы только представьте сколько в Cpp реализации лишних копирований и присваиваний происходит, и все бесплатно, ах, эти новые квантовые ноутбуки.
Результаты :
99999999 3105052 - cpp
99999999 3098734 - c
И да, это расчёты честные, никаких компайлтайм расчётов нету.

Цитата Сообщение от ct0r Посмотреть сообщение
а ты зачем считаешь кол-во инструкций? Типа меньше инструкций - быстрее программа?
В данном случае - да, слишком уж большой разрыв для идентичных алгоритмов.
А вы считаете, что в данном случае меньшее количество инструкций хуже работают?
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
22.03.2016, 17:16
Цитата Сообщение от Nosey Посмотреть сообщение
В данном случае - да, слишком уж большой разрыв для идентичных алгоритмов.
А вы считаете, что в данном случае меньшее количество инструкций хуже работают?
Да я фиг знает. Мерить надо. Я не умею считать такты с учетом конвейеров и суперскалярности, с учетом зависимостей по данным, с учетом кол-ва обращений к памяти и кол-ва промахов кэша и тд и тп. Интуиция тут не помощник. Ну если кто-то умеет, то ок.
Компилятор, когда оптимизирует, на кол-во инструкций точно не смотрит.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
22.03.2016, 17:26  [ТС]
Цитата Сообщение от ct0r Посмотреть сообщение
А что такое "некультурный стиль" в С++?
Тот, который "в стиле языка Си". Т.е. в моей терминологии при написании программы на Си++ "культурно" это

C++
a = b * c;
не "культурно"

C
operator_mul (&a, &b, &c);
При написании "культурно" (т.е. в стиле Си++) программа выглядит красиво, но работает неэффективно

Добавлено через 9 минут
Цитата Сообщение от Nosey Посмотреть сообщение
Ну ладно, открывай ротик, закладываю
Мне не интересно смотреть на исходник, в котором используется какой-то непонятный самопальный Math.h, о содержании которого я должен догадываться. Засовывание результатов в вектор - это, насколько я понял, борьба с оптимизациями. Но тем не менее, этот процесс входит в замер. А если получится так, что на одну итерацию цикла приходится условно 10 тактов для умножения матрицы и 1000 тактов для засовывания в вектор (т.е. доля полезной нагрузки составляет 1% от общего времени), то такой замер ни о чём. Очевидно, ты об этом не задумывался, когда писал вектор, в который нужно будет засунуть 100 миллионов экземпляров и не можешь сказать, какую долю времени всего теста занимает менеджер памяти при работе с вектором. Так что твой пример я готов рассматривать только в варианте с полным исходником. Чтобы он изначально был рабочим, чтобы я его мог переписать с симетричными подходами "c" и "cpp" и с правильным построением замера

Правда я всё равно не понимаю, что ты мне продемонстрировать этим примером хочешь. Если хочешь продемонстрировать, что ненужные копирования занимают всего 1% (2%, 3%, не суть) от времени исполнения, то мне это вовсе не интересно. Если для выполнения какой-то задачи код должен быть быстрым, то борьба идёт за каждый процент времени исполнения
0
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
22.03.2016, 17:28
Evg, ну ООП в С++ тогда тоже некультурно, потому что в стиле Smalltalk. А перегрузка операторов - потому что в стиле ALGOL.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
22.03.2016, 17:29  [ТС]
Цитата Сообщение от avgoor Посмотреть сообщение
Имелось ввиду class MatrixMul, MatrixPlus... Дальше можно извратиться с шаблонами построить на них синтаксический парсер и надеятся, что компилятор схлопнет все это в эффективный код
Если рассматривать вариант с извращениями, то написание функции с тремя аргументами выглядит самым простым и эффективным решением. Я плохо знаю Си++, потому и спросил. Я думал, что можно написать реализацию матриц так, чтобы можно было писать "a = b * c" и иметь при этом эффективный код
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
22.03.2016, 17:43
Цитата Сообщение от Evg Посмотреть сообщение
чтобы можно было писать "a = b * c" и иметь при этом эффективный код
...
Цитата Сообщение от avgoor Посмотреть сообщение
Зависит много от чего. Например: размерность матрицы - это поле класса или параметр шаблона? Может это вообще разреженые матрицы итд.
Теоретически можно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.03.2016, 17:43

Какое значение получит переменная p при выполнении следующего оператора присваивания?
var p: set of 0..9; i, j: integer; Если i=2 и j=5, то какое значение получит переменная p при выполнении следующего оператора...

Ошибка при выполнении оператора присваивания производного класса через указатель на базовый
Здравствуйте, не могу понять из-за чего ошибка. Надо в производном классе объявить оператор сложения и обратится к нему через базовый. ...

Ошибка при реализации перегрузки оператора <<
Добрый день. Прошу помощи. Имеется такой класc. class DList { ... public: ... void Save(std::ofstream &amp;b_out); //...

Ошибка в вводе данных из HTML и переносе их в JavaScript, при выполнении оператора IF или оператора swithc
доброго времени суток, при выполнении одной учебной задачи столкнулся с проблемой: при введении любого значения в поле, код выдает только...

Переопределение оператора присваивания
Имеется такой простой класс: class TClass { private: float* A; int N; public: TClass(int _N) ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Доктрина интенционального знания - Доктрина для портала "Срез".
Hrethgir 25.07.2026
Может найдётся кто захочет оценить доктрину. . . Написания правил участия для меня роскошь, требующая лимита времени, поэтому все сообщения не прошедшие модерацию будут видны только участникам портала,. . .
сукцессия 44. Решил подать на припринт в межународные сервисы препринтов. Но нужно одобрение от ученых
anaschu 25.07.2026
Английский вариант. Пока кто то не одобрит мою личность, мне не получиться это опубликовать на препринте. Но заявку на публикацию статьи я сегодня подам.
сукцессия 43. Вторая научная статья за месяц- прайминг и гатгил
anaschu 25.07.2026
две стороны одной монеты
Более приземисто - Эстафету хвоста в .cdl (деревья эстафеты в сад).
Hrethgir 24.07.2026
В будущем, после написания блока инверсии обхода дерева (эстафеты хвоста), я планирую вернуться к нашему прошлому разговору о том, обладают ли знания целеполаганием. Тогда я пришел к выводу, что. . .
Вот представьте что вам дали бессмертие.
kumehtar 24.07.2026
Вот представьте что вам дали бессмертие, ничего более не меняя. Вообще ничего, только бессмертие в нынешнем виде. Рады были бы? Что бы вы тут делали всё это время? Никакой пенсии. Никакого нового. . .
сукцессия 41
anaschu 24.07.2026
Численная верификация бифуркации в агентной модели лесной сукцессии: от одного параметра к ансамблю Автор: пользователь @Shumilov_AS | Раздел: Прикладная математика / Численные методы Кратко. . .
сукцессия 40. Ансамблевая кластерная параметризаци, часть 1.
anaschu 24.07.2026
Пр# Сопровождение научной статьи ИИ-ассистентом: подготовка публикации и калибровка агентно-ориентированной модели сукцессии микоризных систем **Полевые заметки о двухнедельной совместной работе**. . .
Теория всего 12. ВГК на планете в стратегической игре "терра"
anaschu 21.07.2026
### Главные семантические изменения и дешифровка новой физики 1. **`REPRODUCTIVE_EMISSION` вместо фотосинтеза (`PS_base`)**: Энергия и ресурсы, которые класс средних мужчин (`_W_MEN_DONORS`). . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru