Seperti yang telah disebutkan, Anda perlu mengubah algoritma menjadi algoritma digit demi digit (ada beberapa contoh di Halaman Wikipedia tentang metode penghitungan akar kuadrat) dan gunakan pustaka aritmatika presisi arbitrer untuk melakukan penghitungan (misalnya, GMP).
Dalam cuplikan berikut saya menerapkan algoritma yang disebutkan sebelumnya, menggunakan GMP (tetapi bukan fungsi akar kuadrat yang disediakan perpustakaan). Daripada menghitung satu digit desimal dalam satu waktu, implementasi ini menggunakan basis yang lebih besar, kelipatan 10 terbesar yang muat di dalam unsigned long
, sehingga dapat menghasilkan 9 atau 18 digit desimal pada setiap iterasi.
Ia juga menggunakan metode Newton yang diadaptasi untuk menemukan "digit" yang sebenarnya.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <gmp.h>
unsigned long max_ul(unsigned long a, unsigned long b)
{
return a < b ? b : a;
}
int main(int argc, char *argv[])
{
// The GMP functions accept 'unsigned long int' values as parameters.
// The algorithm implemented here can work with bases other than 10,
// so that it can evaluate more than one decimal digit at a time.
const unsigned long base = sizeof(unsigned long) > 4
? 1000000000000000000
: 1000000000;
const unsigned long decimals_per_digit = sizeof(unsigned long) > 4 ? 18 : 9;
// Extract the number to be square rooted and the desired number of decimal
// digits from the command line arguments. Fallback to 0 in case of errors.
const unsigned long number = argc > 1 ? atoi(argv[1]) : 0;
const unsigned long n_digits = argc > 2 ? atoi(argv[2]) : 0;
// All the variables used by GMP need to be properly initialized before use.
// 'c' is basically the remainder, initially set to the original number
mpz_t c;
mpz_init_set_ui(c, number);
// At every iteration, the algorithm "move to the left" by two "digits"
// the reminder, so it multplies it by base^2.
mpz_t base_squared;
mpz_init_set_ui(base_squared, base);
mpz_mul(base_squared, base_squared, base_squared);
// 'p' stores the digits of the root found so far. The others are helper variables
mpz_t p;
mpz_init_set_ui(p, 0UL);
mpz_t y;
mpz_init(y);
mpz_t yy;
mpz_init(yy);
mpz_t dy;
mpz_init(dy);
mpz_t dx;
mpz_init(dx);
mpz_t pp;
mpz_init(pp);
// Timing, for testing porpuses
clock_t start = clock(), diff;
unsigned long x_max = number;
// Each "digit" correspond to some decimal digits
for (unsigned long i = 0,
last = (n_digits + decimals_per_digit) / decimals_per_digit + 1UL;
i < last; ++i)
{
// Find the greatest x such that: x * (2 * base * p + x) <= c
// where x is in [0, base), using a specialized Newton method
// pp = 2 * base * p
mpz_mul_ui(pp, p, 2UL * base);
unsigned long x = x_max;
for (;;)
{
// y = x * (pp + x)
mpz_add_ui(yy, pp, x);
mpz_mul_ui(y, yy, x);
// dy = y - c
mpz_sub(dy, y, c);
// If y <= c we have found the correct x
if ( mpz_sgn(dy) <= 0 )
break;
// Newton's step: dx = dy/y' where y' = 2 * x + pp
mpz_add_ui(yy, yy, x);
mpz_tdiv_q(dx, dy, yy);
// Update x even if dx == 0 (last iteration)
x -= max_ul(mpz_get_si(dx), 1);
}
x_max = base - 1;
// The actual format of the printed "digits" is up to you
if (i % 4 == 0)
{
if (i == 0)
printf("%lu.", x);
putchar('\n');
}
else
printf("%018lu", x);
// p = base * p + x
mpz_mul_ui(p, p, base);
mpz_add_ui(p, p, x);
// c = (c - y) * base^2
mpz_sub(c, c, y);
mpz_mul(c, c, base_squared);
}
diff = clock() - start;
long int msec = diff * 1000L / CLOCKS_PER_SEC;
printf("\n\nTime taken: %ld.%03ld s\n", msec / 1000, msec % 1000);
// Final cleanup
mpz_clear(c);
mpz_clear(base_squared);
mpz_clear(p);
mpz_clear(pp);
mpz_clear(dx);
mpz_clear(y);
mpz_clear(dy);
mpz_clear(yy);
}
Anda dapat melihat digit keluarannya di sini.
person
Bob__
schedule
20.02.2020
10
). - person Some programmer dude   schedule 20.02.2020sqrt(5)
tetapi menurut saya Anda benar-benar ingin menulis program untuk 'menghitung' angka ini dan kemudian mencetaknya digit demi digit. Perhatikan bahwa komputer biasanya bekerja pada sejumlah angka penting yang tetap dan Anda memerlukan perpustakaan khusus untuk dapat bekerja pada angka desimal sebanyak yang Anda inginkan - seperti yang dicatat oleh @pmg. -- komputer biasanya ditetapkan pada sejumlah digit untuk menghemat memori, atau setidaknya membuatnya dapat dikelola sehingga komputer mengetahui berapa banyak memori yang harus ditetapkan ke setiap nomor.... - person tom   schedule 20.02.2020sqrt
tidak berubah lagi. Untuk lebih presisi, Anda memerlukan metode lain. - person Paul Ogilvie   schedule 20.02.2020