Как сложить два многочлена разной длины

96
30 мая 2021, 07:40

В общем, есть функция с перегруженным оператором сложения. Если степень многочленов одинаковая, то всё считает спокойно, но если степень многочленов разная, то одночлены складываются неправильно(т.е одночлен второй степени может прибавиться к одночлену третьей степени и т.д.) Вроде бы должно быть простое решение, но я его не нахожу.

 public static Polynomial operator +(Polynomial One, Polynomial Two)
        {
            int pow1 = One.power;
            int pow2 = Two.power;
            double[] coeff1 = new double[pow1 + 1];
            Polynomial Three = new Polynomial(coeff1, pow1);
            for (int i = 0; i < One.power + 1; i++)
            {
                Three.coeff[i] = One.coeff[i] + Two.coeff[i];
            }
            return Three;
            }
        public void Output(Polynomial One)
        {
            for (int i = 0; i <= power; i++)
            {
                Console.Write(One.coeff[i] + "x" + "^" + (power-i));
                if (i < power)
                {
                    Console.Write("+");
                }
            }
            Console.WriteLine(" ");
        }
Answer 1

И так, как я понял (поправьте если ошибся), структуру вашего полинома можно представить следующим образом:

class Polinomial
{
  //точность вычислений для операций с плавающей точкой
  private static readonly double _precision = 0.0001;
  //массив под коэффициенты, по-умолчанию, инициализируем пустым
  private readonly double[] _coeff = new double[0];
  //добавим индексатор для доступа к коэффициентам на чтение
  //подобные объекты лучше делать неизменяемыми
  public double this[int index] => _coeff[index];
  //степень хранить не требуется, длина массива хранится, а не вычисляется
  public int Power => _coeff.Length - 1;
  //конструктор принимающий массив у вас уже есть, параметр степень там избыточен,
  //что будет если передать степень большую чем длина массива? убираем степень из параметров
  public Polinomial(double[] coeff)
  {
    _coeff = coeff;
  }
  public static Polinomial operator +(Polinomial a, Polinomial b)
  {
    //выбираем полином наибольшей и наименьшей степени
    Polinomial maxPowerPoly = a.Power < b.Power ? b : a;
    Polinomial minPowerPoly = a.Power < b.Power ? a : b;
    //создаем массив для предварительного результата
    double[] predResult = new double[maxPowerPoly.Power + 1];
    //складываем члены начиная с нулевой до максимальной степени для полинома меньшей степени
    for(int i = 0; i < minPowerPoly.Power + 1; i++)
    {
      predResult[i] = minPowerPoly[i] + maxPowerPoly[i];
    }
    //дописываем старшие члены от полинома большей степени
    for(int i = minPowerPoly.Power + 1; i < maxPowerPoly.Power + 1; i++)
    {
      predResult[i] = maxPowerPoly[i];
    }
    //ищем индекс наибольшего не нулевого элемента массива
    //при сложении полиномов одинаковой степени, степень может и уменьшиться
    int notZeroIndex = predResult.Length - 1;
    //все  что меньше заданной точности по модулю - считаем нулем
    while(Math.Abs(predResult[notZeroIndex]) < _precision)
    {
      notZeroIndex--;
    }
    //формируем окончательный результат
    double[] result = new double[notZeroIndex+1];
    for(int i = 0; i < result.Length; i++)
    {
      //если значение меньше заданной точности - заменяем его на явный ноль
      result[i] = Math.Abs(predResult[i]) < _precision ? 0.0 : predResult[i];
    }
    return new Polinomial(result);
  }
  //ну и, в качестве бонуса, сделаем нормальный вывод через ToString
  //чтобы можно было просто сунуть переменную нашего типа в Console.WriteLine
  public override string ToString()
  {
    StringBuilder res = new StringBuilder();
    if(Power == 1)
    {
      res.Append(_coeff[Power].ToString("0.####x"));
    }
    else
    {
      res.Append(_coeff[Power].ToString("0.####x^"));
      res.Append(Power);
    }
    for (int i = Power - 1; i >= 0; i--)
    {
      if(Math.Abs(_coeff[i]) > _precision)
      {
        if(i > 1)
        {   
          res.Append(_coeff[i].ToString("+0.####x^;-0.####x^"));
          res.Append(Power);
        }
        else if(i > 0)
        {
          res.Append(_coeff[i].ToString("+0.####x;-0.####x"));
        }
        else
        {
          res.Append(_coeff[i].ToString("+0.####;-0.####"));
        }
      }
    }
    return res.ToString();
  }
  //остальное допишете сами по аналогии
}

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

Важное уточнение: все это будет работать при одном, но важном условии - индекс коэффициента в массиве должен совпадать со степенью элемента полинома, к которому относится данный коэффициент. Это значит, что полином вида
x^2 + 2x + 3
будет представлен массивом
new double[]{ 3.0, 2.0, 1.0 }
иными словами запись коэффициентов будет в обратном порядке, относительно принятого в математике, ну и пустые элементы промежуточных степеней также придется хранить постоянно. В вашем коде данное условие было нарушено, коэффициенты хранились в прямом порядке, из-за чего и возникала проблема при сложении.

Эти условия накладывает выбранный вами способ хранения коэффициентов.

READ ALSO
Как правильно использовать SecureString?

Как правильно использовать SecureString?

Например, нужно захешировать пароль методом string CalculateHash(string source)Но если я вытяну значение строки с SecureString в виде экземпляра класса string и передам...

102
Когда и как включается DI в asp netcore

Когда и как включается DI в asp netcore

В описаниях DI для asp netcore пишут, что настройка выполняется в ConfigureServices() класса Startup

92
Покраска Excel при экспорте

Покраска Excel при экспорте

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

91
Chrome failed to start: exited abnormally (unknown error: DevToolsActivePort file doesn&#39;t exist) Тест первый запустился прошел

Chrome failed to start: exited abnormally (unknown error: DevToolsActivePort file doesn't exist) Тест первый запустился прошел

проблема в чем: поставил chromedriver через консоль, тест первый раз запустился прошел, следующий сразу упал, потом постоянно такая ошибка, возможно...

147