找到尽可能多的2的平方根数字

时间:2013-03-12 13:06:46

标签: c++ sqrt

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
 double a = sqrt(2);
 cout << a << endl;
}

嗨,这是找到sqrt为2的程序,它在输出中只打印1.41421如何实现它,以便在小数点后打印200000位数

  

1.41421 ..........高达200 000位

有这样的印刷方法吗?

4 个答案:

答案 0 :(得分:7)

It can be shown

sqrt(2) = (239/169)*1/sqrt(1-1/57122)

使用泰勒级数展开可以有效地计算1 / sqrt(1-1 / 57122):

1/sqrt(1-x) = 1 + (1/2)x + (1.3)/(2.4)x^2 + (1.3.5)/(2.4.6)x^3 + ...

There's also a C program available that uses this method(我稍微重新格式化并纠正了它):

/*
** Pascal Sebah : July 1999
**
** Subject:
**
**    A very easy program to compute sqrt(2) with many digits.
**    No optimisations, no tricks, just a basic program to learn how
**    to compute in multiprecision.
**
** Formula:
**
**    sqrt(2) = (239/169)*1/sqrt(1-1/57122)
**
** Data:
**
**    A big real (or multiprecision real) is defined in base B as:
**      X = x(0) + x(1)/B^1 + ... + x(n-1)/B^(n-1)
**      where 0<=x(i)<B
**
** Results: (PentiumII, 450Mhz)
**
**    1000   decimals :   0.02seconds
**    10000  decimals :   1.7s
**    100000 decimals : 176.0s
**
** With a little work it's possible to reduce those computation
** times by a factor of 3 and more.
*/

#include <stdio.h>
#include <stdlib.h>

long B = 10000; /* Working base */
long LB = 4;    /* Log10(base)  */

/*
** Set the big real x to the small integer Integer
*/
void SetToInteger(long n, long* x, long Integer)
{
  long i;
  for (i = 1; i < n; i++)
    x[i] = 0;
  x[0] = Integer;
}

/*
** Is the big real x equal to zero ?
*/
long IsZero(long n, long* x)
{
  long i;
  for (i = 0; i < n; i++)
    if (x[i])
      return 0;
  return 1;
}

/*
** Addition of big reals : x += y
**  Like school addition with carry management
*/
void Add(long n, long* x, long* y)
{
  long carry = 0, i;
  for (i = n - 1; i >= 0; i--)
  {
    x[i] += y[i] + carry;
    if (x[i] < B)
      carry = 0;
    else
    {
      carry = 1;
      x[i] -= B;
    }
  }
}

/*
** Multiplication of the big real x by the integer q
*/
void Mul(long n, long* x, long q)
{
  long carry = 0, xi, i;
  for (i = n - 1; i >= 0; i--)
  {
    xi = x[i] * q;
    xi += carry;
    if (xi >= B)
    {
      carry = xi / B;
      xi -= carry * B;
    }
    else
      carry = 0;
    x[i] = xi;
  }
}

/*
** Division of the big real x by the integer d
**  Like school division with carry management
*/
void Div(long n, long* x, long d)
{
  long carry = 0, xi, q, i;
  for (i = 0; i < n; i++)
  {
    xi    = x[i] + carry * B;
    q     = xi / d;
    carry = xi - q * d;
    x[i]  = q;
  }  
}

/*
** Print the big real x
*/
void Print(long n, long* x)
{
  long i;
  printf("%ld.", x[0]);
  for (i = 1; i < n; i++)
    printf("%04ld", x[i]);
  printf("\n");
}

/*
** Computation of the constant sqrt(2)
*/
int main(void)
{
  long NbDigits = 200000, size = 1 + NbDigits / LB;
  long* r2 = malloc(size * sizeof(long));
  long* uk = malloc(size * sizeof(long));
  long k = 1;
  /*
  ** Formula used:
  **    sqrt(2) = (239/169)*1/sqrt(1-1/57122)
  ** and
  **   1/sqrt(1-x) = 1+(1/2)x+(1.3)/(2.4)x^2+(1.3.5)/(2.4.6)x^3+...
  */
  SetToInteger(size, r2, 1); /* r2 = 1 */
  SetToInteger(size, uk, 1); /* uk = 1 */
  while (!IsZero(size, uk))
  {
    Div(size, uk, 57122); /* uk = u(k-1)/57122 * (2k-1)/(2k) */
    Div(size, uk, 2 * k);
    Mul(size, uk, 2 * k - 1);
    Add(size, r2, uk);    /* r2 = r2+uk */
    k++;
  }
  Mul(size, r2, 239);
  Div(size, r2, 169);  /* r2 = (239/169)*r2 */

  Print(size, r2);     /* Print out of sqrt(2) */

  free(r2);
  free(uk);

  return 0;
}

计算200,000位sqrt(2)需要大约一分钟。

但请注意,在200,000位数字处,由于累积的舍入错误,产生的最后11位数字不正确,如果您想要200,000个正确数字,则需要运行200,012位数字。

答案 1 :(得分:4)

以下是使用GNU GMP库的问题代码。代码将打印1000位sqrt(2),增加注释行中的数字以满足您的请求。

#include <stdio.h>
#include <gmp.h>

int main(int argc, char *argv[])
{
  mpf_t res,two;
  mpf_set_default_prec(1000000); // Increase this number.
  mpf_init(res);
  mpf_init(two);
  mpf_set_str(two, "2", 10);
  mpf_sqrt (res, two); 
  gmp_printf("%.1000Ff\n\n", res); // increase this number.
  return 0;
}

请使用以下命令编译它:

$gcc gmp.c  -lgmp -lm -O0 -g3

答案 2 :(得分:1)

就双精度算法的精度而言,您给出的示例是准确的,这是大多数C ++编译器使用的最高精度。通常,计算机不能用于进行更高精度的计算。 如果这是某种类型的家庭作业,那么我怀疑你需要找出一个计算算法 - 你需要以某种方式保留你自己的数字数组,以保持你需要的所有精度。 如果你有一些真实世界的应用程序,你肯定应该使用专门用来做这种算术的高精度库(GMP是一个很好的开源可能性) - 这是一个复杂的轮子,不需要重新发明。

答案 3 :(得分:1)

这是一个解决方案,使用优质的Prolog编程语言在不到一分钟的时间内计算出100万个sqrt(2)的数字。它基于求解pell方程,另见here

p*p+1 = 2*q*q

可以将再现关系p'= 3p + 4q和q'= 2p + 3q作为矩阵乘法。也就是说,如果我们将矢量[p,q]乘以系数矩阵,我们得到矢量[p&#39;,q&#39;]:

| p' |    | 3  4 |   | p |
|    | =  |      | * |   |
| q' |    | 2  3 |   | q |

对于矩阵A,我们可以使用二进制递归,以便我们可以在O(log n)运算中计算A ^ n。我们需要大量的名字。我正在使用这个实验代码here,其中主程序就是:

/**
  * pell(N, R):
  * Compute the N-the solution to p*p+1=2*q*q via matrices and return
  * p/q in decimal format in R.
  */
pell(N, R) :-
   X is [[3,4],[2,3]],
   Y is X^N,
   Z is Y*[[1],[1]],
   R is Z[1,1]*10^N//Z[2,1].

以下屏幕截图显示了时间和一些结果。我使用了10次迭代10次。可以将结果与此页面here进行比较。

enter image description here

缺少什么仍然是明确的标准和计算,表明有多少位数是稳定的。我们需要更多时间来做到这一点。

编辑20.12.2016:
我们通过相对误差的上限稍微改进了代码,并通过微调结果来进一步计算稳定的数字。 100万位的计算时间现在低于2秒:

?- time(pell(653124, _, S)).
% Uptime 1,646 ms, GC Time 30 ms, Thread Cpu Time 1,640 ms
S = -1000000