Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,17 @@ negative even integer or off the integers, since the extension through the gamma
| `"n!!".ToEntity()` | throws `UnhandledParseException` | `n!!` |
| `"n!!!".ToEntity()` | throws `UnhandledParseException` | throws `UnrecognizedFunctionParseException` |

### `mod` compiles over `Complex`

**Not silent: what was refused is compiled.** `Compile<Complex, ...>` refused `mod` with `UncompilableNodeException`,
the operator not being defined for `System.Numerics.Complex`. It now takes the remainder `Compile` takes: the floored
one where both sides are real, and `NaN` where either is not
([#2195](https://github.com/asc-community/AngouriMath/issues/2195)).

| Input | Was (2.6.0) | Now |
|---|---|---|
| `"x mod 3".ToEntity().Compile<Complex, Complex>("x")(7)` | `UncompilableNodeException` | `(1, 0)` |

### A compiled statement with no truth value has none

**Silent in part: a compiled comparison has the truth value evaluation gives it.** A comparison over `Complex` was refused
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,12 @@ public virtual Expression ConvertBinaryNode(Expression left, Expression right, E
// the shortest expression that turns the one into the other for every pair of
// signs. Not widened to double the way division is -- the remainder of two
// integers is an integer, and widening would only lose that.
// Over the complex numbers the remainder FastExpression takes, the floored one where
// both are real and NaN where either is not, as the interpreter leaves it unevaluated:
// the operator is not defined for System.Numerics.Complex, and this was refused.
// https://github.com/asc-community/AngouriMath/issues/2195
Modf when left.Type == typeof(System.Numerics.Complex) && right.Type == typeof(System.Numerics.Complex)
=> Expression.Call(complexRemainder, left, right),
Modf => Operator(ExpressionType.Modulo,
Operator(ExpressionType.Add, Operator(ExpressionType.Modulo, left, right), right),
right),
Expand Down Expand Up @@ -452,6 +458,9 @@ private static MethodInfo Conv<TFrom, TTo>(Expression<Func<TFrom, TTo>> e)
{ (ExpressionType.GreaterThanOrEqual, typeof(BigInteger)), Cmp<BigInteger>((a, b) => a >= b) },
};

[ConstantField] private static readonly MethodInfo complexRemainder =
((MethodCallExpression)((Expression<Func<System.Numerics.Complex, System.Numerics.Complex, System.Numerics.Complex>>)((a, b) => RealOnly.Mod(a, b))).Body).Method;

private static MethodInfo Op<T>(Expression<Func<T, T, T>> e)
=> ((BinaryExpression)e.Body).Method
?? throw new AngouriBugException($"{typeof(T)} defines this operator as an instruction, not a method");
Expand Down
14 changes: 14 additions & 0 deletions Sources/Tests/UnitTests/Convenience/ModulusTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,20 @@ public void TheStackMachineRefusesANonRealArgument() =>
public void TheLinqCompilerAgreesWithTheInterpreter(int at, int expected) =>
Assert.Equal(expected, "x mod 3".ToEntity().Compile<int, int>("x")(at));

/// <summary>
/// Over <see cref="Complex"/>, where the operator is not defined and this was refused, the
/// LINQ compiler takes the remainder the stack machine does.
/// https://github.com/asc-community/AngouriMath/issues/2195
/// </summary>
[Fact]
public void TheLinqCompilerTakesTheStackMachinesRemainderOverTheComplexNumbers()
{
var compiled = "x mod 3".ToEntity().Compile<Complex, Complex>("x");
Assert.Equal(new Complex(1, 0), compiled(7));
Assert.Equal(new Complex(2, 0), compiled(-7));
Assert.True(double.IsNaN(compiled(new Complex(2, 1)).Real));
}

[Fact]
public void TheLinqCompilerKeepsTheFractionalPart() =>
Assert.Equal(1.5, "x mod y".ToEntity().Compile<double, double, double>("x", "y")(7.5, 2), 9);
Expand Down
Loading