2014-02-02 1 views
0

Общий вопрос о функции pow в объективе-c.Объектив C функция функции смещения точности

Почему следующий код выплюнуть ANS = 4,9999999, когда база = 125

NSDecimalNumber * base = [[NSDecimalNumber alloc ]initWithString:@"125"]; 
NSDecimalNumber * root = [[NSDecimalNumber alloc] initWithString:@"3"]; 
double ans=pow(125, 1.0/[root doubleValue]); 

и ровно 3, когда основание = 27

NSDecimalNumber * base = [[NSDecimalNumber alloc ]initWithString:@"27"]; 
NSDecimalNumber * root = [[NSDecimalNumber alloc] initWithString:@"3"]; 
double ans=pow(125, 1.0/[root doubleValue]); 
+1

Предполагается, что это 'double ans = pow ([base doubleValue], 1.0/[root doubleValue]);'? Ни один из ваших вычислений не использует 27. –

ответ

5

Есть несколько факторов, на работе здесь. Самое главное, 1.0/3.0 не совсем одна треть, так что вы находитесь не вычисляет корень куба base. Вместо этого, вычисление, которое вы определили это:

base**0.333333333333333314829616256247390992939472198486328125 

или

exp(0.333333333333333314829616256247390992939472198486328125 * log(base)) 

Когда base является 125, точный результат реального числа этого расчета является:

4.999999999999999553291243227753830961690873860134487744... 

Два ближайшими представляемыми двойниками к этому значению являются 5.0 и:

4.99999999999999911182158029987476766109466552734375 

Последнее значение едва приближается к математически точному результату, поэтому функция pow вернула наилучший ответ (или «правильно округленный»).

Когда вы делаете то же вычисление с base равным 27, то результат математически точный реальный номер:

2.99999999999999981704430129767885583952101310176125736... 

В этом случае, это число несколько ближе к 3.0, чем в любой другой представимыми двойной, поэтому снова pow вернул наилучший результат.

Так что в этих случаях функция pow дает вам самые точные возможные результаты для вычислений, которые вы предложили. Теперь, при этом, нет никакой гарантии, что pow делает это для всех возможных входов (и вообще, в общем, это не так). Вы не получите таких точных результатов для всех входов, и вы получите значительно менее точные результаты для многих входов на некоторых платформах. В общем, вы не должны зависеть от округления последней бит функции pow или от любой функции, которая явно не определена для получения корректно округленных результатов.

Вкратце: результаты, полученные вами, являются наилучшими возможными результатами, а на некоторых других платформах вам не повезет.


Альтернативы:

  • Вы могли бы рассмотреть возможность использования функции cbrt, которая также не гарантирует правильное округление, но по крайней мере вычисления кубического корня, а не 0.3333333333333333148296 ... ю степень.

  • Если вы знаете априори, что результат должен быть целым числом, вы можете округлить его до ближайшего целого с помощью функции round или rint.

  • Если вам действительно нужно точное округление последнего бита, рассмотрите возможность использования библиотеки CRLibm. Это придет с некоторыми издержками, но если вы абсолютно должны иметь правильное округление, это единственный хороший вариант (но обратите внимание, что он даст точно такие же результаты для этих конкретных примеров).

+0

Из упомянутых альтернатив в конечном итоге идет функция cbrt. –