|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Функция расстановки коэффициентов в уравнениях хим. реакций
Здравствуйте!
Не могли бы Вы написать функцию расстановки коэффициентов в уравнениях хим. реакций. Нужно как один из модулей моей будущей программы (не коммерческая). Для меня это сложно, да и в математических методах слаб. Знаю только, что это можно сделать методом Гаусса-Жордана. Буду очень благодарен за любую помощь. Спасибо Всем! |
#2
|
||||
|
||||
Сперва распроси Гауса-Жордана поподробнее о его методе потом с этим методом сюда
|
#3
|
|||
|
|||
Цитата:
|
#4
|
|||
|
|||
Че-то я не понимаю, кому помощь-то нужна???
Здесь форум программистов, а не математиков. Если нужна помощь, то предоставьте теорию (хотя бы ссылку на адекватную статью). ЗЫ. Последнее китайское предупреждение. |
#5
|
||||
|
||||
Перефразирую...
разберитесь с методом Гаусса-Жордана, составьте алгоритм, попробуйте реализовать в Delphi, если последнее не получается, то с кусками кода сюда, если никак даже с первым шагом, то сюда, ну или ждите того, кто знает этот метод а то получается: "мне надо сделать класс, проводящий ЦОС, приходящего с квадратичного фильтра, мне сказали, что БПФ не подходит (кстати, объясните почему), а нужны 3К преобразования с учетом корреляционной составляющей" (фраза содержит явный бред), а потом непонимание, почему никто "не хочет" помочь Понять, что хочет заказчик - бесценно, ведь он платит MasterCard |
#6
|
|||
|
|||
Нашел в интернете алгоритм ( а точнее код) расстановки коэффициентов в уравнениях химических реакций методом Гаусса-Жордана (как я понял это метод решения систем линейных уравнений). Опять-таки, то, что смог понять из этого кода, так это то, что сначала создается матрица элементов (чисел), затем матрица преобразуется в систему линейных уравнений, которые решаются и из этих уравнений находятся коэффициенты для всех веществ хим. реакции. Проблеме в том, что код написан (как я понял) на С++. Мне и в паскалевском коде такой сложности трудно ориентироваться, а тут тем более.
Код:
/*** Решение уравнений методом Гаусса - Жордана ***/ #include <math.h> #define GAUSS_ACCURACY 0.0000001 #define GAUSS_OK 0 #define GAUSS_NOSOL 1 #define GAUSS_MANYSOL 2 /*********************************************/ /* Функция решения систем линейных уравнений */ /* методом Гаусса - Жордана */ /* (C) 2002 Восков Алексей */ /* версия 2.1 */ /*********************************************/ /* ВХОДНЫЕ ДАННЫЕ */ /* a[20][20] - Матрица для хранения системы a[y][x] последний столбец - для хранения св. члена св. член - в правой части n - число неизвестных u - число уравнений ВЫХОДНЫЕ ДАННЫЕ x[20] - массив для хранения корней системы в случае нормального выполнения задачи функция возвращает 0, в случае неразрешимости 1 в случае бесконечного числа решений 2 */ int gauss(double a[20][20], int n, int u, double x[20]) { int i, j, k; /* Счетчики циклов */ int sn; /* Номер строки */ double d; /* Коэффициент домножения или модуль наиб. эл. */ /*** Проверка u и n ***/ if (n > u) return 2; /*** Приведение к диагональному виду ***/ for (j = 0; j < n; j++) { /* а) поиск строки с наибольшим по модулю элементом */ d = fabs(a[j][j]); sn = j; for (i = j; i < u; i++) if (fabs(a[i][j]) > d) { d = fabs(a[i][j]); sn = i; } /* б) перенос строки на надлежащее место */ for (k = 0; k <= n; k++) { d = a[sn][k]; a[sn][k] = a[j][k]; a[j][k] = d; } /* в) деление ведущего ур-я на главный элемент */ d = a[j][j]; if (d) for (k = 0; k <= n; k++) a[j][k] /= d; else for (k = 0; k <= n; k++) a[j][k] = 0; /* г) вычитание данной строки из всех остальных */ /* с домножением на коэффициент */ for (i = 0; i < u; i++) { if (i == j) continue; /* Не трогаем вычит. строку */ d = -a[i][j]; for (k = 0; k <= n; k++) /* Вычитание */ a[i][k] += a[j][k] * d; } } /*** Вычисление корней ***/ /* а) проверка системы на разрешимость */ if (u > n) { for (i = n; i < u; i++) { k = 0; for (j = 0; j < n; j++) if (fabs(a[i][j]) > GAUSS_ACCURACY) k = 1; if (k == 0 && fabs(a[i][n]) > GAUSS_ACCURACY) return 1; } } /* б) поиск корней */ for (i = 0; i < n; i++) { x[i] = -a[i][n]; if (a[i][i] != 1) /** Обработка ошибок **/ { if (x[i]) return GAUSS_NOSOL; /* Решений нет */ else return GAUSS_MANYSOL; /* Бесконечно много решений */ } if (fabs(x[i]) < GAUSS_ACCURACY) x[i] = 0; /* Обнуление слишком малых знач. */ } return GAUSS_OK; /* Нормальное завершение работы */ } http://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%93%D0%B0%D1%83% D1%81%D1%81%D0%B0_%E2%80%94_%D0%96%D0%BE%D1%80%D0% B4%D0%B0%D0%BD%D0%B0 Выкладываю программу которая основана на этом принципе расстановки коэффициентов. Для примера, можно уравнять реакцию: NaCl+H2SO4+KMnO4=Cl2+MnSO4+Na2SO4+K2SO4+H2O c_urav.zip Буду благодарен за перевод кода на Delphi и если возможно, подробное пояснения кода. Спасибо Всем большое! |
#7
|
||||
|
||||
Примерно так:
Код:
{*** Решение уравнений методом Гаусса - Жордана ***} unit GausJordan; interface type TInMatr = array[0..19] of array[0..19] of Double; TOutMatr = array[0..19] of Double; const GAUSS_ACCURACY = 0.0000001; GAUSS_OK = 0; GAUSS_NOSOL = 1; GAUSS_MANYSOL = 2; function gauss(a : TInMatr; n, u : Integer; var x : TOutMatr) : Integer; implementation {********************************************* * Функция решения систем линейных уравнений * * методом Гаусса - Жордана * * (C) 2002 Восков Алексей * * версия 2.1 * *********************************************} // ВХОДНЫЕ ДАННЫЕ { a[20][20] - Матрица для хранения системы a[y][x] последний столбец - для хранения св. члена св. член - в правой части n - число неизвестных u - число уравнений ВЫХОДНЫЕ ДАННЫЕ x[20] - массив для хранения корней системы в случае нормального выполнения задачи функция возвращает 0, в случае неразрешимости 1 в случае бесконечного числа решений 2 } function gauss(a : TInMatr; n, u : Integer; var x : TOutMatr) : Integer; var i, j, k : Integer; // Счетчики циклов sn : Integer; // Номер строки d : Double; // Коэффициент домножения или модуль наиб. эл. begin Result := GAUSS_OK; // Нормальное завершение работы //*** Проверка u и n *** if n > u then begin Result := GAUSS_MANYSOL; Exit; end; //*** Приведение к диагональному виду *** for j := 0 to n - 1 do begin // а) поиск строки с наибольшим по модулю элементом d := Abs(a[j][j]); sn := j; for i := j to u - 1 do if Abs(a[i][j]) > d then begin d := Abs(a[i][j]); sn := i; end; // б) перенос строки на надлежащее место for k := 0 to n do begin d := a[sn][k]; a[sn][k] := a[j][k]; a[j][k] := d; end; // в) деление ведущего ур-я на главный элемент d := a[j][j]; if d > 0 then for k := 0 to n do a[j][k] := a[j][k] / d else for k := 0 to n do a[j][k] := 0; // г) вычитание данной строки из всех остальных // с домножением на коэффициент for i := 0 to u - 1 do begin if i = j then Continue; // Не трогаем вычит. строку d := -a[i][j]; for k := 0 to n do // Вычитание a[i][k] := a[i][k] + a[j][k] * d; end; end; //*** Вычисление корней *** // а) проверка системы на разрешимость if u > n then begin for i := n to u - 1 do begin k := 0; for j := 0 to n - 1 do if Abs(a[i][j]) > GAUSS_ACCURACY then k := 1; if (k = 0) and (Abs(a[i][n]) > GAUSS_ACCURACY) then begin Result := GAUSS_NOSOL; Exit; end; end; end; // б) поиск корней for i := 0 to n - 1 do begin x[i] := -a[i][n]; if a[i][i] <> 1 then // Обработка ошибок begin if x[i] > 0 then begin Result := GAUSS_NOSOL; // Решений нет Exit; end else begin Result := GAUSS_MANYSOL; // Бесконечно много решений Exit; end; end; if Abs(x[i]) < GAUSS_ACCURACY then x[i] := 0; // Обнуление слишком малых знач. end; end; end. Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. |
Этот пользователь сказал Спасибо angvelem за это полезное сообщение: | ||
Aristarh Dark (01.09.2012)
|
#8
|
|||
|
|||
Спасибо большое за перевод кода. Не сочтите за наглость, не могли бы перевести еще один модуль программы на язык Делфи. Эти оба модуля исходники программы которую выкладывал выше (с_urav).
Последний раз редактировалось PIF85, 01.09.2012 в 15:09. |
#9
|
|||
|
|||
Вот код:
Код:
/*** ПОДКЛЮЧАЕМЫЕ ФАЙЛЫ ***/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "gauss2.inc" /********** КОНСТАНТЫ **********/ #define ACCURACY GAUSS_ACCURACY #define ERR_MANYSOL "Реакцию можно уравнять бесконечным числом способов" #define ERR_NOSOL "Эту реакцию нельзя уравнять" #define ERR_EQU "Неверное использование '='" #define ERR_PLUS "Неверное использование '+'" #define ERR_SYNT "Синтаксическая ошибка" #define ERR_WRONGEL "Элемент %c%c не может быть уравнен" #define ERR_CHARGE "Нарушен закон сохранения заряда" #define ERR_MANYELEM "Слишком много элементов" #define ERR_MANYCOMP "Слишком много соединений" #define ERR_MANYBR "Слишком много скобок" #define ERR_SYNTBR "Неправильное использование скобок" /********** ОБЪЯВЛЕНИЯ ФУНКЦИЙ **********/ double rou(double x); char cmpzero(double x); /********** СТРУКТУРЫ **********/ struct composition /* Структура для хранения формулы вещества */ { char name[64]; /* Название соединения */ int charge; /* Заряд иона */ }; struct brackets /* Структура для хранения координат скобок */ { unsigned char open_sign; /* Символ открытой скобки */ unsigned char close_sign; /* Символ закрытой скобки */ int open_pos; /* Позиция открывающей скобки */ int close_pos; /* Позиция закрывающей скобки */ double index; /* Индекс при скобке */ }; /********** ОСНОВНАЯ ФУНКЦИЯ **********/ /* Эта функция осуществляет уравнивание уравнения реакции. Формат ввода указан в начале этого листинга. char *in - входная строка char *res - выходная строка Функция возвращает 0 в случае успеха и 1 в случае ошибки В выходной строке записано либо уравненное уравнение, либо текстовое сообщение с описанием ошибки */ /*** Макросы при функции c_urav ***/ /* Вывод на печать строк */ #define PRINT(fmt, arg) {sprintf(buf, fmt, arg); \ strcat(res, buf);} #define LPRINT(arg) {sprintf(buf, arg);\ strcat(res, buf);} /* Вывод сообщения об ошибке на экран и завершение работы программы */ #define errmessage(txt) {sprintf(res,"%s",txt); return 1;} int c_urav(char *in, char *res) { char buf[100]; /* Буфер для печати */ char eq[256]; /* Буфер для уравнения */ struct composition comp[20]; /* Формулы соединений */ char elem[60] = {0}; /* Массив для хранения знаков эл.*/ /* 2 знака на каждый элемент */ char ce[3]={0}; /* Знак текущего хим. элемента */ double a[20][20] = {0}; /* Матрица для хранения системы ур-ий*/ double x[20]; /* Матрица для хранения коэфф. */ int ncomp; /* (Число соединений в уравнении) - 1 */ int nelem; /* (Число элементов в соединении) - 1 */ struct brackets br[4] = /* Массив для хранения параметров скобок */ {'[',']',-1,-1,1, '(',')',-1,-1,1, '*',13,-1,-1,1, '{','}',-1,-1,1}; double ta, tb; /* Временные переменные */ char *cptr; int i, j, k; /* Счетчики циклов */ unsigned char c, c1; /* Символьные переменные */ double ii; /* Индекс перед элементом */ int n; /* Номер элемента и пр. */ /***** I. ОБРАБОТКА ИСХОДНЫХ ДАННЫХ *****/ res[0] = 0; for (i = 0, j = 0; i < strlen(in); i++) if (in[i] != ' ') eq[j++] = in[i]; eq[j] = 0; /***** II. РАЗБИВКА СТРОКИ НА СОЕДИНЕНИЯ ***/ i = -1; /* Позиция в уравнении */ j = 0; /* Позиция в формуле соединения */ k = 0; /* Число знаков равенства */ n = 1; /* Режим работы 0 выключить разбивку 1 включить разбивку */ ncomp = 0; /* Номер анализируемого соединения */ do { c = eq[++i]; if (c == '{') n = 0; if (c == '}') n = 1; if ( (c == '+' && n) || c == '=') { if (c == '=') k++; comp[ncomp++].name[j] = 0; j = 0; } else comp[ncomp].name[j++] = c; } while (c); if (!n) errmessage(ERR_SYNT); /***** III. ЭЛЕМЕНТАРНЫЙ СИНТАКСИЧЕСКИЙ КОНТРОЛЬ *****/ if (ncomp > 19) errmessage(ERR_MANYCOMP); if (k != 1) /* Должен быть 1 знак '=' */ errmessage(ERR_EQU); for (i = 0; i <= ncomp; i++) { c = comp[i].name[0]; if (c == 0) /* Не должно быть 2 '+' подряд */ errmessage(ERR_PLUS); if ( !(c >= 'A' && c <= 'Z') && c != 'e' && c != '(' && c != ')' && c != '[' && c != ']') errmessage(ERR_SYNT); } /***** IV. СИНТАКСИЧЕСКИЙ АНАЛИЗ БРУТТО - ФОРМУЛЫ СОЕДИНЕНИЙ ***/ nelem = -1; for (i = 0; i <= ncomp; i++) { /*** Анализ формулы на содержание скобок ***/ for (j = 0; j <= 3; j++) /* Сброс массива с коорд. скобок */ { br[j].open_pos = -1; br[j].close_pos = -1;} for (j = 0; j <= strlen(comp[i].name); j++) /* Поиск скобок */ { c = comp[i].name[j]; for (k = 0; k <= 3; k++) { if (c == br[k].open_sign) /* Открывающие скобки */ { if (br[k].open_pos != -1) errmessage(ERR_MANYBR); br[k].open_pos = j; if (k == 2) /* Звёздочка */ { br[2].close_pos = strlen(comp[i].name) + 1; br[2].index = strtod(&comp[i].name[j + 1],&cptr); if (br[k].index == 0) br[k].index = 1;} } if (c == br[k].close_sign) /* Закрывающие скобки */ { if (br[k].close_pos != -1) errmessage(ERR_MANYBR); br[k].close_pos = j; br[k].index = strtod(&comp[i].name[j + 1],&cptr); if (br[k].index == 0) br[k].index = 1;} } } /* Проверка синтаксиса скобок */ for (k = 0; k <= 3; k++) if ((br[k].open_pos == -1 && br[k].close_pos != -1)||(br[k].open_pos > br[k].close_pos)) errmessage(ERR_SYNTBR); /* Выделение электрического заряда */ if (br[3].open_pos != -1 && br[3].close_pos != -1) { /* Выделение абсолютного значения */ comp[i].charge = strtol(&comp[i].name[br[3].open_pos + 1], &cptr, 10); /* Обработка знака */ c = comp[i].name[br[3].close_pos - 1]; if ((c == '-' || c == '+') && comp[i].charge == 0) comp[i].charge = 1; if (c == '-') comp[i].charge = -comp[i].charge; } else comp[i].charge = 0; /* Реакция на признак электрона */ if (comp[i].name[0] == 'e') { comp[i].charge = -1; continue;} /* Синтаксический разбор по элементам */ for (j = 0; j <= strlen(comp[i].name); j++) { /* Первый символ элемента */ c = comp[i].name[j]; if (c < 'A' || c > 'Z') continue; ce[0] = c; /* Попытка обнаружить второй символ элемента */ c1 = comp[i].name[j + 1]; ce[1] = (c1 < 'a' || c1 > 'z') ? 32 : c1; /* Выделение индекса */ if (ce[1] == 32) ii = strtod(&comp[i].name[j + 1], &cptr); else ii = strtod(&comp[i].name[j + 2], &cptr); if (ii == 0) ii = 1; /* В случае отсутствия числа */ /* индекс - 1*/ /* Согласование индекса со скобками */ for (k = 0; k <= 2; k++) if (j > br[k].open_pos && j < br[k].close_pos) ii *= br[k].index; /* Занесение нового элемента в строку */ if (strstr(elem, ce) == NULL) { strcat(elem, ce); nelem++; } /* Вычисление номера элемента и занесение индекса в матрицу */ n = (strstr(elem, ce) - &elem[0]) / 2; a[n][i] += ii; } } if (nelem > 19) errmessage(ERR_MANYELEM); /* Не слишком ли много элементов? */ /***** V. КАЖДЫЙ ЭЛЕМЕНТ ДОЛЖЕН БЫТЬ В ОБЕИХ ЧАСТЯХ УРАВНЕНИЯ *****/ for (i = 0; i <= nelem; i++) { n = 0; for (j = 0; j <= ncomp; j++) if (a[i][j]) n++; if (n < 2) { sprintf(res, ERR_WRONGEL, elem[i * 2], elem[i * 2 + 1]); return 1; } } /***** VI. ПРОВЕРКА ЗАКОНА СОХРАНЕНИЯ ЗАРЯДА ПЕРЕНОС ЗАРЯДОВ В ОБЩУЮ МАТРИЦУ ***/ n = 0; for (i = 0; i <= ncomp; i++) { a[nelem + 1][i] = comp[i].charge; if (comp[i].charge) n++; } if (n == 1) errmessage (ERR_CHARGE);/* Если только 1 заряж. частица */ if (n) nelem++; /* Расширение границ матрицы */ /***** VII. ПРИМЕНЕНИЕ МЕТОДА ГАУССА *****/ i = gauss(a, ncomp, nelem + 1, x); if (i == GAUSS_NOSOL) errmessage(ERR_NOSOL); if (i == GAUSS_MANYSOL) errmessage(ERR_MANYSOL); x[ncomp] = 1; /***** VIII. ПРИВЕДЕНИЕ КОРНЕЙ К ЦЕЛОЧИСЛЕННОМУ ВИДУ *****/ for (i = 1; i <= 1000; i++) { /* Проверка коэфф i на пригодность */ k = 1; for (j = 0; j <= ncomp; j++) { ta = x[j] * (double)i; tb = rou(ta) - ta; if (cmpzero(tb)) {k = 0; break;} } /* Собственно домножение */ if (k == 1) { for (j = 0; j <= ncomp; j++) x[j] *= (double)i; break; } } /***** IX. ВЫВОД ОТВЕТА *****/ /* Соединения с отриц. коэффициентами - продукты с положительными - исходные */ if (x[0] < 0) k = -1; else k = 1; for (i = 0; i <= ncomp; i++) x[i] *= k; /* а) Вывод исходных веществ */ j = 0; /* Если 0 - вещ-во не встречалось */ for (i = 0; i <= ncomp; i++) { /* Вывод соединения i с коэффициентом */ if (x[i] <= 0) continue; if (i > 0 && j) PRINT("%s", " + "); /* Вывод знака - разделителя */ j++; if (cmpzero(x[i] - 1.0)) PRINT("%.0f ",x[i]); PRINT("%s",comp[i].name); } PRINT("%s", " = "); /* Вывод знака равенства */ /* б) Вывод продуктов */ j = 0; /* Если 0 - вещ-во не встречалось */ for (i = 0; i <= ncomp; i++) { /* Вывод соединения i с коэффициентом */ if (x[i] >= 0) continue; if (i > 0 && j) LPRINT(" + "); /* Вывод знака - разделителя */ j++; if (cmpzero(-x[i] - 1.0)) PRINT("%.0f ",-x[i]); PRINT("%s",comp[i].name); } return 0; } /********** ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ **********/ /* Функция округляет число по математическим законам: 3.6 = 4 -3.6 = - 4 3.1 = 3 -3.1 = 3 */ double rou(double x) { double c, d; d = modf(x, &c); if (fabs(d) < 0.5) return c; if (x < 0) return c - 1.0; if (x > 0) return c + 1.0; } /* Сравнение числа с нулем с точностью ACCURACY */ /* 0 - если 0 1 - если не 0 */ char cmpzero(double x) { return (fabs(x) > ACCURACY); } |
#10
|
||||
|
||||
Держи. Сделал, потому что самому было интересно. И, может быть, пригодится когда
Перезалил аттач. Передвинул 1 End немного, поставил несколько индексов, уменьшил размер матрицы.. Последний раз редактировалось YVitaliy, 01.09.2012 в 23:33. |
Этот пользователь сказал Спасибо YVitaliy за это полезное сообщение: | ||
PIF85 (01.09.2012)
|
#11
|
|||
|
|||
Цитата:
|
#12
|
||||
|
||||
Мне уже можно и не делать.
Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. Последний раз редактировалось angvelem, 01.09.2012 в 23:30. |
Этот пользователь сказал Спасибо angvelem за это полезное сообщение: | ||
PIF85 (01.09.2012)
|
#13
|
||||
|
||||
Цитата:
P.S Нет, к сожалению, химией не увлекаюсь. Хотя в универе КР на отлично писал (в частности, по органической химии) |
#14
|
||||
|
||||
Пытаюсь разобраться.
Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. |
#15
|
||||
|
||||
Цитата:
Добавлю и свой вариант, пусть ТС сам разбирается, что к чему. Хм, заметил ошибку. В последний момент добавил в юнит UravProc.pas функцию Format использующую wvsprintf и забыл, что она не работает с дробными числами. Немного изменил код с учётом этого. Обновил вложение. chemistry.rar 8.6Кб Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. Последний раз редактировалось angvelem, 03.09.2012 в 23:08. Причина: Из-за крайне малого разрешённого объёма вложений, вынес архив на внешний сайт. |