开发者

C++ double value losing precision when multiplied?

I am trying to create a function to find the square root of a number. For debugging purposes, it has instructions to print current variable values. The function squareRoot accepts two arguments, x and t. It then declares and initializes n and s. n is the amount to add or subtract, halving every time it is used. s is what is thought to be the current square root. When running, I can clearly see that n is adjusting correctly. However, s stops changing when the first four digits are correct. I am using this call in main():

cout << squareRoot(1000, 10) << "\n";

This should print the square root of 1000 to the nearest tenth, but two weird things happen:

  • It doesn't stop at 31.6.
  • It stops at 4 digits!

My theory as to why it stops at four digits is this: In multiplying, s loses some of its precision. Is this true? If so, can you tell me how to correct it? If not, what is causing this and how can I correct that?

I tried to solve it already by using another variable, s1, which would be multiplied and checked. Then s would be incremented by n, and s1 synchronized with s. This didn't work, so I went back to the original code.

My code is as follows:

#include <iostream>
using namespace std;

double squareRoot(double x, int t) {
    double s = 0;
    double n = 0.1;
    while ((s*s) <= x) {
         开发者_如何学运维   s += n;
            n *= 2;
            cout << n << "\n" << s << "\n";
    }
    cout << "\n";
    s -= n;
    // Keep changing until margin of error is reached
    while ((((s*s) - x) < (1/t)) || ((x - (s*s) < (1/t)))) {
        // If too high, lower s
        if ((s*s) <= x) {
            s += n;
            n /= 2;
            cout << "Adding 1/2 of previous n\n";
        }
        // If too low, raise s
        else if ((s*s) >= x) {
            s -= n;
            n /= 2;
            cout << "Subtracting 1/2 of previous n\n";
        }
        cout << s << "\n" << n << "\n\n";
    }
    return s;
}

I am running Windows 7 64 bit, MSVC++ 2008 Express. Thank you in advance for all answers!


It converges to the correct square root, but cout only prints six significant digits by default: 31.xxxx.

Also notice that your termination check does not work because (1/t) will always evaluate to 0 for t>1. Use 1./t instead.


Unrelated, but your sqrt algorithm can be sped up by using an existing one, such as Newton's Method.

It goes like this:

double mySqrt(double x, unsigned long accuracy = 10)
{
   if(x < 0.0)
      return(-1.0);

   double retval = 1.0;

   for(unsigned long rep = 0; rep < accuracy; rep++)
      retval = ((x / retval) + retval) / 2.0;

   return(retval);
}

Newton's method also works for cube roots, etc. For decimal exponents, look up the Binomial Theorem.


The reason loop isn't stopping is that loop condition isn't correct. You have

while ((current - target < precision) || (target - current < precision)) {
    ...
}

But either value current - target or value target - current will be <= 0. And 0 < precision. Thus you have equivalent of while (true) {...} loop.
You need something like

while (abs(current - target) > precision) {
    ...
}

(don't know exact function for getting absolute value in C++)

edit
Just noticed, hamster3null wrote about 1/t before me.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜