ตามที่ระบุไว้แล้ว คุณต้องเปลี่ยนอัลกอริทึมเป็นตัวเลขต่อหลัก (มีตัวอย่างบางส่วนใน หน้าวิกิพีเดียเกี่ยวกับวิธีการคำนวณรากที่สอง) และใช้ไลบรารีเลขคณิตที่มีความแม่นยำตามอำเภอใจเพื่อทำการคำนวณ (เช่น GMP)
ในตัวอย่างต่อไปนี้ ฉันใช้อัลกอริธึมที่กล่าวถึงก่อนหน้านี้ โดยใช้ GMP (แต่ไม่ใช่ฟังก์ชันสแควร์รูทที่ไลบรารีจัดเตรียมให้) แทนที่จะคำนวณทศนิยมทีละหลัก การใช้งานนี้ใช้ฐานที่ใหญ่กว่า ซึ่งเป็นพหุคูณที่ยิ่งใหญ่ที่สุดของ 10 ที่พอดีกับ unsigned long
เพื่อให้สามารถสร้างทศนิยม 9 หรือ 18 หลักในแต่ละครั้งของการวนซ้ำ
นอกจากนี้ยังใช้วิธีนิวตันที่ดัดแปลงเพื่อค้นหา "ตัวเลข" ที่แท้จริง
#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);
}
คุณสามารถดูตัวเลขที่ส่งออกได้ที่นี่
person
Bob__
schedule
20.02.2020
10
เป็นสิ่งที่คุณต้องการ) - person Some programmer dude   schedule 20.02.2020sqrt(5)
แต่สำหรับฉันแล้วดูเหมือนว่าคุณต้องการเขียนโปรแกรมเพื่อ 'คำนวณ' ตัวเลขนี้จริงๆ แล้วจึงพิมพ์ทีละหลัก โปรดทราบว่าโดยปกติคอมพิวเตอร์จะทำงานกับตัวเลขนัยสำคัญจำนวนคงที่ และคุณต้องมีไลบรารีพิเศษเพื่อให้สามารถทำงานกับตำแหน่งทศนิยมได้มากเท่าที่คุณต้องการ - ตามที่ @pmg ระบุไว้ -- โดยปกติแล้ว คอมพิวเตอร์จะถูกกำหนดตามจำนวนหลักที่กำหนดไว้เพื่อประหยัดหน่วยความจำ หรืออย่างน้อยก็ทำให้สามารถจัดการได้ เพื่อให้คอมพิวเตอร์รู้ว่าจะกำหนดหน่วยความจำให้กับแต่ละหมายเลขเท่าใด.... - person tom   schedule 20.02.2020sqrt
จะไม่เปลี่ยนแปลงอีกต่อไป หากต้องการความแม่นยำมากขึ้น คุณจะต้องใช้วิธีอื่น - person Paul Ogilvie   schedule 20.02.2020