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:
parent
0432170047
commit
d161281a47
@ -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()
|
||||||
{
|
{
|
||||||
|
@ -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()
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user