Итак, я пытаюсь сделать pow (x, y). Где x и y - беззнаковые длинные, а результат сохраняется в беззнаковом длинном. Этот результат будет меньше, чем 2 ^ 63, поэтому я смогу это сделать. Но поскольку он возвращает число с плавающей запятой, я получаю неточные результаты для больших чисел. Есть ли способ получить точный результат без использования внешних библиотек, таких как bignum? Я знаю, что мог бы просто сделать x*x в Y раз, но я стараюсь избегать этого, потому что пытаюсь сделать свою программу быстрее.
Pow точность с unsigned long
Ответы (3)
Функция pow возвращает двойное значение, у которого есть проблемы с точностью, и когда вы будете приводить его к длинному значению, вы наверняка получите проблему с точностью. Насколько я знаю, если вы не используете библиотеку, невозможно получить точный результат, используя только функцию pow.
Вы также можете посмотреть Возведение в степень путем возведения в квадрат, а также посмотреть барак-манос answer, где вы можете попытаться реализовать свою собственную функцию pow как
unsigned long long pow(unsigned long long x,unsigned int y) { unsigned long long res = 1; while (y > 0) { if (y & 1) res *= x; y >>= 1; x *= x; } return res; }
10000^10000
не меньше, чем 2^63
, так что у вас будут другие проблемы с этим. Помимо того факта, что вам потребуется (приблизительно) 125 других вселенных, чтобы хранить все эти цифры.
- person Jongware; 22.10.2015
10000^10000
больше, чем 2 ^ 63, но все равно легко поместится на веб-странице, хотя и не в комментарии: за 1
следует 40000 0
s.
- person chqrlie; 22.10.2015
10000^10
, согласно калькулятору Google, равно 1e+40
. Это 10³¹ Гб — немного многовато для веб-страницы, а обсуждаемое число на целый гугол больше.
- person Jongware; 22.10.2015
x=10000
и y=10000
, но формула довольно запутанная. 10000^10000
в базе 10 имеет ровно 40001 цифру. Это намного больше, чем 10000^10
, почти в 1000 раз больше цифр, но все равно умещается на веб-странице.
- person chqrlie; 22.10.2015
unsigned long long pow(unsigned long long x,unsigned int y) ...
— хороший способ вызвать неприятные ошибки. C не имеет сигнатур для функций с тем же именем. Это маскирует/скрывает стандартный `double pow( double, double ); функция.
- person Andrew Henle; 22.10.2015
pow
по определению неточен. Он использует exp(y*log(x))
как способ эмулировать x ^ y
. Если вам нужна полная точность, вам нужно либо использовать внешнюю библиотеку, либо создать собственную версию pow
.
Я не уверен в вашем коде. Но я думаю, ваш код такой
unsigned long x,y;
x=...//
y=...//
unsigned long res=pow(x,y);
Это неправильно. Потому что pow() всегда возвращает тип double.
double pow(double x, double y)
вот почему у вас есть номер двойного типа.
Чтобы получить правильный номер, вы можете сделать следующее:
unsigned long x,y;
x=...//
y=...//
unsigned long res=(unsigned long)pow(x,y);
pow
правильно объявлено через #include <math.h>
, первый вариант не представляет проблемы, преобразование в unsigned long
является неявным, и компилятор будет генерировать правильный код. И наоборот, если pow
не объявлено, добавление явного преобразования ничего не меняет: компилятор предположит, что функция имеет прототип int pow(int,int);
, и сгенерированный код будет совершенно неправильным.
- person chqrlie; 26.10.2015
pow
делаетexp(y*log(x))
, что быстро, но есть проблемы с точностью. - person Breaking not so bad   schedule 22.10.2015x
иy
таковы, что результат будет достаточно мал, или вы подразумеваете модульную арифметику? Если вы проверите, чтоx
равно0
или1
, у вас должно быть не более 61 умножения с циклом грубой силы, даже не заслуживающим оптимизации. - person chqrlie   schedule 22.10.2015unsigned long pow(unsigned long x, unsigned long y);
какy
кратноеx
? - person Paul Evans   schedule 23.10.2015