Есть несколько факторов, на работе здесь. Самое главное, 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. Это придет с некоторыми издержками, но если вы абсолютно должны иметь правильное округление, это единственный хороший вариант (но обратите внимание, что он даст точно такие же результаты для этих конкретных примеров).
Предполагается, что это 'double ans = pow ([base doubleValue], 1.0/[root doubleValue]);'? Ни один из ваших вычислений не использует 27. –