Я знаю из предыдущих тем по этой теме, что использование арифметики 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 и т.д.
Как мне изменить свой код, чтобы правильный результат сохранялся в корневой переменной.
pow возвращает double. Когда используется cout, оно округляется (таким образом, оно равно 4). Когда вы бросаете его в int, он просто обрезает дробную часть. Pow возвращает что-то вроде 4 - eps (из-за точности вопросов). Когда он просто усечен, он равен 3. Грязный взлом полезен в конкурсах программирования: int root = (int)(pow(...) + 1e-7)
(int)round(pow(..,..))
.
Насколько я знаю, в 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), но если вы используете их на целых числах, тогда вам нужно написать собственную логику, чтобы найти точное решение, как только они перестанут сходиться.
В вашей программе есть две проблемы:
Перегрузка pow(int, int)
больше недоступна. Чтобы избежать этой проблемы, введите первый параметр в double
, float
или long double
.
Кроме того, команда cout
округляет ваш ответ в верхней крыше (3.something на 4), и сохранение ваших данных удаляет всю десятичную часть и принимает только целую часть.
(double)
заставляют меня поверить, что вы не знаете правил литералов C ++, операторов и продвижений типов.