2017-11-04 16:02:37 +01:00
using System ;
using System.Runtime.InteropServices ;
using System.Diagnostics ;
namespace Math.Gmp.Native
{
/// <summary>
/// Represents a multiple precision floating-point number.
/// </summary>
/// <remarks>
/// <para>
2017-12-15 02:18:55 +01:00
/// The floating point functions accept and return exponents in the C type <see cref="mp_exp_t">mp_exp_t</see>.
2017-11-04 16:02:37 +01:00
/// Currently this is usually a long, but on some systems it’ s an int for efficiency.
/// </para>
/// <para>
/// In .NET, this is a 32-bit integer.
/// </para>
/// </remarks>
2017-12-15 02:18:55 +01:00
/// <seealso cref="mp_exp_t">mp_exp_t</seealso>
/// <seealso cref="mp_limb_t">mp_limb_t</seealso>
/// <seealso cref="mpq_t">mpq_t</seealso>
/// <seealso cref="mpz_t">mpz_t</seealso>
2017-11-04 16:02:37 +01:00
public class mpf_t : mp_base
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
2017-12-03 23:32:51 +01:00
private bool _initialized = false ;
2017-11-04 16:02:37 +01:00
2017-12-03 23:32:51 +01:00
internal void Initializing ( )
2017-11-04 16:02:37 +01:00
{
size_t length = /*sizeof(int) + sizeof(int) + sizeof(int)*/ 12 U + ( size_t ) IntPtr . Size ;
2017-12-03 23:32:51 +01:00
Pointer = gmp_lib . allocate ( length ) . ToIntPtr ( ) ;
//gmp_lib.ZeroMemory(Pointer, (int)length);
}
internal void Initialized ( )
{
//gmp_lib.ZeroMemory(Pointer, (int)length);
_initialized = true ;
}
internal void Clear ( )
{
if ( _initialized ) gmp_lib . free ( Pointer ) ;
Pointer = IntPtr . Zero ;
_initialized = false ;
2017-11-04 16:02:37 +01:00
}
/// <summary>
/// The number of limbs currently in use, or the negative of that when representing a negative value.
/// </summary>
/// <remarks>
/// <para>
2017-12-15 02:18:55 +01:00
/// Zero is represented by <see cref="_mp_size">_mp_size</see> and <see cref="_mp_exp">_mp_exp</see> both set to zero,
/// and in that case the <see cref="mp_base._mp_d">mp_base._mp_d</see> data is unused.
/// (In the future <see cref="_mp_exp">_mp_exp</see> might be undefined when representing zero.)
2017-11-04 16:02:37 +01:00
/// </para>
/// </remarks>
public override mp_size_t _mp_size
{
get
{
2017-12-03 23:32:51 +01:00
return Marshal . ReadInt32 ( Pointer , /*sizeof(int)*/ 4 ) ;
2017-11-04 16:02:37 +01:00
}
}
/// <summary>
/// The precision of the mantissa, in limbs.
/// </summary>
/// <remarks>
/// <para>
2017-12-15 02:18:55 +01:00
/// In any calculation the aim is to produce <see cref="_mp_prec">_mp_prec</see> limbs of result (the most significant being non-zero).
2017-11-04 16:02:37 +01:00
/// </para>
/// </remarks>
public int _mp_prec
{
get
{
2017-12-03 23:32:51 +01:00
return Marshal . ReadInt32 ( Pointer , 0 ) ;
2017-11-04 16:02:37 +01:00
}
}
/// <summary>
/// The exponent, in limbs, determining the location of the implied radix point.
/// </summary>
/// <remarks>
/// <para>
/// Zero means the radix point is just above the most significant limb.
/// Positive values mean a radix point offset towards the lower limbs and hence a value ≥ 1, as for example in the diagram above.
/// Negative exponents mean a radix point further above the highest limb.
/// </para>
/// <para>
/// Naturally the exponent can be any value, it doesn’ t have to fall within the limbs as the diagram shows,
/// it can be a long way above or a long way below.
2017-12-15 02:18:55 +01:00
/// Limbs other than those included in the {<see cref="mp_base._mp_d">mp_base._mp_d</see>, <see cref="_mp_size">_mp_size</see>} data are treated as zero.
2017-11-04 16:02:37 +01:00
/// </para>
/// </remarks>
public int _mp_exp
{
get
{
2017-12-03 23:32:51 +01:00
return Marshal . ReadInt32 ( Pointer , /*sizeof(int) + sizeof(int)*/ 8 ) ;
2017-11-04 16:02:37 +01:00
}
}
2017-12-03 23:32:51 +01:00
/// <summary>
/// Gets or sets the pointer to the significand array of limbs of the floating-point number.
/// </summary>
2017-11-04 16:02:37 +01:00
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
2017-12-03 23:32:51 +01:00
public override IntPtr _mp_d_intptr
2017-11-04 16:02:37 +01:00
{
get
{
2017-12-03 23:32:51 +01:00
return Marshal . ReadIntPtr ( Pointer , /*sizeof(int) + sizeof(int) + sizeof(int)*/ 12 ) ;
2017-11-04 16:02:37 +01:00
}
set
{
2017-12-03 23:32:51 +01:00
Marshal . WriteIntPtr ( Pointer , /*sizeof(int) + sizeof(int) + sizeof(int)*/ 12 , value ) ;
2017-11-04 16:02:37 +01:00
}
}
/// <summary>
/// Gets the unmanaged memory pointer of the multiple precision floating-point number.
/// </summary>
/// <returns>The unmanaged memory pointer of the multiple precision floating-point number.</returns>
public IntPtr ToIntPtr ( )
{
2017-12-03 23:32:51 +01:00
return Pointer ;
2017-11-04 16:02:37 +01:00
}
/// <summary>
2017-12-15 02:18:55 +01:00
/// Converts a <see cref="string">string</see> value to an <see cref="mpf_t">mpf_t</see> value.
2017-11-04 16:02:37 +01:00
/// </summary>
2017-12-15 02:18:55 +01:00
/// <param name="value">A <see cref="string">string</see> value.</param>
/// <returns>An <see cref="mpf_t">mpf_t</see> value.</returns>
2017-11-04 16:02:37 +01:00
/// <remarks>
/// <para>
/// Base is assumed to be 10 unless the first character of the string is <c>B</c>
/// followed by the base <c>2</c> to <c>62</c> or <c>-62</c> to <c>-2</c> followed
/// by a space and then the floating-point number.
/// Negative values are used to specify that the exponent is in decimal.
/// </para>
/// </remarks>
public static implicit operator mpf_t ( string value )
{
int @base = 10 ;
mpf_t x = new mpf_t ( ) ;
gmp_lib . mpf_init ( x ) ;
if ( value ! = null & & value . Substring ( 0 , 1 ) . ToUpperInvariant ( ) = = "B" )
{
int pos = value . IndexOf ( ' ' , 1 ) ;
if ( pos ! = - 1 & & int . TryParse ( value . Substring ( 1 , pos - 1 ) , out @base ) = = true )
value = value . Substring ( pos + 1 ) ;
}
char_ptr s = new char_ptr ( value ) ;
gmp_lib . mpf_set_str ( x , s , @base ) ;
gmp_lib . free ( s ) ;
return x ;
}
/// <summary>
/// Return the string representation of the float.
/// </summary>
/// <returns>The string representation of the float.</returns>
public override string ToString ( )
{
if ( ! _initialized ) return null ;
ptr < mp_exp_t > exp = new ptr < mp_exp_t > ( 0 ) ;
char_ptr s_ptr = gmp_lib . mpf_get_str ( char_ptr . Zero , exp , 10 , 0 , this ) ;
string s = s_ptr . ToString ( ) ;
gmp_lib . free ( s_ptr ) ;
if ( s . StartsWith ( "-" , StringComparison . Ordinal ) )
2017-12-03 23:32:51 +01:00
return "-0." + s . Substring ( 1 ) + "e" + exp . Value . Value . ToString ( System . Globalization . CultureInfo . InvariantCulture ) ;
2017-11-04 16:02:37 +01:00
else
2017-12-03 23:32:51 +01:00
return "0." + s + "e" + exp . Value . Value . ToString ( System . Globalization . CultureInfo . InvariantCulture ) ;
2017-11-04 16:02:37 +01:00
}
}
}