Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C#中,如何将大整数的除法计算为十进制而不是双精度? TL;博士_C#_Type Conversion - Fatal编程技术网

在C#中,如何将大整数的除法计算为十进制而不是双精度? TL;博士

在C#中,如何将大整数的除法计算为十进制而不是双精度? TL;博士,c#,type-conversion,C#,Type Conversion,BigRational类型可以转换为double来计算值。但是,在分子和分母达到一定大小后,返回的值是double.NaN 由于BigRational将分子和分母作为System.Numerics.BigIntegers进行跟踪,因此您可以使用对数属性的解决方法: a / b = e^(ln(a) - ln(b)) 通过我们的biginger分子和分母,我们可以调用 BigInteger num = myBigRational.Numerator; BigInteger den = myBig

BigRational
类型可以转换为
double
来计算值。但是,在分子和分母达到一定大小后,返回的值是
double.NaN

由于
BigRational
将分子和分母作为
System.Numerics.BigInteger
s进行跟踪,因此您可以使用对数属性的解决方法:

a / b = e^(ln(a) - ln(b))
通过我们的
biginger
分子和分母,我们可以调用

BigInteger num = myBigRational.Numerator;
BigInteger den = myBigRational.Denominator;
double value = Math.Exp(BigInteger.Log(num) - BigInteger.Log(den));
由于接近0的值的
double
类型的结构限制,我宁愿使用
decimal
。我只是还不知道怎么做

上下文 只是为了好玩,我正在编写一个程序,使用
arctan
的函数计算pi

arctan(x) = x - x^3/3 + x^5/5 - x^7/7 +  x^9/9 - ...
如果我们在1处计算序列,我们得到

arctan(1) = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...
由于arctan(1)=pi/4,我们可以将级数乘以4来计算pi

我的程序的目标是计算要收敛到精确到n位数的
pi所需的级数项数。例如,为了使序列精确到一位数字(3),它需要前三项:

1 term:  4 * (1) = 4
2 terms: 4 * (1 - 1/3) = 2.666666666666667
3 terms: 4 * (1 - 1/3 + 1/5) = 3.466666666666667
要精确到2位(3.1),它需要前19个术语。精确到3位(3.14)需要前119个术语,依此类推

我最初使用C#的
decimal
type编写程序:

const int MaxDigits = 20;
private static void RunDecimalCalculation()
{
    decimal pi = 0m; // our current approximation of pi
    decimal denominator = 1m;
    decimal addSubtract = 1m;
    ulong terms = 0;

    for (int digits = 0; digits < MaxDigits; digits++)
    {
        decimal piToDigits, upperBound;
        GetBounds(digits, out piToDigits, out upperBound);

        while (pi >= upperBound | pi < piToDigits)
        {
            pi += addSubtract * 4m / denominator;
            denominator += 2m;
            addSubtract *= -1m;
            terms++;
        }

        PrintUpdate(terms, digits, pi);
    }
}

/// <summary>
/// Returns the convergence bounds for <paramref name="digits"/> digits of pi.
/// </summary>
/// <param name="digits">Number of accurate digits of pi.</param>
/// <param name="piToDigits">Pi to the first <paramref name="digits"/> digits of pi.</param>
/// <param name="upperBound">same as <paramref name="piToDigits"/>, but with the last digit + 1</param>
/// <example>
/// <code>GetBounds(1)</code>:
///     piToDigits = 3
///     upperBound = 4
/// 
/// <code>GetBounds(2)</code>:
///     piToDigits = 3.1
///     upperbound = 3.2
/// </example>
private static void GetBounds(int digits, out decimal piToDigits, out decimal upperBound)
{
    int pow = (int)Math.Pow(10, digits);
    piToDigits = (decimal)Math.Floor(Math.PI * pow) / pow;
    upperBound = piToDigits + 1m / pow;
}
然而,我意识到,由于每次迭代中的舍入错误,在足够的术语之后,所需的术语数量可能会减少。因此,我开始研究F#PowerPack的
BigRational
,并重写代码:

// very minor optimization by caching common values
static readonly BigRational Minus1 = BigRational.FromInt(-1);
static readonly BigRational One = BigRational.FromInt(1);
static readonly BigRational Two = BigRational.FromInt(2);
static readonly BigRational Four = BigRational.FromInt(4);

private static void RunBigRationalCalculation()
{
    BigRational pi = BigRational.Zero;
    ulong terms = 0;
    var series = TaylorSeries().GetEnumerator();

    for (int digits = 0; digits < MaxDigits; digits++)
    {
        BigRational piToDigits, upperBound;
        GetBounds(digits, out piToDigits, out upperBound);

        while (pi >= upperBound | pi < piToDigits)
        {
            series.MoveNext();
            pi += series.Current;
            terms++;
        }

        double piDouble = Math.Exp(BigInteger.Log(pi.Numerator) - BigInteger.Log(pi.Denominator));
        PrintUpdate(terms, digits, (decimal)piDouble);
    }
}

// code adapted from http://tomasp.net/blog/powerpack-numeric.aspx
private static IEnumerable<BigRational> TaylorSeries()
{
    BigRational n = One;
    BigRational q = One;

    while (true)
    {
        yield return q * Four / n;

        n += Two;
        q *= Minus1;
    }
}
这是不准确的。有没有一种方法可以通过数学向导或一些库来解决这个问题,这些库具有
Math.Exp()
biginger.Log()
decimal
版本

在C#中,如何将大整数的除法计算为十进制而不是双精度

您有较大的整数N和D,希望将精确值N/D近似为十进制。WOLOG假设两者都是正的

这很容易。首先解决这个问题:

  • 给定N和D,找到使N/D-M/1028的绝对值最小的大整数M
第二,解决这个问题:

  • 给定M,求大整数M'和非负整数E,使M/1028=M'/10e和E最小化
第三,解决这个问题:

  • 给定M',求非负大整数I0,I1,I2,使M'=I0+I1*232+I2*264,且每个都严格小于232。如果没有这样的I0、I1、I2,那么您的数字就不能表示为十进制
将I0、I1和I2转换为无符号整数,然后再转换为有符号整数

现在你有了所有需要打电话的东西

嘿,你手里有一个小数点

也就是说:你不应该一开始就这么做。你在用大有理数做数学;你为什么要把它们改成小数或双数呢?只要把π近似到你想要的大有理数的任何水平,然后将你的缓慢转换序列与之进行比较


仅供参考,此系列收敛速度非常慢。一旦你根据经验确定了它的收敛速度,你能证明收敛速度的任何界限吗?

这个问题的答案似乎可以满足你的两个需要:@Abion47-Hmm,也许吧。我不确定这段代码是否与我在做迭代十进制问题时遇到的问题相同。他们的
DecimalExp()
LogN()
代码的序列收敛性与我的相同。也就是说,如果他们的代码是准确的,我想我的十进制版本也会是准确的——很可能是这样;我只是不确定。看起来您在原始代码中进行了一系列从
double
int
double
decimal
的转换。每次这样做,都有可能在计算中引入错误。为了确保得到清晰的结果,你应该只计算一种类型。我不明白的是,为什么你要用双精度或十进制进行计算。将pi表示为一个BigRational,小数位数尽可能多,并使用它。提示:确定两个事物的接近程度的第一步是取它们的差。
double piDouble = Math.Exp(BigInteger.Log(pi.Numerator) - BigInteger.Log(pi.Denominator));