Math.Gmp.Native/Math.Gmp.Native/mpf_t.cs

182 lines
6.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Math.Gmp.Native
{
/// <summary>
/// Represents a multiple precision floating-point number.
/// </summary>
/// <remarks>
/// <para>
/// The floating point functions accept and return exponents in the C type <see cref="mp_exp_t"/>.
/// Currently this is usually a long, but on some systems its an int for efficiency.
/// </para>
/// <para>
/// In .NET, this is a 32-bit integer.
/// </para>
/// </remarks>
/// <seealso cref="mp_exp_t"/>
/// <seealso cref="mp_limb_t"/>
/// <seealso cref="mpq_t"/>
/// <seealso cref="mpz_t"/>
public class mpf_t : mp_base
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool _initialized = false;
internal void Initializing()
{
size_t length = /*sizeof(int) + sizeof(int) + sizeof(int)*/ 12U + (size_t)IntPtr.Size;
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;
}
/// <summary>
/// The number of limbs currently in use, or the negative of that when representing a negative value.
/// </summary>
/// <remarks>
/// <para>
/// Zero is represented by <see cref="_mp_size"/> and <see cref="_mp_exp"/> both set to zero,
/// and in that case the <see cref="mp_base._mp_d"/> data is unused.
/// (In the future <see cref="_mp_exp"/> might be undefined when representing zero.)
/// </para>
/// </remarks>
public override mp_size_t _mp_size
{
get
{
return Marshal.ReadInt32(Pointer, /*sizeof(int)*/ 4);
}
}
/// <summary>
/// The precision of the mantissa, in limbs.
/// </summary>
/// <remarks>
/// <para>
/// In any calculation the aim is to produce <see cref="_mp_prec"/> limbs of result (the most significant being non-zero).
/// </para>
/// </remarks>
public int _mp_prec
{
get
{
return Marshal.ReadInt32(Pointer, 0);
}
}
/// <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 &#8805; 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 doesnt have to fall within the limbs as the diagram shows,
/// it can be a long way above or a long way below.
/// Limbs other than those included in the {<see cref="mp_base._mp_d"/>, <see cref="_mp_size"/>} data are treated as zero.
/// </para>
/// </remarks>
public int _mp_exp
{
get
{
return Marshal.ReadInt32(Pointer, /*sizeof(int) + sizeof(int)*/ 8);
}
}
/// <summary>
/// Gets or sets the pointer to the significand array of limbs of the floating-point number.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public override IntPtr _mp_d_intptr
{
get
{
return Marshal.ReadIntPtr(Pointer, /*sizeof(int) + sizeof(int) + sizeof(int)*/ 12);
}
set
{
Marshal.WriteIntPtr(Pointer, /*sizeof(int) + sizeof(int) + sizeof(int)*/ 12, value);
}
}
/// <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()
{
return Pointer;
}
/// <summary>
/// Converts a <see cref="string"/> value to an <see cref="mpf_t"/> value.
/// </summary>
/// <param name="value">A <see cref="string"/> value.</param>
/// <returns>An <see cref="mpf_t"/> value.</returns>
/// <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))
return "-0." + s.Substring(1) + "e" + exp.Value.Value.ToString(System.Globalization.CultureInfo.InvariantCulture);
else
return "0." + s + "e" + exp.Value.Value.ToString(System.Globalization.CultureInfo.InvariantCulture);
}
}
}