#include <iostream>
#include <cmath>
using namespace std;
int main()
{
double a = sqrt(2);
cout << a << endl;
}
嗨,这是查找 2 的 sqrt 的程序,它在输出中仅打印 1.41421 如何实现它以使其在小数点后打印 200000 位
1.41421.............最多 200 000 位
有没有这样的打印方法?
可以证明
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 + ...
还有一个可用的 C 程序使用这种方法(我稍微重新格式化并更正了它):
/*
** 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 位。
这是您使用 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
这是一个使用古老的 Prolog 编程语言在不到一分钟的时间内计算出 100 万位 sqrt(2) 的解决方案。它基于求解 pell 方程,另请参见此处:
p*p+1 = 2*q*q
递归关系 p′=3p+4q 和 q′=2p+3q 可以转换为矩阵乘法。即我们看到,如果我们将向量 [p,q] 乘以系数矩阵,我们得到向量 [p',q']:
| p' | | 3 4 | | p |
| | = | | * | |
| q' | | 2 3 | | q |
对于矩阵 A,我们可以使用二进制递归,以便我们可以在 O(log n) 操作中计算 A^n。我们需要大量的数字。我在这里使用这个实验代码,因此主程序很简单:
/**
* 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 次百万次迭代。可以在此处将结果与此页面进行比较。
缺少的仍然是一个明确的标准和计算,说明有多少位数是稳定的。我们将需要更多时间来做到这一点。
编辑 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
就双重算术的精度而言,您给出的示例是准确的,这是大多数 C++ 编译器使用的最高精度。一般来说,计算机没有工具来进行更高精度的计算。如果这是某种家庭作业,那么我怀疑您需要找出一种计算算法-您需要以某种方式保留自己的数字数组以保持所需的所有精度。如果您有一些实际应用程序,您绝对应该使用专门用于执行此类算术的高精度库(GMP 是一个很好的开源可能性) - 这是一个不需要重新发明的复杂轮子。