Информация об изменениях

Сообщение Re[26]: И еще рассуждения об ИИ от 12.02.2026 3:21

Изменено 12.02.2026 4:31 Pavel Dvorkin

Re[26]: И еще рассуждения об ИИ
Здравствуйте, Sinclair, Вы писали:

Наверное, пора закачивать. Поэтому ограничусь лишь небольшим.

PD>>Я ничего против того, что он на это указал, не имею. Пусть напомнит, верно. Но меня-то иное интересовало — может ли оно быть при тех данных, которые меня интересуют. А на этот вопрос у него ответа нет.

S>Потому что он не знает, какие данные вас интересуют.
S>Вот вы только что сказали, что ничего, кроме этой программы, у вас нет.
PD>>Если эти длина и ширина — размеры дисплея обычной машины в пикселях, то совершенно спокойно можно остаться с unit — пока что дисплеев с размерами, при которых переполнение возможно, в природе нет.
S>И вдруг появляется контекст — оказывается, речь о длине и ширине экрана в пикселях. Если бы мы дали ИИ это как вводную, его ответ был бы другим. А так вы соврали исполнителю работ, скрыв важные детали.

Я могу согласиться, что именно для этого случая можно приделать к программе какой-то файл с подробным описанием всех переменных. Правда, сдается мне, что если по каждой операции умножения мы будем писать такие объяснения в каком угодно виде, то программу мы напишем ко второму пришествию.
Но это ладно. Ну а если все же взять более серьезный код.

Например, вот такое. Сразу скажу — я не автор и не проверял его работу. Просто взял вот тут в качестве примера

https://www.cyberforum.ru/cpp-beginners/thread1641625.html

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <omp.h>
#include <cstdlib> 
const double eps = 0.0001;
using namespace std;
void Mul(int N, double **A,double *x,double *y)
{
    for (int i = 0; i<N; i++)
    {   
        y[i] = 0;
        for (int j = 0; j<N; j++)
            y[i] = y[i] + (A[i][j] * x[j]);
    }
}
  
void PrintMatrix(int N, double **A )
{
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
            cout << A[i][j]<<" ";
        cout << endl;
    }
}
void PrintVec(int N, double *A)
{
    for (int i = 0; i < N; i++)
    {
            cout << A[i] << " ";
    }
    cout << endl;
}
 
void Jacobi(int N, double**A, double* F, double* X)
{
    double norm,* TempX = new double[N];
    for(int k=0;k<N;k++)
        TempX[k]= X[k];
    int cnt = 0;
    do {
        for (int i = 0; i < N; i++) 
        {
            TempX[i] = F[i];
            for (int g = 0; g < N; g++) 
                if (i != g)
                    TempX[i] -= A[i][g] * X[g];
            TempX[i] /= A[i][i];
        }
       norm = fabs(X[0] - TempX[0]);
        for (int h = 0; h < N; h++) 
        {
            if (fabs(X[h] - TempX[h]) > norm)
                norm = fabs(X[h] - TempX[h]);
            X[h] = TempX[h];
        }
        cnt++; 
         
    } 
    while (norm >= eps);
 
    cout<<"Кол-во итераций = "<<cnt;
    delete[] TempX;
}
void Load(int &N, double **&A, double *&F)
{
    setlocale(0,"");
    ifstream fin;
    fin.open("primer");
    fin >> N;
    F = new double [N];
    A = new double *[N];
        for (int i = 0; i < N; i++)
            A[i] = new double[N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
                fin >> A[i][j];
            fin >> F[i];
        }
    fin.close();
}
int main()
{
    double **Matrix, *b,*y,*x;
    int n;
    Load(n, Matrix, b);
    cout << "Матрица:\n";
    PrintMatrix(n, Matrix);
    cout << "\n"<<"b: ";
    PrintVec(n, b);
   x = new double[n];
   for(int i=0;i<n;i++)
    x[i]=1.0;
   y = new double[n];
   Jacobi(n, Matrix, b, x);
    cout <<"\n"<< "Результат | x: ";
    PrintVec(n, x);
   cout << "A*x=b | b: ";
   Mul(n, Matrix, x, y);
   PrintVec(n, y);
    delete x;
   delete y;
  system("pause");
    return 1;
}


Допустим, мне надо использовать этот код. Верен ли он алгоритмически (то есть делает ли то, что ему положено) — не обсуждаем. Меня интересуют лишь два вопроса

Может ли произойти переполнение с плавающей точкой в этом коде ?
Не возникнет ли тут деление на 0 ?

Почему взял этот пример ? Дело в том, что в мои молодые годы я как раз реализовал (сам не писал, перевел на другую машину) код, внутри которого был алгоритм Якоби. И на исходной машине все вполне работало, а на той, на которую я переводил иногда нет.

Причиной было различие размеров переменных. На IBM-360 double занимает 8 байт, а на БЭСМ-6 — 6 байт.

Начал разбираться — оказалось, что в коде для IBM-360 в этом алгоритме в самом начале выполняется установка т.н. стандартного корректирующего действия. Суть ее в том, что если происходит переполнение, то в ячейку ответа засылается максимально допустимое число. Алгоритм вполне такое допускал, так как он итерационный, и на следующей итерации поправится сам. В общем, своего рода обработка исключения. Написано все было на Фортране, обработки исключений в нынешнем смысле слова в нем не было.

Для БЭСМ-6 возможности установить стандартное корректирующее действие не было. Вот тут-то я и покрутился, пытаясь понять, где это переполнение может возникнуть.

Если хотите знать, что в исходной матрице — пожалуйста. Сравнительно небольшие числа на главной диагонали и в ее окрестности. Остальные элементы нулевые. В векторе тоже небольшие числа.
Могу даже сказать, что это за числа. Опуская детали, это энергия взаимодействия атомов, прямо не связанных в молекуле органического соединения. Там взаимодействие убывает по алгоритму R^-6 и R^-12 (потенциал Леннард — Джонса)

U = Eo*[ (R0/R)^12 — (Ro/R)^6]

Поэтому если атомы находятся далеко друг от друга, то в матрице просто 0 ставится.

S>Это примерно то же самое, что врать адвокату или врачу. Искусственный интеллект точно так же, как и естественный, дополнит вашу постановку недостающими деталями, подобрав самую правдоподобную для него картинку.


Ну вот я Вам и не соврал. Все изложил, что знаю. Жду ответа



PD>>Ну а если это размеры дисплея — ну сделаю тест 10000 на 10000, все будет в порядке, можно так и оставить.

S>Если бы вы коммитили такой код в любом моём проекте, то он не прошёл бы review.

Нет, не придется мне коммитить код в Ваш проект. Да и в любой другой тоже. Моя программистская карьера завершена. Но в ней я такое (да и не такое!) не раз коммитил, и как-то все потом благополучно работало и никто не жаловался.

S>Потому что нет никакой гарантии, что пользователь не соберётся его использовать за пределами неявно подразумеваемых вами ограничений.

S>Завтра кто-то захочет использовать вашу библиотеку для рисования на виртуальном экране размером в 100000*200000 пикселов, и код начнёт делать фигню.
S>Если вы заложились на такое ограничение, будьте любезны
S>а) явно это задокументировать
S>б) выразить в коде.
S>А после этого мы посмотрим, нужно ли писать тесты и какие именно тесты.

Ну что же, выскажусь и по этому замечанию.

В теории Вы правы. Если мой код действительно в библиотеке, да еще рассчитанной на то, что ее будет использовать потом широкий круг пользователей, то такое недопустимо.

Но где я сказал, что этот код для библиотеки ? Я такого нигде не говорил.

Где я сказал, что этот код может быть, когда-то будет использоваться кем-то для иной цели ? Я такого тоже не говорил.

Или в моем примере с Якоби — меня абсолютно не интересует, что будет, если какой-то другой пользователь начнет использовать этот код для каких-то матриц, в которых иные данные (ну скажем, много больших элементов далеко от главной диагонали). Это его проблемы. В той задаче, что я сейчас решаю, данные именно такие и другими быть не могут — объяснение выше.

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

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

S>1. Тест может и не найти ошибку. От того, что ваши тесты зелены, уверенности в корректности кода не прибавляется.

S>2. Статический анализ ошибку совершенно точно найдёт, но для него нужны формальные критерии. То есть надо сесть и написать спецификацию для вашего кода на формальном языке. И вот после этого верифицирующий компилятор вам сможет (иногда) сказать "ошибок точно нет".

Я Вам все сказал , что мог, по этому Якоби примеру. Хотите еще что-то — скажите, что нужно, честно отвечу, если смогу.

S>3. ИИ, как видим, не ограничен ни наличием тестов, ни наличием формальных спецификаций. Если бы вы снабдили ваш код хотя бы комментарием на естественном языке об ожидаемом диапазоне параметров, то ИИ смог бы точно сказать, есть ли в коде ошибка или нет.


Я Вам дал на естественном языке информацию об ожидаемом диапазоне данных во входной матрице. Другой информации у меня нет.

PD>>unsigned int population;


PD>>Это корректно или нет ?

S>Это примерно такой же вопрос, как и "как правильно писать — Ирак или Иран". Не бывает никакой правильности

PD>>Если это население страны, то я нелестно выскажусь в адрес того, кто мне скажет, что может не хватить. Нет таких стран с населением 4 млрд. человек и скорее всего не будет. А если когда-то и будет, то моей программы уже точно не будет

S>Да-да. Именно так и думали все авторы программ, у которых под номер года отводили 2 цифры.


А вот тут как раз все немного иначе.

Те, кто отводил под это 2 цифры в 1960 или 1970 году — вполне были правы. Не дожили их машины и и их программы до 2000 года. И не могли дожить. А если какой-то их код и дожил года до так 1980, то его потом все равно переносили, там и должны были поправить. Там скорее всего многое пришлось бы править — ну хотя бы из-за разных размеров данных на разных машинах.

(В скобках. В Фортране до введения типа CHARACTER тексты хранили в INTEGER переменных. На IBM-360 — 4 символа в одной. На БЭСМ-6 — 6 символов в одной. Перенос программы с IBM на БЭСМ в этом плане тоже еще то было удовольствие. А там была символьная обработка — прежде чем матрицу для Якоби сделать, надо было формулу распарсить, а она давалась текстовой строкой)

Те, кто писал их в 1980 году — уже должен был подумать.

Те, кто писал такое в 1990 году — идиот.

Идиотов оказалось не так уж много, поэтому вокруг проблемы 2000 шуму было много, а реально ничего не произошло. Ну может, в ПО для конторы "Рога и копыта" копыта были помечены как полученные от коров 1901 года.

А то ведь можно и до абсурда довести. Как Ваша программа будет работать после 9999 года ? Не пора ли уже сейчас об этом подумать ?

То же и с населением. Ну не будет программа корректно работать, когда появится город с населением в 4 миллиарда человек. Вот только когда он появится (если он вообще когда-нибудь появится) — этой программы уже сотни лет как не будет.

В общем, как сказано в библии

Итак, не заботьтесь о завтрашнем дне, ибо завтрашний сам будет заботиться о своём: довольно для каждого дня своей заботы.


Остальное <skipped>, потому что повторяет то же самое.
Re[26]: И еще рассуждения об ИИ
Здравствуйте, Sinclair, Вы писали:

Наверное, пора закачивать. Поэтому ограничусь лишь небольшим.

PD>>Я ничего против того, что он на это указал, не имею. Пусть напомнит, верно. Но меня-то иное интересовало — может ли оно быть при тех данных, которые меня интересуют. А на этот вопрос у него ответа нет.

S>Потому что он не знает, какие данные вас интересуют.
S>Вот вы только что сказали, что ничего, кроме этой программы, у вас нет.
PD>>Если эти длина и ширина — размеры дисплея обычной машины в пикселях, то совершенно спокойно можно остаться с unit — пока что дисплеев с размерами, при которых переполнение возможно, в природе нет.
S>И вдруг появляется контекст — оказывается, речь о длине и ширине экрана в пикселях. Если бы мы дали ИИ это как вводную, его ответ был бы другим. А так вы соврали исполнителю работ, скрыв важные детали.

Я могу согласиться, что именно для этого случая можно приделать к программе какой-то файл с подробным описанием всех переменных. Правда, сдается мне, что если по каждой операции умножения мы будем писать такие объяснения в каком угодно виде, то программу мы напишем ко второму пришествию.
Но это ладно. Ну а если все же взять более серьезный код.

Например, вот такое. Сразу скажу — я не автор и не проверял его работу. Просто взял вот тут в качестве примера

https://www.cyberforum.ru/cpp-beginners/thread1641625.html

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <omp.h>
#include <cstdlib> 
const double eps = 0.0001;
using namespace std;
void Mul(int N, double **A,double *x,double *y)
{
    for (int i = 0; i<N; i++)
    {   
        y[i] = 0;
        for (int j = 0; j<N; j++)
            y[i] = y[i] + (A[i][j] * x[j]);
    }
}
  
void PrintMatrix(int N, double **A )
{
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
            cout << A[i][j]<<" ";
        cout << endl;
    }
}
void PrintVec(int N, double *A)
{
    for (int i = 0; i < N; i++)
    {
            cout << A[i] << " ";
    }
    cout << endl;
}
 
void Jacobi(int N, double**A, double* F, double* X)
{
    double norm,* TempX = new double[N];
    for(int k=0;k<N;k++)
        TempX[k]= X[k];
    int cnt = 0;
    do {
        for (int i = 0; i < N; i++) 
        {
            TempX[i] = F[i];
            for (int g = 0; g < N; g++) 
                if (i != g)
                    TempX[i] -= A[i][g] * X[g];
            TempX[i] /= A[i][i];
        }
       norm = fabs(X[0] - TempX[0]);
        for (int h = 0; h < N; h++) 
        {
            if (fabs(X[h] - TempX[h]) > norm)
                norm = fabs(X[h] - TempX[h]);
            X[h] = TempX[h];
        }
        cnt++; 
         
    } 
    while (norm >= eps);
 
    cout<<"Кол-во итераций = "<<cnt;
    delete[] TempX;
}
void Load(int &N, double **&A, double *&F)
{
    setlocale(0,"");
    ifstream fin;
    fin.open("primer");
    fin >> N;
    F = new double [N];
    A = new double *[N];
        for (int i = 0; i < N; i++)
            A[i] = new double[N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
                fin >> A[i][j];
            fin >> F[i];
        }
    fin.close();
}
int main()
{
    double **Matrix, *b,*y,*x;
    int n;
    Load(n, Matrix, b);
    cout << "Матрица:\n";
    PrintMatrix(n, Matrix);
    cout << "\n"<<"b: ";
    PrintVec(n, b);
   x = new double[n];
   for(int i=0;i<n;i++)
    x[i]=1.0;
   y = new double[n];
   Jacobi(n, Matrix, b, x);
    cout <<"\n"<< "Результат | x: ";
    PrintVec(n, x);
   cout << "A*x=b | b: ";
   Mul(n, Matrix, x, y);
   PrintVec(n, y);
    delete x;
   delete y;
  system("pause");
    return 1;
}


Допустим, мне надо использовать этот код. Верен ли он алгоритмически (то есть делает ли то, что ему положено) — не обсуждаем. Меня интересуют лишь два вопроса

Может ли произойти переполнение с плавающей точкой в этом коде ?
Не возникнет ли тут деление на 0 ?

Почему взял этот пример ? Дело в том, что в мои молодые годы я как раз реализовал (сам не писал, перевел на другую машину) код, внутри которого был алгоритм Якоби. И на исходной машине все вполне работало, а на той, на которую я переводил иногда нет.

Причиной было различие размеров переменных. На IBM-360 double занимает 8 байт, а на БЭСМ-6 — 6 байт.

Начал разбираться — оказалось, что в коде для IBM-360 в этом алгоритме в самом начале выполняется установка т.н. стандартного корректирующего действия. Суть ее в том, что если происходит переполнение, то в ячейку ответа засылается максимально допустимое число. Алгоритм вполне такое допускал, так как он итерационный, и на следующей итерации поправится сам. В общем, своего рода обработка исключения. Написано все было на Фортране, обработки исключений в нынешнем смысле слова в нем не было.

Для БЭСМ-6 возможности установить стандартное корректирующее действие не было. Вот тут-то я и покрутился, пытаясь понять, где это переполнение может возникнуть.

Если хотите знать, что в исходной матрице — пожалуйста. Сравнительно небольшие числа на главной диагонали и в ее окрестности. Остальные элементы нулевые. В векторе тоже небольшие числа.
Могу даже сказать, что это за числа. Опуская детали, это энергия взаимодействия атомов, прямо не связанных в молекуле органического соединения. Там взаимодействие убывает по алгоритму R^-6 и R^-12 (потенциал Леннард — Джонса)

U = Eo*[ (R0/R)^12 — (Ro/R)^6]

Поэтому если атомы находятся далеко друг от друга, то в матрице просто 0 ставится.

S>Это примерно то же самое, что врать адвокату или врачу. Искусственный интеллект точно так же, как и естественный, дополнит вашу постановку недостающими деталями, подобрав самую правдоподобную для него картинку.


Ну вот я Вам и не соврал. Все изложил, что знаю. Жду ответа

А пока что могу сказать, что было у меня. Просто убрал это стандартное корректирующее действие и стал ждать, что из этого выйдет. Примеры запускал (считайте, что тесты) Когда переполнение наконец произошло, нашел его место и поставил проверку. Вот и все. Место такое нашлось одно за все время, что я с программой работал. Нашлось бы еще одно — поставил бы проверку и там. И это при (будем так условно считать) полном непонимании этого алгоритма — я и впрямь в деталях той реализации разбираться не стал.



PD>>Ну а если это размеры дисплея — ну сделаю тест 10000 на 10000, все будет в порядке, можно так и оставить.

S>Если бы вы коммитили такой код в любом моём проекте, то он не прошёл бы review.

Нет, не придется мне коммитить код в Ваш проект. Да и в любой другой тоже. Моя программистская карьера завершена. Но в ней я такое (да и не такое!) не раз коммитил, и как-то все потом благополучно работало и никто не жаловался.

S>Потому что нет никакой гарантии, что пользователь не соберётся его использовать за пределами неявно подразумеваемых вами ограничений.

S>Завтра кто-то захочет использовать вашу библиотеку для рисования на виртуальном экране размером в 100000*200000 пикселов, и код начнёт делать фигню.
S>Если вы заложились на такое ограничение, будьте любезны
S>а) явно это задокументировать
S>б) выразить в коде.
S>А после этого мы посмотрим, нужно ли писать тесты и какие именно тесты.

Ну что же, выскажусь и по этому замечанию.

В теории Вы правы. Если мой код действительно в библиотеке, да еще рассчитанной на то, что ее будет использовать потом широкий круг пользователей, то такое недопустимо.

Но где я сказал, что этот код для библиотеки ? Я такого нигде не говорил.

Где я сказал, что этот код может быть, когда-то будет использоваться кем-то для иной цели ? Я такого тоже не говорил.

Или в моем примере с Якоби — меня абсолютно не интересует, что будет, если какой-то другой пользователь начнет использовать этот код для каких-то матриц, в которых иные данные (ну скажем, много больших элементов далеко от главной диагонали). Это его проблемы. В той задаче, что я сейчас решаю, данные именно такие и другими быть не могут — объяснение выше.

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

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

S>1. Тест может и не найти ошибку. От того, что ваши тесты зелены, уверенности в корректности кода не прибавляется.

S>2. Статический анализ ошибку совершенно точно найдёт, но для него нужны формальные критерии. То есть надо сесть и написать спецификацию для вашего кода на формальном языке. И вот после этого верифицирующий компилятор вам сможет (иногда) сказать "ошибок точно нет".

Я Вам все сказал , что мог, по этому Якоби примеру. Хотите еще что-то — скажите, что нужно, честно отвечу, если смогу.

S>3. ИИ, как видим, не ограничен ни наличием тестов, ни наличием формальных спецификаций. Если бы вы снабдили ваш код хотя бы комментарием на естественном языке об ожидаемом диапазоне параметров, то ИИ смог бы точно сказать, есть ли в коде ошибка или нет.


Я Вам дал на естественном языке информацию об ожидаемом диапазоне данных во входной матрице. Другой информации у меня нет.

PD>>unsigned int population;


PD>>Это корректно или нет ?

S>Это примерно такой же вопрос, как и "как правильно писать — Ирак или Иран". Не бывает никакой правильности

PD>>Если это население страны, то я нелестно выскажусь в адрес того, кто мне скажет, что может не хватить. Нет таких стран с населением 4 млрд. человек и скорее всего не будет. А если когда-то и будет, то моей программы уже точно не будет

S>Да-да. Именно так и думали все авторы программ, у которых под номер года отводили 2 цифры.


А вот тут как раз все немного иначе.

Те, кто отводил под это 2 цифры в 1960 или 1970 году — вполне были правы. Не дожили их машины и и их программы до 2000 года. И не могли дожить. А если какой-то их код и дожил года до так 1980, то его потом все равно переносили, там и должны были поправить. Там скорее всего многое пришлось бы править — ну хотя бы из-за разных размеров данных на разных машинах.

(В скобках. В Фортране до введения типа CHARACTER тексты хранили в INTEGER переменных. На IBM-360 — 4 символа в одной. На БЭСМ-6 — 6 символов в одной. Перенос программы с IBM на БЭСМ в этом плане тоже еще то было удовольствие. А там была символьная обработка — прежде чем матрицу для Якоби сделать, надо было формулу распарсить, а она давалась текстовой строкой)

Те, кто писал их в 1980 году — уже должен был подумать.

Те, кто писал такое в 1990 году — идиот.

Идиотов оказалось не так уж много, поэтому вокруг проблемы 2000 шуму было много, а реально ничего не произошло. Ну может, в ПО для конторы "Рога и копыта" копыта были помечены как полученные от коров 1901 года.

А то ведь можно и до абсурда довести. Как Ваша программа будет работать после 9999 года ? Не пора ли уже сейчас об этом подумать ?

То же и с населением. Ну не будет программа корректно работать, когда появится город с населением в 4 миллиарда человек. Вот только когда он появится (если он вообще когда-нибудь появится) — этой программы уже сотни лет как не будет.

В общем, как сказано в библии

Итак, не заботьтесь о завтрашнем дне, ибо завтрашний сам будет заботиться о своём: довольно для каждого дня своей заботы.


Остальное <skipped>, потому что повторяет то же самое.