In the previous version, the binary method was used to calculate the square root of an integer. It was a bit difficult to look at the code, and the convergence was slow. When vc6 was around 80, it was necessary to say that the template recursion was too unbearable.
Now we are looking at a method that uses the Newton Iteration Method to accelerate convergence. The number of iterations is greatly reduced. vc6 can support up to 225.
Or code. Compared with the previous one, the code changes a little. Four macros can still be used.
Serving# Include <iostream> <br/> using namespace STD; <br/> // Enum {stop_tag = (size_t)-1}; // some compiler will crash so be careful! Warning comes if size_t is not used! <Br/> static const size_t stop_tag = (size_t)-1; // try the one above if your compiler doesn't support static Const. <br/>/* binary search between [M1, M2] */<br/> template <size_t N, size_t M1, size_t m2> // assert M1 <= m2 <= n <br/> struct sqrt_check <br/>{< br/> Enum {middle = (M1 + m2) /2 }; <br/> Enum {end = m1 * m1 = n | m2 * M2 = n | M1 = Middle | middle * middle = n }; <br/> Enum {selector = middle * Middle> N }; <br/> Enum {<br/> result = n = m1 * m1? <Br/> m1: N = m2 * m2? <Br/> M2: M1 = middle? // | M1-M2 | = 1, which means m1 * m1 <= n <= m2 * M2 <br/> m1: N = middle * middle? // Bsearch begin! <Br/> middle: Selector? <Br/> sqrt_check <End? Stop_tag: N, end? Stop_tag: M1, end? Stop_tag: middle >:: result <br/>: sqrt_check <End? Stop_tag: N, end? Stop_tag: middle, end? Stop_tag: M2 >:: result <br/>}; <br/> template <> <br/> struct sqrt_check <stop_tag, stop_tag, stop_tag> <br/>{< br/> Enum {result =-1}; // stop here! <Br/>}; <br/> template <size_t N, size_t M1, size_t m2> <br/> struct sqrt_check_newton <br/>{< br/> Enum {next = (M1 + N/M1)/2 }; // Newton iterator method <br/> Enum {end = next = m1 | next = m2 | next * Next = n }; <br/> Enum {<br/> result = n = next * Next | M1 = next? // Fixed point <br/> next: m2 = next? // | M1-M2 | = 1, which means m1 * m1 <= n <= m2 * M2 swing back and forth <br/> (M2 + M1)/2: sqrt_check_newton <(end? Stop_tag: N), (end? Stop_tag: Next), (end? Stop_tag: M1) >:: result <br/>}; <br/> template <> <br/> struct sqrt_check_newton <stop_tag, stop_tag, stop_tag> <br/>{< br/> Enum {result =-1}; // stop here! <Br/> }; <br/>/* Get the SQRT result of N */<br/> template <size_t n> <br/> struct sqrt_nature <br/> {<br/> // enum {result = sqrt_check <n, 1, n/2 + 1 >:: result}; // begin searching between [1, n/2 + 1] <br/> Enum {result = sqrt_check_newton <n, n/2, N >:: result };< br/> Enum {square = Result * result = n };< br/> }; <br/> template <> <br/> struct sqrt_nature <1> <br/>{< br/> Enum {result = 1 }; <br/> Enum {square = tr UE };< br/> }; <br/> template <> <br/> struct sqrt_nature <0> <br/>{< br/> Enum {result = 0 }; <br/> Enum {square = true}; <br/> }; <br/>/* Check if n % d = 0 */<br/> template <size_t N, size_t D> <br/> struct prime_check <br/> {<br/> Enum {mod = n % d = 0 }; <br/> Enum {<br/> prime = d = 1? <Br/> true: MoD? <Br/> false: prime_check <MoD? Stop_tag: N, MoD? Stop_tag: d-1 >:: prime <br/>}; <br/> template <> <br/> struct prime_check <stop_tag, stop_tag> <br/>{< br/> Enum {Prime = true };< br/> }; <br/>/* Check if n is a prime */<br/> template <size_t n> <br/> struct prime_nature <br/>{< br/> Enum {prime = prime_check <n, sqrt_nature <n >:: result >:: prime }; <br/> Enum {composite =! Prime };< br/> }; <br/> template <> <br/> struct prime_nature <1> <br/>{< br/> Enum {Prime = false }; <br/> Enum {composite = false };< br/>}; <br/>/* Get the Count of prime smaller than N. */<br/> template <size_t n> <br/> struct prime_count_nature <br/> {<br/> Enum {prime_count = prime_count_nature <N-1> :: prime_count + (prime_nature <n >:: Prime? 1: 0) }; <br/> Enum {composite_count = N-prime_count-1}; <br/> }; <br/> template <> <br/> struct prime_count_nature <1> <br/>{< br/> Enum {prime_count = 0 }; <br/> Enum {composite_count = 0 }; <br/>}; <br/>/* the following 4 macros are used for test. you can uncomment any of 4. */<br/> # define test (X)/<br/> do {/<br/> If (bool (prime_nature <X >:: prime )) /<br/> cout <x <Endl;/<br/>} while (false) <br/> // # Defin E test (x) cout <prime_count_nature <X >:: prime_count <Endl <br/> // # define test (X) cout <x <''<(bool (prime_nature <x>: PRIME )? "Yes": "no") <Endl <br/> // # define test (x) cout <x <''<sqrt_nature <x> :: result <Endl <br/>/* test from 1 to n */<br/> template <size_t n> <br/> struct test_nature: public test_nature <N-1> <br/>{< br/> test_nature (): test_nature <N-1> () {test (n) ;}< br/> }; <br/> template <> <br/> struct test_nature <1> <br/>{< br/> test_nature () {test (1 );} <br/>}; <br/> int main () <br/>{< br/> test_nature <225> X; // vc6.0 will crash for nesting template over 225 <br/> // test (8); <br/> return 0; <br/>}< br/>
Key points: Enum {next = (M1 + N/M1)/2 };// Newton iterator Method
Y = x
2
=
> X = (x + y/X)/2
When Y is greater than 0, there is only one fixed point (x + y/X)/2: Y1/2
This example tells us that coder can take a big step forward with a small improvement in algorithms.
Walk first, then walk. What scientist do you say this is?