ошибка точности в корне числа n в C ++

0

Я знаю из предыдущих тем по этой теме, что использование арифметики float вызывает прецизионные аномалии. Но интересно, что я заметил, что одна и та же функция ведет себя по-разному.
Использование вывода COUT равно 4, но если я сохраняю результат в переменной, тогда результат равен 3 !

#include <iostream>
#include <cmath>
using namespace std;
#define mod 1000000007
long long int fastPower(long long int a, int n){
    long long int res = 1;
    while (n) {
            if (n & 1) res = (res * a) % mod;
            n >>= 1; a = (a * a) % mod;
    }
    return res;
}
int main() {
    int j = 3;
    cout << pow(64, (double)1.0/(double)j) << endl; // Outputs 4
    int root = pow(64, (double)1.0/(double)j);
    cout << root << endl;                           // Outputs 3
    /* As said by "pts", i tried including this condition in my code but including this line in my code resulted in TimeLimitExceeded(TLE). */
    if (fastPower(root+1,j) <= 64) root++;
    cout << root << endl;                           // Outputs 4 :)
    return 0;
}

Вывод кода на Ideone.com
Теперь, как мы можем избежать таких ошибок в конкурсе программирования. Я не хочу использовать функцию "round", потому что мне нужно только целочисленное значение root. т.е.
63 (1/6)= 1, 20 (1/2)= 4 и т.д.
Как мне изменить свой код, чтобы правильный результат сохранялся в корневой переменной.

  • 8
  • 3
    Все эти (double) заставляют меня поверить, что вы не знаете правил литералов C ++, операторов и продвижений типов.
Показать ещё 2 комментария
Теги:
algorithm
math
floating-accuracy

3 ответа

2

pow возвращает double. Когда используется cout, оно округляется (таким образом, оно равно 4). Когда вы бросаете его в int, он просто обрезает дробную часть. Pow возвращает что-то вроде 4 - eps (из-за точности вопросов). Когда он просто усечен, он равен 3. Грязный взлом полезен в конкурсах программирования: int root = (int)(pow(...) + 1e-7)

  • 0
    Я добавил возможное решение в свой ответ.
  • 0
    Или используйте функцию round, (int)round(pow(..,..)) .
2

Насколько я знаю, в C и C++ нет однозначного ответа для того, чтобы получить a корень из b округленный вниз.

В качестве быстрого обходного пути вы можете сделать что-то вроде:

int root(int a, int b) {
  return floor(pow(b, 1.0 / a) + 0.001);
}

Это не работает для каждого значения, но, регулируя константу (0.001), вам может повезти, и она будет работать для ввода теста.

В качестве обходного пути используйте pow когда вы его используете, и если он вернет r, попробуйте r - 1, r и r + 1, умножив его обратно (используя быстрое возведение в степень целых чисел). Это будет работать большую часть времени.

Если вам нужно решение, которое работает 100% времени, то не используйте числа с плавающей запятой. Используйте, например, двоичный поиск с возведением в степень. Существуют более быстрые алгоритмы (например, итерация Newton), но если вы используете их на целых числах, тогда вам нужно написать собственную логику, чтобы найти точное решение, как только они перестанут сходиться.

  • 0
    Спасибо, я уже попробовал это, но получил TLE.
  • 0
    Что означает TLE?
Показать ещё 3 комментария
0

В вашей программе есть две проблемы:

  1. Перегрузка pow(int, int) больше недоступна. Чтобы избежать этой проблемы, введите первый параметр в double, float или long double.

  2. Кроме того, команда cout округляет ваш ответ в верхней крыше (3.something на 4), и сохранение ваших данных удаляет всю десятичную часть и принимает только целую часть.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню