Страницы

Поиск по вопросам

понедельник, 6 января 2020 г.

Как решить квадратное уравнение написанное в виде строки?

#c


Пользователь вводит строку которая является квадратным уравнением,вот так: 

scanf("%s",string[80]);


Вводим,например: 21x^2+3x+5=0. Нужно считать строку каким-то способом взять из нее
a,b,c, то есть 21,3,5, чтобы эти числа были типом double. И потом уже решить квадратное
уравнение. В программе можно использовать только библиотеку stdio и только одну функцию
из библиотеки math.h - это sqrt, больше ничего нельзя.

Уравнение я смогу написать а вот как изьять из строки числа как double понятия не имею.
    


Ответы

Ответ 1



В данном случае scanf() с одной большой форматной строкой, как предложил @Sergey, не подойдёт. Раз члены уравнения могут следовать в любом порядке, то и строку надо считывать частями. Пусть на входе у нас строка вида S1+...+SN=0 или S1+...+SN=<нецелое_число> (где Si = <нецелое_число>x, либо Si = <нецелое_число>x^<целое_число>), а на выходе — массив коэффициентов, где индекс массива соответствует нужной степени при коэффициенте. Важное замечание: так как число может быть сколь угодно большим, то во избежание переполнения строкового буфера мы будем считывать его поциферно. Ну а так как строка сложная, воспользуемся конечным автоматом. #include #define bool unsigned char #define true 1 #define false 0 enum States { // Конечные состояния Result_Success, // Успешное завершение Result_CoefficientCantBeStored, // Ошибка: массив outCoeffs слишком мал Result_UnexpectedSymbolInCoeff, // Ошибка: неожиданный символ в коэффициенте Result_UnexpectedEndOfPower, // Ошибка: После знака степени нет самой степени Result_UnexpectedEndOfRightSide,// Ошибка: не указана правая часть уравнения // Промежуточные состояния State_AtCoeffStart, // Первый символ коэффициента (+/-/цифра) State_AtCoeff, // Дальнейшие цифры коэффициента State_AtX, // Буква "икс" State_AtPowerCoeffStart, // Первый символ показателя степени члена State_AtPowerCoeff, // Показатель степени члена State_AtRightSideStart, // Первый символ справа от знака равенства State_AtRightSide, // Дальнейшие цифры справа от знака равенства // Первое неконечное состояние (используется при проверке на необходимость выхода) FirstInternalState = State_AtCoeffStart }; /** * Функция разбора строки с линейным уравнением и вычленения из неё коэффициентов. * * Переметры: * * in * Дескриптор входного символьного потока. * * outCoeffs * Указатель на массив, который будет принимать коэффициенты, считанные * из уравнения. Коэффициент для N-й степени идёт в outCoeffs[N]. * Если определённый коэффициент не указан в уравнении, то в соответствующий * элемент массива будет записан положительный ноль. * * coeffsCount * Количество элементов в массиве outCoeffs. Если очередная степень приводит * к записи за пределами outCoeffs, функция возвращает * Result_CoefficientCantBeStored. * * Возвращаемое значение: * * Константа из семейства States::Result_*. При возникновении ошибки происходит * возврат кода, отличного от Result_Success; массив outCoeffs при этом содержит * те коэффициенты, которые были успешно считаны целиком до возникновения ошибки. */ enum States parse(FILE* in, double* outCoeffs, size_t coeffsCount) { // Зануляем все указанные коэффициенты, вдруг не все из них будут указаны в уравнении for(size_t i = 0; i < coeffsCount; ++i) outCoeffs[i] = 0.0; enum States state = State_AtCoeffStart; size_t currentPowCoefficient = 0; bool isPositiveCoeff; double numBuffer = 0.0; bool metDecimalDot = false; size_t denomPower = 0; // Так как нам может потребоваться попридержать текущий символ до следующего // состояния, введём для него промежуточный буфер char ch = fgetc(in); while(state >= FirstInternalState) { // Считываем очередной символ и решаем, что с ним делать (решение принимаем // с помощью простенького конечного автомата). // // Да простят меня нелюбители switch-bases FSM, но пробрасывать // во вспомогательные функции все параметры и переменные — для учебного // примера это, пожалуй, перебор. switch(state) { case State_AtCoeffStart: // Сюда мы можем выйти при завершении предыдущего члена. // Поэтому именно здесь мы выдаём готовый коэффициент. if(coeffsCount > currentPowCoefficient) { // Чтобы сместить десятичную точку на denomPower позиций // вправо, мы могли бы воспользоваться pow(). Однако, // для этого потребуется зпрещённая math.h, а потому мы //вынуждены крутить цикл double decimalPointOffseter = 1.0; for(size_t i = 0; i < denomPower; ++i) decimalPointOffseter /= 10.0; outCoeffs[currentPowCoefficient] = numBuffer * (isPositiveCoeff ? 1.0 : -1.0) / decimalPointOffseter; } else state = Result_CoefficientCantBeStored; // Переходим непосредственно к чтению нового члена metDecimalDot = false; if(ch == '-') { numBuffer = 0.0; isPositiveCoeff = false; ch = fgetc(in); state = State_AtCoeff; } else if(ch == '=') { ch = fgetc(in); state = State_AtRightSideStart; } else if(ch == EOF) { state = Result_Success; } else { numBuffer = 0.0; isPositiveCoeff = true; state = State_AtCoeff; } break; case State_AtCoeff: if(ch >= '0' && ch <= '9') { numBuffer *= 10.0; numBuffer += (float)(int)(ch - '0'); ch = fgetc(in); ++denomPower; // Ничего не проверяем, всё равно будет сброс при точке } else if(ch == 'x') { state = State_AtX; ch = fgetc(in); } else if(ch == '+' || ch == '-' || ch == EOF) { // Окончание коэффициента с нулевой степенью. Придерживаем символ currentPowCoefficient = 0; state = State_AtCoeffStart; } else if(ch == '.') { metDecimalDot = true; denomPower = 0; } else state = Result_UnexpectedSymbolInCoeff; break; case State_AtX: // Подготавливаем аккумулятор для коэффициента currentPowCoefficient = 0; if(ch == '^') { ch = fgetc(in); state = State_AtPowerCoeffStart; } else { // Окончание коэффициента с первой степенью. Придерживаем символ currentPowCoefficient = 1; state = State_AtCoeffStart; } break; case State_AtPowerCoeffStart: state = (ch != EOF) ? State_AtPowerCoeff : Result_UnexpectedEndOfPower; break; case State_AtPowerCoeff: if(ch >= '0' && ch <= '9') { currentPowCoefficient *= 10.0; currentPowCoefficient += (size_t)(ch - '0'); ch = fgetc(in); } else state = State_AtCoeffStart; break; case State_AtRightSideStart: if(ch == '-') { numBuffer = 0.0; isPositiveCoeff = true; // Инверсия знака ch = fgetc(in); state = State_AtRightSide; } else if(ch == EOF) { state = Result_UnexpectedEndOfRightSide; } else { numBuffer = 0.0; isPositiveCoeff = false; // Инверсия знака state = State_AtRightSide; } break; case State_AtRightSide: if(ch == EOF) { currentPowCoefficient = 0; numBuffer = -numBuffer; // Переходим, чтобы сохранить коэффициент и сразу же выйти state = State_AtCoeffStart; } else if(ch == '.') { metDecimalDot = true; denomPower = 0; } else { numBuffer *= 10.0; numBuffer += (double)(int)(ch - '0'); ch = fgetc(in); ++denomPower; // Ничего не проверяем, всё равно будет сброс при точке } break; } } return state; }

Ответ 2



scanf("%fx^2+%fx+%f=0", &a, &b, &c);

Комментариев нет:

Отправить комментарий