2015-10-22 4 views
4

Так что я пытаюсь сделать pow (x, y). Где x и y - unsigned longs, и результат сохраняется в unsigned long. Этот результат будет меньше, чем 2^63, поэтому я должен это сделать. Но поскольку он возвращает число с плавающей запятой, я получаю неточные результаты для больших чисел. Нужно ли получить точный результат без использования внешних библиотек, таких как bignum? Я знаю, что могу просто делать x * x a Y раз, но этого я пытаюсь избежать, потому что я пытаюсь сделать свою программу быстрее.Положительная точность с неподписанными длинными

+1

Где ваш код? Вероятно, вам нужно округлить float до ближайшего целого числа. – owacoder

+2

'pow' does' exp (y * log (x)) ', который работает быстро, но имеет проблемы с точностью. –

+2

Это может вас заинтересовать: https://en.wikipedia.org/wiki/Exponentiation_by_squaring – szczurcio

ответ

5

Функция pow возвращает двойное значение, которое имеет проблемы с точностью, и когда вы произведете его до конца, тогда вы, несомненно, получите точность. Насколько я знаю, если вы не используете библиотеку, невозможно получить точный результат, используя только функцию pow.

Вы также можете посмотреть на Exponentiation by squaring, а также посмотреть на Barak Маноса 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; 
} 
+0

Этот метод эффективен для очень больших чисел? Как 10000^10000 (x^y)? потому что я хочу держать значение под 2^63-1 все время.Поэтому я стараюсь приблизиться как можно ближе к 2^63-1, тогда я сделаю свой расчет на этой части, возьму результат и перенесу его на следующий расчет, пока мой у не станет достаточно маленьким, чтобы сделать мой расчет немедленно. – LifeisHard

+2

@LifeisHard: '10000^10000' не меньше' 2^63', поэтому у вас возникнут другие проблемы. Помимо того, что вам понадобится (приблизительно) 125 других юниверсов для хранения всех этих цифр. – usr2564301

+0

@Jongware: '10000^10000' больше, чем 2^63, но все равно легко поместится на веб-странице, хотя не в комментарии: '1', за которым следуют 40000' 0 '. – chqrlie

1

pow по определению неточным. Он использует exp(y*log(x)) как способ эмулировать x^y. Если вам нужна полная точность, вам нужно либо использовать внешнюю библиотеку, либо сделать свою собственную версию pow.

-1

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

unsigned long x,y; 
x=...// 
y=...// 

unsigned long res=pow(x,y); 

Неправильно. Потому что pow() всегда возвращают двойной тип.

double pow(double x, double y) 

вот почему у вас есть номер двойного типа.

Чтобы получить правильный номер, который вы можете сделать так:

unsigned long x,y; 
    x=...// 
    y=...// 

    unsigned long res=(unsigned long)pow(x,y); 
+1

Это не решает проблему OP: «поскольку он возвращает число с плавающей запятой, я получаю неточные результаты для больших чисел». – usr2564301

+0

@ Jongware вы уверены, что значение ** res ** является числом с плавающей запятой. –

+0

Ваше объяснение в замешательстве: до тех пор, пока 'pow' правильно объявлен с помощью' #include ', первый вариант не представляет проблемы, преобразование в' unsigned long' является неявным, и правильный код будет сгенерирован компилятором. И наоборот, если 'pow' не объявлен, добавление явного преобразования ничего не меняет: компилятор будет считать, что функция имеет' int pow (int, int); 'prototype и созданный код будут полностью неправильными. – chqrlie