diff --git a/UPolynomial.pas b/UPolynomial.pas index c4fd23b..035cb09 100644 --- a/UPolynomial.pas +++ b/UPolynomial.pas @@ -38,7 +38,29 @@ type property Degree: Integer read GetDegree; property Coefficient[const AIndex: Integer]: TBigInt read GetCoefficient; function CalcValueAt(const AX: Int64): TBigInt; + function CalcSignVariations: Integer; + + // Returns 2^n * f(x), given a polynomial f(x) and exponent n. + function ScaleByPowerOfTwo(const AExponent: Cardinal): TBigIntPolynomial; + + // Returns f(s * x), given a polynomial f(x) and scale factor s. function ScaleVariable(const AScaleFactor: TBigInt): TBigIntPolynomial; + + // Returns f(x / 2), given a polynomial f(x). + function ScaleVariableByHalf: TBigIntPolynomial; + + // Returns f(x + 1), given a polynomial f(x). + function TranslateVariableByOne: TBigIntPolynomial; + + // Returns a polynomial with the reverse order of coefficients, i.e. the polynomial + // a_0 * x^n + a_1 * x^(n - 1) + ... + a_(n - 1) * x + a_n, + // given a polynomial + // a_n * x^n + a_(n - 1) * x^(n - 1) + ... + a_1 * x + a_0. + function RevertOrderOfCoefficients: TBigIntPolynomial; + + // Returns a polynomial with all coefficents shifted down one position, and the constant term removed. This should + // only be used when the constant term is zero and is then equivalent to a division of polynomial f(x) by x. + function DivideByVariable: TBigIntPolynomial; function IsEqualTo(const AOther: TBigIntPolynomial): Boolean; function ToString: string; class function Create(const ACoefficients: array of TBigInt): TBigIntPolynomial; static; @@ -72,6 +94,34 @@ begin Result := Result * AX + FCoefficients[i]; end; +function TBigIntPolynomial.CalcSignVariations: Integer; +var + current, last, i: Integer; +begin + Result := 0; + last := 0; + for i := 0 to Length(FCoefficients) - 1 do + begin + current := FCoefficients[i].Sign; + if (current <> 0) and (last <> current) then + begin + if last <> 0 then + Inc(Result); + last := current + end; + end; +end; + +function TBigIntPolynomial.ScaleByPowerOfTwo(const AExponent: Cardinal): TBigIntPolynomial; +var + len, i: Integer; +begin + len := Length(FCoefficients); + SetLength(Result.FCoefficients, len); + for i := 0 to len - 1 do + Result.FCoefficients[i] := FCoefficients[i] << AExponent; +end; + function TBigIntPolynomial.ScaleVariable(const AScaleFactor: TBigInt): TBigIntPolynomial; var len, i: Integer; @@ -94,6 +144,72 @@ begin end; end; +function TBigIntPolynomial.ScaleVariableByHalf: TBigIntPolynomial; +var + len, i: Integer; +begin + len := Length(FCoefficients); + SetLength(Result.FCoefficients, len); + Result.FCoefficients[0] := FCoefficients[0]; + for i := 1 to len - 1 do + Result.FCoefficients[i] := FCoefficients[i] >> i; +end; + +function TBigIntPolynomial.TranslateVariableByOne: TBigIntPolynomial; +var + len, i, j: Integer; + factors: array of Cardinal; +begin + len := Length(FCoefficients); + SetLength(Result.FCoefficients, len); + SetLength(factors, len); + for i := 0 to len - 1 do + begin + Result.FCoefficients[i] := TBigInt.Zero; + factors[i] := 1; + end; + + // Calculates new coefficients. + for i := 0 to len - 1 do + begin + for j := 0 to len - i - 1 do + begin + if (i <> 0) and (j <> 0) then + factors[j] := factors[j] + factors[j - 1]; + Result.FCoefficients[i] := Result.FCoefficients[i] + factors[j] * FCoefficients[j + i]; + end; + end; +end; + +function TBigIntPolynomial.RevertOrderOfCoefficients: TBigIntPolynomial; +var + len, skip, i: Integer; +begin + // Counts the trailing zeros to skip. + len := Length(FCoefficients); + skip := 0; + while (skip < len) and (FCoefficients[skip] = 0) do + Inc(skip); + + // Copies the other coefficients in reverse order. + SetLength(Result.FCoefficients, len - skip); + for i := skip to len - 1 do + Result.FCoefficients[len - i - 1] := FCoefficients[i]; +end; + +function TBigIntPolynomial.DivideByVariable: TBigIntPolynomial; +var + len: Integer; +begin + len := Length(FCoefficients); + if len > 1 then + Result.FCoefficients := Copy(FCoefficients, 1, len - 1) + else begin + SetLength(Result.FCoefficients, 1); + Result.FCoefficients[0] := TBigInt.Zero; + end; +end; + function TBigIntPolynomial.IsEqualTo(const AOther: TBigIntPolynomial): Boolean; var i: Integer; diff --git a/tests/UPolynomialTestCases.pas b/tests/UPolynomialTestCases.pas index b4d75a0..c0e9e91 100644 --- a/tests/UPolynomialTestCases.pas +++ b/tests/UPolynomialTestCases.pas @@ -40,6 +40,13 @@ type procedure TestUnequalSameLength; procedure TestUnequalDifferentLength; procedure TestTrimLeadingZeros; + procedure TestCalcValueAt; + procedure TestSignVariations; + procedure TestScaleByPowerOfTwo; + procedure TestScaleVariable; + procedure TestTranslateVariableByOne; + procedure TestRevertOrderOfCoefficients; + procedure TestDivideByVariable; end; implementation @@ -110,6 +117,69 @@ begin AssertTrue('Polynomials are not equal.', a = b); end; +procedure TBigIntPolynomialTestCase.TestCalcValueAt; +var + a: TBigIntPolynomial; + exp: TBigInt; +begin + a := TBigIntPolynomial.Create([80, 892477222, 0, 921556, 7303]); + exp:= TBigInt.FromInt64(16867124285); + AssertTrue('Polynomial evaluation unexpected.', a.CalcValueAt(15) = exp); +end; + +procedure TBigIntPolynomialTestCase.TestSignVariations; +var + a: TBigIntPolynomial; +begin + a := TBigIntPolynomial.Create([-10, 15, 0, 10, -20, -15, 0, 0, 5, 10, -10]); + AssertEquals(4, a.CalcSignVariations); +end; + +procedure TBigIntPolynomialTestCase.TestScaleByPowerOfTwo; +var + a, b: TBigIntPolynomial; +begin + a := TBigIntPolynomial.Create([10, 7, 5, 1034]).ScaleByPowerOfTwo(7); + b := TBigIntPolynomial.Create([128 * 10, 128 * 7, 128 * 5, 128 * 1034]); + AssertTrue('Polynomials are not equal.', a = b); +end; + +procedure TBigIntPolynomialTestCase.TestScaleVariable; +var + a, b: TBigIntPolynomial; +begin + a := TBigIntPolynomial.Create([10, 7, 5, 1034]).ScaleVariable(TBigInt.FromInt64(10)); + b := TBigIntPolynomial.Create([10, 70, 500, 1034000]); + AssertTrue('Polynomials are not equal.', a = b); +end; + +procedure TBigIntPolynomialTestCase.TestTranslateVariableByOne; +var + a, b: TBigIntPolynomial; +begin + a := TBigIntPolynomial.Create([10, 7, 5, 1034]).TranslateVariableByOne; + b := TBigIntPolynomial.Create([1056, 3119, 3107, 1034]); + AssertTrue('Polynomials are not equal.', a = b); +end; + +procedure TBigIntPolynomialTestCase.TestRevertOrderOfCoefficients; +var + a, b: TBigIntPolynomial; +begin + a := TBigIntPolynomial.Create([0, 10, 7, 5, 1034]).RevertOrderOfCoefficients; + b := TBigIntPolynomial.Create([1034, 5, 7, 10]); + AssertTrue('Polynomials are not equal.', a = b); +end; + +procedure TBigIntPolynomialTestCase.TestDivideByVariable; +var + a, b: TBigIntPolynomial; +begin + a := TBigIntPolynomial.Create([0, 10, 7, 5, 1034]).DivideByVariable; + b := TBigIntPolynomial.Create([10, 7, 5, 1034]); + AssertTrue('Polynomials are not equal.', a = b); +end; + initialization RegisterTest(TBigIntPolynomialTestCase);