Unable to increase the precision in computing square root using bisection method.

Tried to code bisection method to compute square root of 2, till the difference between two consecutive steps is less than some specific value, say 10^{-11}, where tolerance variable is specified as 11.

But, inspite of choosing long double data type,am unable to get beyond 6 places after decimal.

The same result is obtained, if choose tolerance as 11, 30, 5.

Cannot understand the reason for that.

The reason for that is unclear, as know that can get infinite number of decimal digits in the decimal expansion of sqrt{2}.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <math.h>
using namespace std;

int main() {
   int val, tolerance;
   cout << "Input the values of the number whose square root need be found, and the tolerance limit in the number of digits, of integer variable: tolerance, giving tolerance limit as: 10^{-tolerance}" << endl;
   cout<< "Enter the number, followed by the # tolerance digits."<< endl;
   cin >>val>> tolerance;
   if(val< 0)
      exit(0); 
   else 
   {
      long double low = 0, high = val;
      long double  mid = (low + high)/2;
      int c = 0; 
      long double diff = 0;

      while (!c) 
      {
         if((mid*mid-val)<0)
             diff = val - mid*mid;
         if (diff <= pow(10, -1*tolerance))
         {
            c = 1;
            cout << "Square root of 2= "<< mid<<endl;
         }
         else if(mid * mid > val) 
         {
               high = mid;
               mid = (low + high)/2;      
          } 
          else 
          {
               low = mid;
               mid = (low + high)/2;
          }
      }
    }
   return 0;
}


Am running on onlinegdb.com, using the C++ option.
Last edited on
A couple of changes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <iomanip>
#include <math.h>
using namespace std;

int main() {
   int val, tolerance;
   cout << "Input the values of the number whose square root need be found, and the tolerance limit in the number of digits, of integer variable: tolerance, giving tolerance limit as: 10^{-tolerance}" << endl;
   cout<< "Enter the number, followed by the # tolerance digits."<< endl;
   cin >>val>> tolerance;
   if(val< 0)
      exit(0); 
   else 
   {
      long double limit = powl(10,-tolerance);  // use powl, not pow for better precision
      long double low = 0, high = val;
      long double  mid = (low + high)/2;
      int c = 0; 
      long double diff = 0;

      while (!c) 
      {
         if((mid*mid-val)<0)
             diff = val - mid*mid;
         if (diff <= limit)
         {
            c = 1;
            cout << "Square root of 2= "<< setprecision(tolerance) << mid<<endl;
         }
         else if(mid * mid > val) 
         {
               high = mid;
               mid = (low + high)/2;      
          } 
          else 
          {
               low = mid;
               mid = (low + high)/2;
          }
      }
    }
   return 0;
}



$ ./a.out 
Input the values of the number whose square root need be found, and the tolerance limit in the number of digits, of integer variable: tolerance, giving tolerance limit as: 10^{-tolerance}
Enter the number, followed by the # tolerance digits.
2 6
Square root of 2= 1.41421
$ ./a.out 
Input the values of the number whose square root need be found, and the tolerance limit in the number of digits, of integer variable: tolerance, giving tolerance limit as: 10^{-tolerance}
Enter the number, followed by the # tolerance digits.
2 10
Square root of 2= 1.414213562
$ ./a.out 
Input the values of the number whose square root need be found, and the tolerance limit in the number of digits, of integer variable: tolerance, giving tolerance limit as: 10^{-tolerance}
Enter the number, followed by the # tolerance digits.
2 20
^C
$ ./a.out 
Input the values of the number whose square root need be found, and the tolerance limit in the number of digits, of integer variable: tolerance, giving tolerance limit as: 10^{-tolerance}
Enter the number, followed by the # tolerance digits.
2 15
Square root of 2= 1.41421356237309

Beware of entering tolerances finer than the decimal precision of long double.
It may get stuck in a loop that never converges to within the tolerance you request.

> The reason for that is unclear, as know that can get
> infinite number of decimal digits in the decimal expansion of sqrt{2}.
If you're looking for hundreds of digits, then floating point is the wrong tool for the job.

it may be worth your time to print the size of long double. It varies depending on the underlying hardware and compiler.
@salem_c Seems the header file iomanip is the key.
But, your program fails to work (as your version works) even if just add an output file to store output. This is additional to the cout statements.
You can check the working of the below program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <iomanip>
#include <fstream>
#include <math.h>
using namespace std;

int main() {
   int val, prec;
   ofstream out_file;
   out_file.open("output_bisect.txt");
   cout << "Enter the number, and precision"<<endl;
   out_file << "Enter the number, and precision"<<endl;
   cin >>val>> prec;
   
   if(val< 0) 
       exit(0);
   else 
   {
      long double low = 0, high = val;
      long double  mid = (low + high)/2;
      int c = 0; long double magn=0;

      while (!c) 
      {
         if((mid*mid-val)<0)
             magn = val - mid*mid;
         
         if (magn <= pow(10, -1*prec))
         {
            cout << "Square root is: " << mid <<endl;
            out_file << "Square root is: " << mid <<endl;
            c = 1;
         }
         else if(mid * mid > val) 
         {
               high = mid;
               mid = (low + high)/2;
          } 
          else 
          {
               low = mid;
               mid = (low + high)/2;  
          }
       }
    }
   return 0;
}
Last edited on
> Seems the header file iomanip is the key.
Yeah, but you still need to call setprecision.

The default I/O precision for floating point types is set by the compiler, commonly set to 6 digits. The I/O precision can be be changed by using <iomanip>'s std::setprecision manipulator.

https://en.cppreference.com/w/cpp/io/manip/setprecision

Your OS, the underlying computer hardware and compiler may use a different maximum precision number, the largest machine-native floating point on many platforms is 80 bits.

If you need a greater number of significant digits than your compiler's default there are 3rd party libraries available. GNU's MPFR library, for instance.

https://www.mpfr.org/

Or Boost's multiprecision library. Integer and floating point types available.

https://www.boost.org/doc/libs/1_81_0/libs/multiprecision/doc/html/index.html
Last edited on
C++20 has std::format that allows for modifying the output precision for floating point types, the default is set to the maximum allowed number of digits.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <iomanip>
#include <numbers>
#include <limits>
#include <format>

int main( )
{
   std::cout << "float: " << sizeof(float) << '\n';
   std::cout << std::numeric_limits<float>::digits10 << "\n\n";

   std::cout << "double: " << sizeof(double) << '\n';
   std::cout << std::numeric_limits<double>::digits10 << "\n\n";

   std::cout << "long double: " << sizeof(long double) << '\n';
   std::cout << std::numeric_limits<long double>::digits10 << "\n\n";

   // default precision, outputs 3.14159
   std::cout << std::numbers::pi << '\n';

   // maximum precision, outputs 3.141592653589793
   constexpr auto max_precision { std::numeric_limits<long double>::digits10 + 1 };
   std::cout << std::setprecision(max_precision) << std::numbers::pi << "\n\n";

   // default precision, outputs 3.141592653589793
   std::cout << std::format("{}\n", std::numbers::pi);

   // https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification
   // outputs 3.141592653589793115997963468544185161590576171875
   // is this really a valid number, though?
   std::cout << std::format("{:2.48f}\n", std::numbers::pi);
}
float: 4
6

double: 8
15

long double: 8
15

3.14159
3.141592653589793

3.141592653589793
3.141592653589793115997963468544185161590576171875

I use MSVC, a long and a long double use the same number of bytes and have the same number of significant digits maximum precision.

If your compiler doesn't support <format> remove lines 25-31 and the <format> header. Compile and run will tell you what your system and compiler can do.

If your compiler doesn't support <format> consider using the {fmt} library, it formed the basis for C++20's stdlib <format> library.

https://fmt.dev/latest/index.html
@salim_c: You stated:
>Beware of entering tolerances finer than the decimal precision of long double.
>It may get stuck in a loop that never converges to within the tolerance you >request.

Please elaborate, as have :
1
2
3
4
5
if((mid*mid-val)<0)
    magn = val - mid*mid;
         
if (magn <= pow(10, -1*prec))
{

then how having value of: pow(10, -1*prec) less than decimal precision of long double, can cause infinite loop.
Last edited on
@George_P Thanks a lot for excellent inputs on the topic, for which even books seems have nothing to impart.
Till now, got inputs from SO (https://stackoverflow.com/q/554063/555045), about an alternative way:
- add in header:
(i) header file : #include <limits>
(ii) typedef std::numeric_limits< double > dbl
- in code, state:
cout.precision(dbl::max_digits10)

This works too, but surprisingly not stated here.
Request if there are gains in one approach over the other; & hence not stated by you?
Also, if outstream's precision is changed, then if store output in file, there the same change should occur too.
But, failed with the SO approach, stated here.

Haven't tried so far your method, but think it would also fail for output stored in file.

Will update soon.
Last edited on
Registered users can post here. Sign in or register to post.