I have the following equation
var x = 1.0175d;
var spread = 0.0525d;
var duration = 6.36019306689938d;
var result = spread - (x / 100 - 1) / duration;
// result = 0.208128137
however I'm struggling to solve the equation for x
where we start from the result
.
0.0525 - ( x / 100 - 1) / 6.36019306689938 = 0.208128137
The following equation solver returns the correct result, and shows a step-by-step, however I cant follow how to turn this into C# as it relies on the notion of x
whilst simplifying the equation.
https://www.mathpapa.com/equation-solver/?q=0.0525-%28x%2F100-1%29%2F6.36019306689938%3D0.208128137
To solve an expression such as spread - (x / 100 - 1) / duration = result
for x
using Math.NET Symbolics
:
Firstly use NuGet to add MathNet.Symbolics
to your project.
Next, to solve an equation you need to rewrite it in normalised form so that it equals zero:
spread - (x / 100 - 1) / duration - result = 0
(In this case we just subtracted the right hand side of the equation from both sides, which by definition results in the expression being equal to zero.)
Then we can define the expression to solve for x
like so:
var expression = Infix.Parse("spread - (x / 100 - 1) / duration - result").ResultValue;
Now we need to write a little helper method to solve a simple root (courtesy of /u/Christoph Rüegg):
public static Expression SolveSimpleRoot(Expression variable, Expression expr)
{
// try to bring expression into polynomial form
Expression simple = Algebraic.Expand(Rational.Numerator(Rational.Simplify(variable, expr)));
// extract coefficients, solve known forms of order up to 1
Expression[] coeff = Polynomial.Coefficients(variable, simple);
return coeff.Length switch {
1 => Expression.Zero.Equals(coeff[0]) ? variable : Expression.Undefined,
2 => Rational.Simplify(variable, Algebraic.Expand(-coeff[0] / coeff[1])),
_ => Expression.Undefined
};
}
Now we can call SolveSimpleRoot()
to solve the expression, and then evaluate that solution by supplying all the spread
, duration
and result
parameters like so:
var solution = SolveSimpleRoot(Expression.Symbol("x"), expression);
Dictionary<string, FloatingPoint> values = new() {
["spread"] = 0.0525,
["duration"] = 6.36019306689938,
["result"] = 0.208128137
};
var answer = Evaluate.Evaluate(values, solution).RealValue;
Putting that all together into a complete console app:
using MathNet.Symbolics;
namespace Net8Console;
static class Program
{
public static void Main()
{
var expression = Infix.Parse("spread - (x / 100.0 - 1.0) / duration - result").ResultValue;
var solution = SolveSimpleRoot(Expression.Symbol("x"), expression);
Dictionary<string, FloatingPoint> values = new() {
["spread"] = 0.0525,
["duration"] = 6.36019306689938,
["result"] = 0.208128137
};
var answer = Evaluate.Evaluate(values, solution).RealValue;
Console.WriteLine(answer);
}
public static Expression SolveSimpleRoot(Expression variable, Expression expr)
{
// try to bring expression into polynomial form
Expression simple = Algebraic.Expand(Rational.Numerator(Rational.Simplify(variable, expr)));
// extract coefficients, solve known forms of order up to 1
Expression[] coeff = Polynomial.Coefficients(variable, simple);
return coeff.Length switch {
1 => Expression.Zero.Equals(coeff[0]) ? variable : Expression.Undefined,
2 => Rational.Simplify(variable, Algebraic.Expand(-coeff[0] / coeff[1])),
_ => Expression.Undefined
};
}
}