diff --git a/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs b/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs
index 981da817..f539e961 100644
--- a/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs
+++ b/mpir.net/mpir.net-tests/HugeFloatTests/ConstructionAndDisposal.cs
@@ -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]
[ExpectedException(typeof(ArgumentException))]
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]
public void FloatConstructorFromExpression()
{
diff --git a/mpir.net/mpir.net-tests/HugeFloatTests/Conversions.cs b/mpir.net/mpir.net-tests/HugeFloatTests/Conversions.cs
index 308afe8e..fdbd41a8 100644
--- a/mpir.net/mpir.net-tests/HugeFloatTests/Conversions.cs
+++ b/mpir.net/mpir.net-tests/HugeFloatTests/Conversions.cs
@@ -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]
[ExpectedException(typeof(ArgumentException))]
public void FloatFromInvalidString()
diff --git a/mpir.net/mpir.net-tests/HugeFloatTests/IO.cs b/mpir.net/mpir.net-tests/HugeFloatTests/IO.cs
index f595ee82..c803a22a 100644
--- a/mpir.net/mpir.net-tests/HugeFloatTests/IO.cs
+++ b/mpir.net/mpir.net-tests/HugeFloatTests/IO.cs
@@ -45,7 +45,7 @@ namespace MPIR.Tests.HugeFloatTests
using (var reader = new StreamReader(ms, Encoding.UTF8, false, 1024, true))
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((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))
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((char)0xFEFF + a.ToString(62), Encoding.UTF8.GetString(ms.ToArray()));
}
diff --git a/mpir.net/mpir.net/HugeFloat.cpp b/mpir.net/mpir.net/HugeFloat.cpp
index 24a30cef..4fcb2828 100644
--- a/mpir.net/mpir.net/HugeFloat.cpp
+++ b/mpir.net/mpir.net/HugeFloat.cpp
@@ -71,14 +71,15 @@ namespace MPIR
return result;
}
- void MPTYPE::FromString(String^ value, int base)
+ void MPTYPE::FromString(String^ value, int base, bool exponentInDecimal)
{
AllocateStruct();
MP(init)(_value);
_allocatedPrecision = MP(get_prec)(_value);
+ base = Math::Abs(base);
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);
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);
- 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);
if(!success)
@@ -339,7 +341,82 @@ namespace MPIR
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
diff --git a/mpir.net/mpir.net/HugeFloat.h b/mpir.net/mpir.net/HugeFloat.h
index d4878917..b1832142 100644
--- a/mpir.net/mpir.net/HugeFloat.h
+++ b/mpir.net/mpir.net/HugeFloat.h
@@ -761,7 +761,7 @@ namespace MPIR
{
_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);
String^ ToString(int base, bool lowercase, int maxDigits, bool exponentInDecimal);
@@ -820,21 +820,33 @@ namespace MPIR
static MPTYPE^ Allocate(mp_bitcnt_t precision);
///
- /// Initializes a new float instance and sets its value from the specified string, using leading characters to recognize the base:
- /// 0x and 0X for hexadecimal, 0b and 0B for binary, 0 for octal, or decimal otherwise.
+ /// Initializes a new float instance and sets its value from the specified string.
+ /// No leading base characters are allowed.
+ /// The exponent is always in decimal.
///
/// string representing the initial value for the new instance. Whitespace in the string is ignored.
- MPTYPE(String^ value) { FromString(value, 0); }
+ MPTYPE(String^ value) { FromString(value, 0, true); }
///
/// Initializes a new float instance and sets its value from the specified string
///
/// string representing the initial value for the new instance. Whitespace in the string is ignored.
/// base the string is in.
- /// 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.
+ /// The base may vary from 2 to 62. No leading base characters are allowed. The exponent is always in decimal
/// 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.
- MPTYPE(String^ value, int base) { FromString(value, base); }
+ MPTYPE(String^ value, int base) { FromString(value, base, true); }
+
+ ///
+ /// Initializes a new float instance and sets its value from the specified string
+ ///
+ /// string representing the initial value for the new instance. Whitespace in the string is ignored.
+ /// base the string is in.
+ /// The base may vary from 2 to 62. No leading base characters are allowed.
+ /// 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.
+ /// True if the exponent is in decimal, false to use the same base as the mantissa.
+ MPTYPE(String^ value, int base, bool exponentInDecimal) { FromString(value, base, exponentInDecimal); }
///
/// Initializes a new float instance and sets its value to the result of computing the source expression.
@@ -1049,11 +1061,24 @@ namespace MPIR
/// If the fraction is not in canonical form, Canonicalize() must be called.
///
/// new value for the object
- /// base the string is in.
- /// 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.
+ /// base the mantissa in the string is in. Exponent is always in decimcal.
+ /// The base may vary from 2 to 62. No leading leading base characters are allowed.
/// 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.
- void SetTo(String^ value, int base);
+ void SetTo(String^ value, int base) { SetTo(value, base, true); }
+
+ ///
+ /// Sets the value of the float object.
+ /// Do not change the value of an object while it is contained in a hash table, because that changes its hash code.
+ /// If the fraction is not in canonical form, Canonicalize() must be called.
+ ///
+ /// new value for the object
+ /// base the string is in.
+ /// The base may vary from 2 to 62. No leading leading base characters are allowed.
+ /// 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.
+ /// If true, the exponent is in decimal; otherwise it is in the same base as the mantissa
+ void SetTo(String^ value, int base, bool exponentInDecimal);
///
/// Sets the value of the float object.