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
14 changes: 14 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,20 @@ arcsine of that is `NaN`. Of `arcsin(k + c)` for `k` from 1 to 40 and `c` in `pi
| `"arcsin(6 + pi)".ToEntity().Evaled` | `NaN` | `1.5707963267948966 - 2.902976737696685i`, to 15 digits |
| `"arccos(6 + pi)".ToEntity().Evaled` | `NaN` | `2.902976737696685i`, to 15 digits |

### An exact rational is zero, positive or negative as it is

**Silent: 0 divided by a rational smaller than about 1e-199 is 0, where it was NaN.** Whether an exact rational was zero,
and its sign, was read off its decimal, written out in the precision context, whose exponent range writes every rational
under about 1e-199 in size as 0. So `0 / 10^(-200)` was a division by zero, and `0 ^ (1/10^250)` a power to an exponent
that was not positive. A rational is now read by its exact value
([#2277](https://github.com/asc-community/AngouriMath/issues/2277)).

| Input | Was (2.6.0) | Now |
|---|---|---|
| `"0 / 10^(-200)".ToEntity().Evaled` | `NaN` | `0` |
| `"0 / (3/10^260)".ToEntity().Evaled` | `NaN` | `0` |
| `"0 ^ (1/10^250)".ToEntity().Evaled` | `NaN` | `0` |

### A system with a product equation is solved branch by branch

**Silent: solutions that were missing are answered.** `EquationSystem.Solve` eliminated `x * y = 0` for `y` as `0`,
Expand Down
3 changes: 3 additions & 0 deletions Sources/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[Tests/UnitTests/Core/DividesTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[Tests/UnitTests/Core/ATinyRationalIsNotZeroTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[Tests/UnitTests/Core/CardinalityTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,15 @@ private protected Complex(Real? real, Real? imaginary) =>
/// <summary>
/// Checks if both parts equal 0
/// </summary>
public new bool IsZero => RealPart.EDecimal.IsZero && ImaginaryPart.EDecimal.IsZero;
/// <remarks>
/// A rational part is zero when it is, and not when its decimal is: written out in the
/// precision context, every rational under 1e-199 in size is 0, and 0 / 10^(-250) was NaN.
/// <a href="https://github.com/asc-community/AngouriMath/issues/2277">#2277</a>
/// </remarks>
public new bool IsZero => PartIsZero(RealPart) && PartIsZero(ImaginaryPart);

private static bool PartIsZero(Real part) =>
part is Rational rational ? rational.ERational.IsZero : part.EDecimal.IsZero;

/// <summary>
/// Creates an instance of Complex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,17 @@ private protected Real() : base(null, null) { }
public override bool IsExact => !EDecimal.IsFinite;

/// <summary>Strictly less than 0</summary>
public bool IsNegative => EDecimal.IsNegative;
/// <remarks>
/// A rational's sign is its own, and not its decimal's: the decimal is written out in the
/// precision context, whose exponent range writes every rational under 1e-199 in size as
/// zero, so 0^(10^(-250)) was NaN.
/// <a href="https://github.com/asc-community/AngouriMath/issues/2277">#2277</a>
/// </remarks>
public bool IsNegative => this is Rational rational ? rational.ERational.Sign < 0 : EDecimal.IsNegative;

/// <summary>Strictly greater than 0</summary>
public bool IsPositive => !EDecimal.IsNegative && !EDecimal.IsZero;
/// <remarks>A rational's sign is its own, as for <see cref="IsNegative"/>.</remarks>
public bool IsPositive => this is Rational rational ? rational.ERational.Sign > 0 : !EDecimal.IsNegative && !EDecimal.IsZero;

/// <summary>
/// Creates an instance of Real
Expand Down
51 changes: 51 additions & 0 deletions Sources/Tests/UnitTests/Core/ATinyRationalIsNotZeroTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// Copyright (c) 2019-2026 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
// Website: https://am.angouri.org.
//

using AngouriMath.Extensions;
using Xunit;
using static AngouriMath.Entity.Number;

namespace AngouriMath.Tests.Core
{
/// <summary>
/// An exact rational is zero, positive or negative as it is, and not as its decimal is: the decimal is written out in the
/// precision context, whose exponent range writes every rational under 1e-199 in size as 0, so 0 / 10^(-200) was NaN.
/// <a href="https://github.com/asc-community/AngouriMath/issues/2277">#2277</a>
/// </summary>
[Trait("Area", "Core")]
public sealed class ATinyRationalIsNotZeroTest
{
[Theory]
[InlineData("0 / 10^(-200)", "0")]
[InlineData("0 / 10^(-250)", "0")]
[InlineData("0 / (3/10^260)", "0")]
[InlineData("0 / (-1/10^300)", "0")]
[InlineData("0 ^ (1/10^250)", "0")]
[InlineData("0 / 10^(-199)", "0")]
[InlineData("10^(-250) * 10^250", "1")]
[InlineData("(1/10^250) / (1/10^250)", "1")]
public void ItIsWhatItIs(string expression, string value)
{
Assert.Equal(value.ToEntity(), expression.ToEntity().Evaled);
Assert.Equal(value.ToEntity(), expression.ToEntity().Simplify());
}

[Fact]
public void ItsSignIsItsOwn()
{
var tiny = Rational.Create(1, PeterO.Numbers.EInteger.FromInt32(10).Pow(250));
Assert.False(tiny.IsZero);
Assert.True(tiny.IsPositive);
Assert.False(tiny.IsNegative);
var negative = (Rational)(-tiny);
Assert.True(negative.IsNegative);
Assert.False(negative.IsPositive);
Assert.True(Integer.Zero.IsZero);
Assert.False(Integer.Zero.IsPositive || Integer.Zero.IsNegative);
}
}
}
Loading