Float size checks and ToDouble(out exp). Apparently duplicate work, committing before merging from remote.

This commit is contained in:
Alex Dyachenko 2015-05-21 21:39:47 -04:00
parent 4770c42686
commit 5ef1d11323
3 changed files with 267 additions and 41 deletions

View File

@ -83,6 +83,22 @@ namespace MPIR.Tests.HugeFloatTests
}
}
[TestMethod]
public void FloatToAndFromDouble2()
{
using (var a = new HugeFloat())
{
a.SetTo(-123.25);
long exp;
double c = a.ToDouble(out exp);
Assert.IsTrue(c.Equals(-0.962890625));
Assert.AreEqual(7L, exp);
Assert.IsTrue(a.Equals(-123.25));
Assert.AreEqual("-0.12325@3", a.ToString());
}
}
[TestMethod]
public void FloatToAndFromFloat()
{
@ -97,6 +113,73 @@ namespace MPIR.Tests.HugeFloatTests
}
}
[TestMethod]
public void FloatToAndFromUlong()
{
using (var a = new HugeFloat())
{
ulong b = 0xF84739ABCDEF4876;
a.SetTo(b);
a.Value = -a;
ulong c = a.ToUlong();
Assert.AreEqual(b, c);
}
}
[TestMethod]
public void FloatToAndFromLong()
{
using (var a = new HugeFloat())
{
long b = -0x784739ABCDEF4876;
a.SetTo(b);
long c = a.ToLong();
Assert.AreEqual(b, c);
}
}
[TestMethod]
public void FloatToUlong2()
{
using (var a = new HugeFloat())
using (var small = new HugeFloat(0.0001))
{
ulong b = ulong.MaxValue;
a.SetTo(b);
a.Value = a + 1 - small;
var c = a.ToUlong();
Assert.AreEqual(b, c);
a.Value = -1 + small;
c = a.ToUlong();
Assert.AreEqual(0UL, c);
}
}
[TestMethod]
public void FloatToLong2()
{
using (var a = new HugeFloat())
using (var small = new HugeFloat(0.0001))
{
long b = long.MaxValue;
a.SetTo(b);
a.Value = a + 1 - small;
var c = a.ToLong();
Assert.AreEqual(b, c);
b = long.MinValue;
a.SetTo(b);
a.Value -= 1 - small;
c = a.ToLong();
Assert.AreEqual(b, c);
}
}
[TestMethod]
public void FloatFromString()
{
@ -136,6 +219,126 @@ namespace MPIR.Tests.HugeFloatTests
}
}
[TestMethod]
public void FloatFitsUlong()
{
using (var a = new HugeFloat(ulong.MaxValue))
using (var small = new HugeFloat(0.0001))
{
Assert.IsTrue(a.FitsUlong());
a.Value = a + 1;
Assert.IsFalse(a.FitsUlong());
a.Value = a - small;
Assert.IsTrue(a.FitsUlong());
a.SetTo(0);
Assert.IsTrue(a.FitsUlong());
a.Value = a - 1;
Assert.IsFalse(a.FitsUlong());
a.Value = a + small;
Assert.IsTrue(a.FitsUlong());
}
}
[TestMethod]
public void FloatFitsLong()
{
using (var a = new HugeFloat(long.MaxValue))
using (var small = new HugeFloat(0.0001))
{
Assert.IsTrue(a.FitsLong());
a.Value = a + 1;
Assert.IsFalse(a.FitsLong());
a.Value = a - small;
Assert.IsTrue(a.FitsLong());
a.SetTo(long.MinValue);
Assert.IsTrue(a.FitsLong());
a.Value = a - 1;
Assert.IsFalse(a.FitsLong());
a.Value = a + small;
Assert.IsTrue(a.FitsLong());
}
}
[TestMethod]
public void FloatFitsUint()
{
using (var a = new HugeFloat(uint.MaxValue))
using (var small = new HugeFloat(0.0001))
{
Assert.IsTrue(a.FitsUint());
a.Value = a + 1;
Assert.IsFalse(a.FitsUint());
a.Value = a - small;
Assert.IsTrue(a.FitsUint());
a.SetTo(0);
Assert.IsTrue(a.FitsUint());
a.Value = a - 1;
Assert.IsFalse(a.FitsUint());
a.Value = a + small;
Assert.IsTrue(a.FitsUint());
}
}
[TestMethod]
public void FloatFitsInt()
{
using (var a = new HugeFloat(int.MaxValue))
using (var small = new HugeFloat(0.0001))
{
Assert.IsTrue(a.FitsInt());
a.Value = a + 1;
Assert.IsFalse(a.FitsInt());
a.Value = a - small;
Assert.IsTrue(a.FitsInt());
a.SetTo(int.MinValue);
Assert.IsTrue(a.FitsInt());
a.Value = a - 1;
Assert.IsFalse(a.FitsInt());
a.Value = a + small;
Assert.IsTrue(a.FitsInt());
}
}
[TestMethod]
public void FloatFitsUshort()
{
using (var a = new HugeFloat(ushort.MaxValue))
using (var small = new HugeFloat(0.0001))
{
Assert.IsTrue(a.FitsUshort());
a.Value = a + 1;
Assert.IsFalse(a.FitsUshort());
a.Value = a - small;
Assert.IsTrue(a.FitsUshort());
a.SetTo(0);
Assert.IsTrue(a.FitsUshort());
a.Value = a - 1;
Assert.IsFalse(a.FitsUshort());
a.Value = a + small;
Assert.IsTrue(a.FitsUshort());
}
}
[TestMethod]
public void FloatFitsShort()
{
using (var a = new HugeFloat(short.MaxValue))
using (var small = new HugeFloat(0.0001))
{
Assert.IsTrue(a.FitsShort());
a.Value = a + 1;
Assert.IsFalse(a.FitsShort());
a.Value = a - small;
Assert.IsTrue(a.FitsShort());
a.SetTo(short.MinValue);
Assert.IsTrue(a.FitsShort());
a.Value = a - 1;
Assert.IsFalse(a.FitsShort());
a.Value = a + small;
Assert.IsTrue(a.FitsShort());
}
}
//private void AssertBetween(int min, int max, long actual)
//{
// Assert.IsTrue(actual >= min && actual <= max, "Expected {0} to {1}, actual {2}", min, max, actual);

View File

@ -891,21 +891,21 @@ namespace MPIR
/// <returns>A string representation of the number in the specified base.</returns>
String^ ToString(int base, bool lowercase) { return ToString(base, lowercase, 0); }
///// <summary>
///// Returns the absolute value of the number as a ulong.
///// <para>If the number is too big, then just the least significant bits that do fit are returned.
///// </para>The sign of the number is ignored, only the absolute value is used.
///// </summary>
///// <returns>The absolute value as a ulong, possibly truncated to the least significant bits only.</returns>
//mpir_ui ToUlong() { return MP(get_ui)(_value); }
/// <summary>
/// Returns the absolute value of the number as a ulong, truncating any fractional part.
/// <para>If the number is too big, the result is undefined. Call FitsUlong() to check if the number will fit.
/// </para>The sign of the number is ignored, only the absolute value is used.
/// </summary>
/// <returns>The absolute value as a ulong, with any fractional part truncated.</returns>
mpir_ui ToUlong() { return MP(get_ui)(_value); }
///// <summary>
///// Returns the value of the number as a long.
///// <para>If the number is too big, then just the least significant bits that do fit are returned, with the same sign as the number.
///// </para>When truncation occurs, the result is propobly not very useful. Call FitsLong() to check if the number will fit.
///// </summary>
///// <returns>The value as a ulong, possibly truncated to the least significant bits only.</returns>
//mpir_si ToLong() { return MP(get_si)(_value); }
/// <summary>
/// Returns the value of the number as a long.
/// <para>If the number is too big, the result is undefined. Call FitsLong() to check if the number will fit.
/// </para>
/// </summary>
/// <returns>The value as a long, possibly truncated to the least significant bits only.</returns>
mpir_si ToLong() { return MP(get_si)(_value); }
/// <summary>
/// Returns the value of the number as a double, truncating if necessary (rounding towards zero).
@ -914,19 +914,20 @@ namespace MPIR
/// <returns>The value as a double, possibly truncated.</returns>
double ToDouble() { return MP(get_d)(_value); }
///// <summary>
///// Returns the value of the number as a double, truncating if necessary (rounding towards zero), and returning the exponent separately.
///// <para>The return is the mantissa, its absolute value will be in the range [0.5 - 1). ///// </para>If the source value is zero, both mantissa and exponent are returned as 0.
///// </summary>
///// <param name="exp">variable to store the exponent in.</param>
///// <returns>The mantissa of the value as a double, possibly truncated.</returns>
//double ToDouble([Out] mpir_si% exp)
//{
// mpir_si x;
// auto result = MP(get_d_2exp)(&x, _value);
// exp = x;
// return result;
//}
/// <summary>
/// Returns the value of the number as a double, truncating if necessary (rounding towards zero), and returning the exponent separately.
/// <para>The return is the mantissa, its absolute value will be in the range [0.5 - 1). /// </para>The exponent is binary, i.e. mantissa * 2^exp is the value of the source number.
/// <para>If the source value is zero, both mantissa and exponent are returned as 0.
/// </para></summary>
/// <param name="exp">variable to store the exponent in.</param>
/// <returns>The mantissa of the value as a double, possibly truncated.</returns>
double ToDouble([Out] mpir_si% exp)
{
mpir_si x;
auto result = MP(get_d_2exp)(&x, _value);
exp = x;
return result;
}
#pragma endregion
@ -1045,19 +1046,41 @@ namespace MPIR
#pragma region Size checks
///// <summary>
///// Returns the number of digits the number would take if written in the specified base.
///// <para>The sign of the number is ignored, just the absolute value is used.
///// </para>The result will be either exact or at most 2 characters too big.
///// If <paramref name="base"/> is a power of 2, the result will always be exact.
///// <para>If the number is 0, the result is always 3.
///// </para>This function can be used to estimate the space required when converting to a string.
///// The right amount of allocation is normally two more than the value returned,
///// one extra for a minus sign and one for the null-terminator.
///// <para>A slash between numerator and denominator is accounted for.</para></summary>
///// <param name="base">Numeric base for the would-be string conversion, in the range from 2 to 62.</param>
///// <returns>The number of digits the number would take written in the specified base, possibly 1 or 2 too big, not counting a leading minus.</returns>
//mp_size_t ApproximateSizeInBase(int base) { return mpz_sizeinbase(&_value->_mp_num, base) + mpz_sizeinbase(&_value->_mp_den, base) + 1; }
/// <summary>
/// Returns true if the value of the float, when truncated to an integer, is in the ulong range.
/// </summary>
/// <returns>true if the value will fit in a ulong</returns>
bool FitsUlong() { return MP(fits_ui_p)(_value) != 0; }
/// <summary>
/// Returns true if the value of the float, when truncated to an integer, is in the long range.
/// </summary>
/// <returns>true if the value will fit in a long</returns>
bool FitsLong() { return MP(fits_si_p)(_value) != 0; }
/// <summary>
/// Returns true if the value of the float, when truncated to an integer, is in the uint range.
/// </summary>
/// <returns>true if the value will fit in a uint</returns>
bool FitsUint() { return MP(fits_uint_p)(_value) != 0; }
/// <summary>
/// Returns true if the value of the float, when truncated to an integer, is in the int range.
/// </summary>
/// <returns>true if the value will fit in a int</returns>
bool FitsInt() { return MP(fits_sint_p)(_value) != 0; }
/// <summary>
/// Returns true if the value of the float, when truncated to an integer, is in the ushort range.
/// </summary>
/// <returns>true if the value will fit in a ushort</returns>
bool FitsUshort() { return MP(fits_ushort_p)(_value) != 0; }
/// <summary>
/// Returns true if the value of the float, when truncated to an integer, is in the short range.
/// </summary>
/// <returns>true if the value will fit in a short</returns>
bool FitsShort() { return MP(fits_sshort_p)(_value) != 0; }
#pragma endregion

View File

@ -1541,7 +1541,7 @@ namespace MPIR
/// <para>If the number is too big, then just the least significant bits that do fit are returned, with the same sign as the number.
/// </para>When truncation occurs, the result is propobly not very useful. Call FitsLong() to check if the number will fit.
/// </summary>
/// <returns>The value as a ulong, possibly truncated to the least significant bits only.</returns>
/// <returns>The value as a long, possibly truncated to the least significant bits only.</returns>
mpir_si ToLong() { return MP(get_si)(_value); }
/// <summary>