Float IO - Read implementation. Also updated construction and assignment to make all string conversions consistent. MPIR 2.7.0 Section 7.7 Completed.

This commit is contained in:
Alex Dyachenko 2014-06-25 16:22:37 -04:00
parent 0432170047
commit d161281a47
5 changed files with 184 additions and 16 deletions

View File

@ -127,6 +127,34 @@ namespace MPIR.Tests.HugeFloatTests
} }
} }
[TestMethod]
public void FloatStringConstructorWithAlternativeExponentMarker()
{
var n = "5432109876543212345789.70515331128527330659e3";
using(var a = new HugeFloat(n))
{
FloatAssert.AreEqual("5432109876543212345789705.15331128527330659", a);
}
}
[TestMethod]
public void FloatStringConstructorWithAlternativeExponentMarker2()
{
var n = "5432109876543212345789.70515331128527330659E3";
using(var a = new HugeFloat(n))
{
FloatAssert.AreEqual("5432109876543212345789705.15331128527330659", a);
}
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void FloatStringConstructorWithAlternativeExponentMarkerInvalid()
{
var n = "5432109876543212345789.70515331128527330659e3";
var a = new HugeFloat(n, 11);
}
[TestMethod] [TestMethod]
[ExpectedException(typeof(ArgumentException))] [ExpectedException(typeof(ArgumentException))]
public void FloatStringConstructorInvalid() public void FloatStringConstructorInvalid()
@ -144,6 +172,27 @@ namespace MPIR.Tests.HugeFloatTests
} }
} }
[TestMethod]
public void FloatStringConstructorHexExponentDecimal()
{
var n = "143210ABCDEF32123457ACDB324.59879@10";
using(var a = new HugeFloat(n, 16))
{
Assert.AreEqual("0.143210ABCDEF32123457ACDB32459879@37", a.ToString(16, false, true));
}
}
[TestMethod]
public void FloatStringConstructorHexExponentInBase()
{
var n = "143210ABCDEF32123457ACDB324.59879@10";
using(var a = new HugeFloat(n, 16, false))
{
Assert.AreEqual("0.143210ABCDEF32123457ACDB32459879@2B", a.ToString(16, false, false));
Assert.AreEqual("0.143210ABCDEF32123457ACDB32459879@43", a.ToString(16, false, true));
}
}
[TestMethod] [TestMethod]
public void FloatConstructorFromExpression() public void FloatConstructorFromExpression()
{ {

View File

@ -158,6 +158,23 @@ namespace MPIR.Tests.HugeFloatTests
} }
} }
[TestMethod]
public void FloatFromStringExpDecimal()
{
using(var a = new HugeFloat())
{
var n = "0.12354523094527035843ABCDEF54@10";
a.SetTo(n, 16);
Assert.AreEqual("0.12354523094527035843ABCDEF54@10", a.ToString(16, false, true));
Assert.AreEqual("0.12354523094527035843ABCDEF54@A", a.ToString(16, false, false));
a.SetTo(n, 16, false);
Assert.AreEqual("0.12354523094527035843ABCDEF54@16", a.ToString(16, false, true));
Assert.AreEqual("0.12354523094527035843ABCDEF54@10", a.ToString(16, false, false));
}
}
[TestMethod] [TestMethod]
[ExpectedException(typeof(ArgumentException))] [ExpectedException(typeof(ArgumentException))]
public void FloatFromInvalidString() public void FloatFromInvalidString()

View File

@ -45,7 +45,7 @@ namespace MPIR.Tests.HugeFloatTests
using (var reader = new StreamReader(ms, Encoding.UTF8, false, 1024, true)) using (var reader = new StreamReader(ms, Encoding.UTF8, false, 1024, true))
b.Read(reader, 10, false); b.Read(reader, 10, false);
Assert.AreEqual(a, b); Assert.AreEqual(a.ToString(10), b.ToString(10));
Assert.AreEqual(ms.Length, ms.Position); Assert.AreEqual(ms.Length, ms.Position);
Assert.AreEqual((char)0xFEFF + a.ToString(10), Encoding.UTF8.GetString(ms.ToArray())); Assert.AreEqual((char)0xFEFF + a.ToString(10), Encoding.UTF8.GetString(ms.ToArray()));
} }
@ -137,7 +137,7 @@ namespace MPIR.Tests.HugeFloatTests
using(var reader = new StreamReader(ms, Encoding.UTF8, false, 1024, true)) using(var reader = new StreamReader(ms, Encoding.UTF8, false, 1024, true))
b.Read(reader, 62, false); b.Read(reader, 62, false);
Assert.AreEqual(a, b); Assert.AreEqual(a.ToString(62), b.ToString(62));
Assert.AreEqual(ms.Length, ms.Position); Assert.AreEqual(ms.Length, ms.Position);
Assert.AreEqual((char)0xFEFF + a.ToString(62), Encoding.UTF8.GetString(ms.ToArray())); Assert.AreEqual((char)0xFEFF + a.ToString(62), Encoding.UTF8.GetString(ms.ToArray()));
} }

View File

@ -71,14 +71,15 @@ namespace MPIR
return result; return result;
} }
void MPTYPE::FromString(String^ value, int base) void MPTYPE::FromString(String^ value, int base, bool exponentInDecimal)
{ {
AllocateStruct(); AllocateStruct();
MP(init)(_value); MP(init)(_value);
_allocatedPrecision = MP(get_prec)(_value); _allocatedPrecision = MP(get_prec)(_value);
base = Math::Abs(base);
IntPtr ptr = Marshal::StringToHGlobalAnsi(value); IntPtr ptr = Marshal::StringToHGlobalAnsi(value);
bool success = 0 == MP(set_str)(_value, (char*)(void*)ptr, base); bool success = 0 == MP(set_str)(_value, (char*)(void*)ptr, exponentInDecimal ? -base : base);
Marshal::FreeHGlobal(ptr); Marshal::FreeHGlobal(ptr);
if(!success) if(!success)
@ -88,10 +89,11 @@ namespace MPIR
} }
} }
void MPTYPE::SetTo(String^ value, int base) void MPTYPE::SetTo(String^ value, int base, bool exponentInDecimal)
{ {
base = Math::Abs(base);
IntPtr ptr = Marshal::StringToHGlobalAnsi(value); IntPtr ptr = Marshal::StringToHGlobalAnsi(value);
bool success = 0 == MP(set_str)(_value, (char*)(void*)ptr, base); bool success = 0 == MP(set_str)(_value, (char*)(void*)ptr, exponentInDecimal ? -base : base);
Marshal::FreeHGlobal(ptr); Marshal::FreeHGlobal(ptr);
if(!success) if(!success)
@ -339,7 +341,82 @@ namespace MPIR
size_t MPTYPE::Read(TextReader^ reader, int base, bool exponentInDecimal) size_t MPTYPE::Read(TextReader^ reader, int base, bool exponentInDecimal)
{ {
throw gcnew NotImplementedException(); StringBuilder str;
int c;
size_t nread = 0;
const unsigned char* digit_value = __gmp_digit_value_tab;
bool hasDecimal = false;
bool inExponent = false;
if (base < 2)
throw gcnew ArgumentException("Invalid base", "base");
if (base > 36)
{
// For bases > 36, use the collating sequence
// 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
digit_value += 224;
if (base > 62)
throw gcnew ArgumentException("Invalid base", "base");
}
// Skip whitespace
while ((c = reader->Peek()) >= 0 && Char::IsWhiteSpace(c))
{
nread++;
reader->Read();
}
// possibly negative
if (c == '-')
{
str.Append((wchar_t)c);
PEEK_NEXT_CHAR;
}
while (c != EOF)
{
if (c == '.')
{
if (hasDecimal) break;
hasDecimal = true;
str.Append((wchar_t)c);
PEEK_NEXT_CHAR;
continue;
}
if ((base <= 10 && Char::ToLower(c) == 'e') || c == '@')
{
if (inExponent) break;
inExponent = true;
str.Append((wchar_t)c);
PEEK_NEXT_CHAR;
// possibly negative
if (c == '-')
{
str.Append((wchar_t)c);
PEEK_NEXT_CHAR;
}
continue;
}
if (inExponent && exponentInDecimal && !Char::IsDigit(c))
break;
int dig = digit_value[c];
if (dig >= base)
break;
str.Append((wchar_t)c);
PEEK_NEXT_CHAR;
}
SetTo(str.ToString(), base, exponentInDecimal);
return str.Length + nread;
} }
#pragma endregion #pragma endregion

View File

@ -761,7 +761,7 @@ namespace MPIR
{ {
_value = (MP(ptr))((*__gmp_allocate_func)(sizeof(MPSTRUCT))); _value = (MP(ptr))((*__gmp_allocate_func)(sizeof(MPSTRUCT)));
} }
void FromString(String^ value, int base); void FromString(String^ value, int base, bool exponentInDecimal);
MPTYPE(bool initialize); MPTYPE(bool initialize);
String^ ToString(int base, bool lowercase, int maxDigits, bool exponentInDecimal); String^ ToString(int base, bool lowercase, int maxDigits, bool exponentInDecimal);
@ -820,21 +820,33 @@ namespace MPIR
static MPTYPE^ Allocate(mp_bitcnt_t precision); static MPTYPE^ Allocate(mp_bitcnt_t precision);
/// <summary> /// <summary>
/// Initializes a new float instance and sets its value from the specified string, using leading characters to recognize the base: /// Initializes a new float instance and sets its value from the specified string.
/// 0x and 0X for hexadecimal, 0b and 0B for binary, 0 for octal, or decimal otherwise. /// <para>No leading base characters are allowed.
/// </para>The exponent is always in decimal.
/// </summary> /// </summary>
/// <param name="value">string representing the initial value for the new instance. Whitespace in the string is ignored.</param> /// <param name="value">string representing the initial value for the new instance. Whitespace in the string is ignored.</param>
MPTYPE(String^ value) { FromString(value, 0); } MPTYPE(String^ value) { FromString(value, 0, true); }
/// <summary> /// <summary>
/// Initializes a new float instance and sets its value from the specified string /// Initializes a new float instance and sets its value from the specified string
/// </summary> /// </summary>
/// <param name="value">string representing the initial value for the new instance. Whitespace in the string is ignored.</param> /// <param name="value">string representing the initial value for the new instance. Whitespace in the string is ignored.</param>
/// <param name="base">base the <paramref name="value"/> string is in. /// <param name="base">base the <paramref name="value"/> string is in.
/// <para>The base may vary from 2 to 62, or if base is 0, then the leading characters are used: 0x and 0X for hexadecimal, 0b and 0B for binary, 0 for octal, or decimal otherwise. /// <para>The base may vary from 2 to 62. No leading base characters are allowed. The exponent is always in decimal
/// </para>For bases up to 36, case is ignored; upper-case and lower-case letters have the same value. /// </para>For bases up to 36, case is ignored; upper-case and lower-case letters have the same value.
/// For bases 37 to 62, upper-case letter represent the usual 10..35 while lower-case letter represent 36..61.</param> /// For bases 37 to 62, upper-case letter represent the usual 10..35 while lower-case letter represent 36..61.</param>
MPTYPE(String^ value, int base) { FromString(value, base); } MPTYPE(String^ value, int base) { FromString(value, base, true); }
/// <summary>
/// Initializes a new float instance and sets its value from the specified string
/// </summary>
/// <param name="value">string representing the initial value for the new instance. Whitespace in the string is ignored.</param>
/// <param name="base">base the <paramref name="value"/> string is in.
/// <para>The base may vary from 2 to 62. No leading base characters are allowed.
/// </para>For bases up to 36, case is ignored; upper-case and lower-case letters have the same value.
/// For bases 37 to 62, upper-case letter represent the usual 10..35 while lower-case letter represent 36..61.</param>
/// <param name="exponentInDecimal">True if the exponent is in decimal, false to use the same base as the mantissa.</param>
MPTYPE(String^ value, int base, bool exponentInDecimal) { FromString(value, base, exponentInDecimal); }
/// <summary> /// <summary>
/// Initializes a new float instance and sets its value to the result of computing the source expression. /// Initializes a new float instance and sets its value to the result of computing the source expression.
@ -1049,11 +1061,24 @@ namespace MPIR
/// </para>If the fraction is not in canonical form, Canonicalize() must be called. /// </para>If the fraction is not in canonical form, Canonicalize() must be called.
/// </summary> /// </summary>
/// <param name="value">new value for the object</param> /// <param name="value">new value for the object</param>
/// <param name="base">base the <paramref name="value"/> string is in. /// <param name="base">base the mantissa in the <paramref name="value"/> string is in. Exponent is always in decimcal.
/// <para>The base may vary from 2 to 62, or if base is 0, then the leading characters are used: 0x and 0X for hexadecimal, 0b and 0B for binary, 0 for octal, or decimal otherwise. /// <para>The base may vary from 2 to 62. No leading leading base characters are allowed.
/// </para>For bases up to 36, case is ignored; upper-case and lower-case letters have the same value. /// </para>For bases up to 36, case is ignored; upper-case and lower-case letters have the same value.
/// For bases 37 to 62, upper-case letter represent the usual 10..35 while lower-case letter represent 36..61.</param> /// For bases 37 to 62, upper-case letter represent the usual 10..35 while lower-case letter represent 36..61.</param>
void SetTo(String^ value, int base); void SetTo(String^ value, int base) { SetTo(value, base, true); }
/// <summary>
/// Sets the value of the float object.
/// <para>Do not change the value of an object while it is contained in a hash table, because that changes its hash code.
/// </para>If the fraction is not in canonical form, Canonicalize() must be called.
/// </summary>
/// <param name="value">new value for the object</param>
/// <param name="base">base the <paramref name="value"/> string is in.
/// <para>The base may vary from 2 to 62. No leading leading base characters are allowed.
/// </para>For bases up to 36, case is ignored; upper-case and lower-case letters have the same value.
/// For bases 37 to 62, upper-case letter represent the usual 10..35 while lower-case letter represent 36..61.</param>
/// <param name="exponentInDecimal">If true, the exponent is in decimal; otherwise it is in the same base as the mantissa</param>
void SetTo(String^ value, int base, bool exponentInDecimal);
/// <summary> /// <summary>
/// Sets the value of the float object. /// Sets the value of the float object.