С ++ двойное значение теряет точность при умножении? - PullRequest
1 голос
/ 05 сентября 2010

Я пытаюсь создать функцию для поиска квадратного корня числа.В целях отладки он имеет инструкции для печати текущих значений переменных.Функция squareRoot принимает два аргумента, x и t.Затем он объявляет и инициализирует n и s.n - это сумма, которую нужно сложить или вычесть, уменьшая ее вдвое при каждом использовании.s - это то, что считается текущим квадратным корнем.Во время работы я четко вижу, что n корректно настраивается.Однако s перестает изменяться, когда первые четыре цифры верны.Я использую этот вызов в main():

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

Это должно вывести квадратный корень из 1000 с точностью до десятых, но происходят две странные вещи:

  • Это не 't останавливается на 31,6.
  • Он останавливается на 4 цифрах!

Моя теория относительно того, почему он останавливается на четырех цифрах, такова: при умножении s теряет часть своей точности,Это правда?Если да, можете ли вы сказать мне, как это исправить?Если нет, то чем это вызвано и как я могу это исправить?

Я уже пытался решить эту проблему, используя другую переменную s1, которая будет умножена и проверена.Тогда s будет увеличен на n, а s1 синхронизирован с s.Это не сработало, поэтому я вернулся к исходному коду.

Мой код выглядит следующим образом:

#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;
}

Я использую 64-битную Windows 7, MSVC ++ 2008 Express.Заранее благодарю за все ответы!

Ответы [ 3 ]

2 голосов
/ 05 сентября 2010

Сходится к правильному квадратному корню, но по умолчанию cout печатает только шесть значащих цифр: 31.xxxx.

Также обратите внимание, что ваша проверка завершения не работает, потому что (1 / t) всегда будет иметь значение 0 при t> 1. Вместо этого используйте 1./t.

1 голос
/ 05 сентября 2010

Не имеет отношения, но ваш алгоритм sqrt может быть ускорен с использованием существующего, такого как метод Ньютона.

Это выглядит так:

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);
}

Метод Ньютона также работает для кубических корней и т. Д. Для получения десятичных показателей посмотрите Биномиальную теорему.

1 голос
/ 05 сентября 2010

Причина, по которой цикл не останавливается, заключается в том, что условие цикла неверно. У вас есть

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

Но либо значение current - target, либо значение target - current будет <= 0. И 0 < precision. Таким образом, у вас есть эквивалент while (true) {...} loop.
Вам нужно что-то вроде

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

(не знаю точную функцию для получения абсолютного значения в C ++)

редактировать
Только что заметил, hamster3null писал о 1/t до меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...