Updated XML documents to match MPIR 2.7.2 documentation, and added mixed comparisons between rationals and integers based on the new mpq_cmp_z function.

This commit is contained in:
Alex Dyachenko 2015-12-23 14:29:26 -05:00
parent b006a3b4d9
commit d895d98428
5 changed files with 137 additions and 45 deletions

View File

@ -41,6 +41,33 @@ namespace MPIR.Tests.HugeRationalTests
}
}
[TestMethod]
public void RationalCompareToHugeInt()
{
using (var a = new HugeRational("-222509832503450298345029835740293845721/115756986668303657898962467957"))
using (var b = new HugeInt("115756986668303657898962467957"))
using (var c = new HugeRational("115756986668303657898962467957/1"))
using (var d = new HugeInt(1922215141))
{
Assert.AreEqual(-1, System.Math.Sign(a.CompareTo(d)));
Assert.AreEqual(1, System.Math.Sign((-a).CompareTo(d)));
Assert.AreEqual(-1, System.Math.Sign((-a).CompareTo(d + 1)));
Assert.AreEqual(1, System.Math.Sign(d.CompareTo(a)));
Assert.AreEqual(-1, System.Math.Sign(d.CompareTo(-a)));
Assert.AreEqual(1, System.Math.Sign((d + 1).CompareTo(-a)));
Assert.AreEqual(0, System.Math.Sign(b.CompareTo(c)));
Assert.AreEqual(0, System.Math.Sign(c.CompareTo(b)));
Assert.AreEqual(0, System.Math.Sign((-b).CompareTo(-c)));
Assert.AreEqual(0, System.Math.Sign((-c).CompareTo(-b)));
Assert.AreEqual(1, System.Math.Sign(b.CompareTo(c - 1)));
Assert.AreEqual(1, System.Math.Sign(c.CompareTo(b - 1)));
Assert.AreEqual(-1, System.Math.Sign((-b).CompareTo(1 - c)));
Assert.AreEqual(-1, System.Math.Sign((-c).CompareTo(1 - b)));
}
}
[TestMethod]
public void RationalCompareToObject()
{
@ -437,6 +464,28 @@ namespace MPIR.Tests.HugeRationalTests
}
}
[TestMethod]
public void RationalEqualsHugeInt()
{
using (var a = new HugeRational("-222509832503450298345029835740293845721/115756986668303657898962467957"))
using (var b = new HugeInt(1922215142))
using (var c = new HugeRational("115756986668303657898962467957/1"))
using (var d = new HugeInt("-115756986668303657898962467957"))
{
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(b.Equals(a));
Assert.IsFalse(a.Equals(-b));
Assert.IsFalse(b.Equals(-a));
Assert.IsFalse(c.Equals(d));
Assert.IsTrue(c.Equals(-d));
Assert.IsTrue((-c).Equals(d));
Assert.IsTrue(d.Equals(-c));
Assert.IsTrue((-d).Equals(c));
Assert.IsTrue(Equals(c, -d));
Assert.IsTrue(Equals(-c, d));
}
}
[TestMethod]
public void RationalEqualsExpression()
{

View File

@ -172,40 +172,7 @@ namespace MPIR
#pragma region Interface implementations
int MPEXPR_NAME::CompareTo(Object^ a, bool& valid)
{
valid = true;
if (IS_NULL(a))
return 1;
MPEXPR_NAME^ expr = dynamic_cast<MPEXPR_NAME^>(a);
if(!IS_NULL(expr))
return CompareTo(expr);
EvaluationContext context;
if(a->GetType() == mpir_ui::typeid)
{
ASSIGN_TO(context);
return MP(cmp_ui)(CTXT(0), (mpir_ui)a);
}
if(a->GetType() == mpir_si::typeid)
{
ASSIGN_TO(context);
return MP(cmp_si)(CTXT(0), (mpir_si)a);
}
if(a->GetType() == double::typeid)
{
ASSIGN_TO(context);
return MP(cmp_d)(CTXT(0), (double)a);
}
valid = false;
return 0;
}
//CompareTo has to be defined in HugeRational.cpp because it depends on HugeRational.h
int MPEXPR_NAME::CompareTo(Object^ a)
{

View File

@ -446,8 +446,11 @@ namespace MPIR
/// <summary>Compares two numbers.
/// <para>If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed.
/// </para></summary>
/// <param name="a">Value to compare the source with</param>
/// </para>Both this method and Equals() allow the argument to be a RationalExpression, however we do not define mixed equality operators,
/// because otherwise testing for a null/non-null expression would require an awkward explicit cast on the null.
/// <para>Although this only applies to equality operators, while comparison operators could have possibly worked, we're leaving out all mixed operators for now.
/// </para>Since comparison via CompareTo() or Equals() is possible between ints and rationals, operators would just be another way to do the same thing.</summary>
/// <param name="a">Value to compare the source with. This can be an integer or rational multi-precision number or expression, or a supported primitive type (long, ulong, or double).</param>
/// <returns>A positive number if the source is greater than <paramref name="a"/>, negative if less, and zero if they are equal.</returns>
virtual int CompareTo(Object^ a) sealed;
@ -467,8 +470,11 @@ namespace MPIR
/// <summary>Compares two numbers.
/// <para>If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed.
/// </para></summary>
/// <param name="a">Value to compare the source with. This can be a multi-precision number, an expression, or a supported primitive type (long, ulong, or double).</param>
/// </para>Both this method and CompareTo() allow the argument to be a RationalExpression, however we do not define mixed equality operators,
/// because otherwise testing for a null/non-null expression would require an awkward explicit cast on the null.
/// <para>Although this only applies to equality operators, while comparison operators could have possibly worked, we're leaving out all mixed operators for now.
/// </para>Since comparison via CompareTo() or Equals() is possible between ints and rationals, operators would just be another way to do the same thing.</summary>
/// <param name="a">Value to compare the source with. This can be an integer or rational multi-precision number or expression, or a supported primitive type (long, ulong, or double).</param>
/// <returns>true if the values of the source and <paramref name="a"/> are equal, false otherwise.</returns>
virtual bool Equals(Object^ a) override sealed;
@ -939,7 +945,7 @@ namespace MPIR
MPEXPR_NAME^ NextPrimeCandidate(MpirRandom^ random);
/// <summary>Computes the greatest common divisor of this number and <paramref name="a"/>.
/// <para>The result is always positive even if one or both inputs are negative.
/// <para>The result is always positive even if one or both inputs are negative (or zero if both inputs are zero).
/// </para>As with all expressions, the result is not computed until the expression is assigned to the Value property or consumed by a method.
/// </summary>
/// <param name="a">Source value to compute the GCD with</param>
@ -1245,9 +1251,14 @@ namespace MPIR
public:
/// <summary>
/// Optionally computes and saves the coefficients <paramref name="s"/> and <paramref name="t"/> such that x*s + y*t = gcd(x, y).
/// Optionally computes and saves the coefficients <paramref name="s"/> and <paramref name="t"/> such that a<paramref name="s"/> + b<paramref name="t"/> = g = gcd(a, b).
/// <para>If only one of the coefficients is needed, use null for the other.
/// </para></summary>
/// </para>The values <paramref name="s"/> and <paramref name="t"/> are chosen such that normally, |<paramref name="s"/>| &lt; |b|/(2g) and |<paramref name="t"/>| &lt; |a|/(2g),
/// and these relations define <paramref name="s"/> and <paramref name="t"/> uniquely.
/// <para>There are a few exceptional cases:
/// </para>If |a| = |b|, then <paramref name="s"/> = 0 and <paramref name="t"/> = sgn(b).
/// <para>Otherwise, <paramref name="s"/> = sgn(a) if b = 0 or |b| = 2g, and <paramref name="t"/> = sgn(b) if a = 0 or |a| = 2g.
/// </para>In all cases, <paramref name="s"/> = 0 if and only if g = |b|, i.e., if b divides a or a = b = 0.</summary>
/// <param name="s">destination for the first coefficient. Can be null if not needed.</param>
/// <param name="t">destination for the second coefficient. Can be null if not needed.</param>
/// <returns>An updated expression, with its internal state updated to save the coefficients.</returns>

View File

@ -165,6 +165,14 @@ namespace MPIR
EvaluationContext context;
IntegerExpression^ expr2 = dynamic_cast<IntegerExpression^>(a);
if (!IS_NULL(expr2))
{
ASSIGN_TO(context);
expr2->AssignToInteger(context);
return MP(cmp_z)(CTXT(0), CTXTI(1));
}
if(a->GetType() == mpir_ui::typeid)
{
ASSIGN_TO(context);
@ -231,6 +239,14 @@ namespace MPIR
EvaluationContext context;
IntegerExpression^ expr2 = dynamic_cast<IntegerExpression^>(a);
if (!IS_NULL(expr2))
{
ASSIGN_TO(context);
expr2->AssignToRational(context);
return MP(equal)(CTXT(0), CTXT(1)) != 0;
}
if(a->GetType() == mpir_ui::typeid)
{
ASSIGN_TO(context);
@ -437,5 +453,48 @@ namespace MPIR
mpf_set_q(_value, CTXT(0));
}
int IntegerExpression::CompareTo(Object^ a, bool& valid)
{
valid = true;
if (IS_NULL(a))
return 1;
IntegerExpression^ expr = dynamic_cast<IntegerExpression^>(a);
if (!IS_NULL(expr))
return CompareTo(expr);
EvaluationContext context;
MPEXPR_NAME^ expr2 = dynamic_cast<MPEXPR_NAME^>(a);
if (!IS_NULL(expr2))
{
expr2->AssignToRational(context);
AssignToInteger(context);
return -MP(cmp_z)(CTXT(0), CTXTI(1));
}
if (a->GetType() == mpir_ui::typeid)
{
AssignToInteger(context);
return mpz_cmp_ui(CTXTI(0), (mpir_ui)a);
}
if (a->GetType() == mpir_si::typeid)
{
AssignToInteger(context);
return mpz_cmp_si(CTXTI(0), (mpir_si)a);
}
if (a->GetType() == double::typeid)
{
AssignToInteger(context);
return mpz_cmp_d(CTXTI(0), (double)a);
}
valid = false;
return 0;
}
#pragma endregion
};

View File

@ -376,8 +376,11 @@ namespace MPIR
/// <summary>Compares two numbers.
/// <para>If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed.
/// </para></summary>
/// <param name="a">Value to compare the source with</param>
/// </para>Both this method and Equals() allow the argument to be an IntegerExpression, however we do not define mixed equality operators,
/// because otherwise testing for a null/non-null expression would require an awkward explicit cast on the null.
/// <para>Although this only applies to equality operators, while comparison operators could have possibly worked, we're leaving out all mixed operators for now.
/// </para>Since comparison via CompareTo() or Equals() is possible between ints and rationals, operators would just be another way to do the same thing.</summary>
/// <param name="a">Value to compare the source with. This can be an integer or rational multi-precision number or expression, or a supported primitive type (long, ulong, or double).</param>
/// <returns>A positive number if the source is greater than <paramref name="a"/>, negative if less, and zero if they are equal.</returns>
virtual int CompareTo(Object^ a) sealed;
@ -413,8 +416,11 @@ namespace MPIR
/// <summary>Compares two numbers.
/// <para>If any argument is an expression, it is evaluated into a temporary variable before the comparison is performed.
/// </para></summary>
/// <param name="a">Value to compare the source with. This can be a multi-precision number, an expression, or a supported primitive type (long, ulong, or double).</param>
/// </para>Both this method and CompareTo() allow the argument to be an IntegerExpression, however we do not define mixed equality operators,
/// because otherwise testing for a null/non-null expression would require an awkward explicit cast on the null.
/// <para>Although this only applies to equality operators, while comparison operators could have possibly worked, we're leaving out all mixed operators for now.
/// </para>Since comparison via CompareTo() or Equals() is possible between ints and rationals, operators would just be another way to do the same thing.</summary>
/// <param name="a">Value to compare the source with. This can be an integer or rational multi-precision number or expression, or a supported primitive type (long, ulong, or double).</param>
/// <returns>true if the values of the source and <paramref name="a"/> are equal, false otherwise.</returns>
virtual bool Equals(Object^ a) override sealed;