Нужно Pow (-1,1,2), чтобы быть 1 - PullRequest
3 голосов
/ 13 июня 2011

Я использую math.h с GCC и GSL. Мне было интересно, как получить это, чтобы оценить?

Я надеялся, что функция pow распознает pow (-1,1.2) как ((-1) ^ 6) ^ (1/5). Но это не так.

Кто-нибудь знает библиотеку c ++, которая распознает их? Возможно, у кого-то есть подпрограмма разложения, которой он мог бы поделиться.

Ответы [ 6 ]

11 голосов
/ 13 июня 2011

Математически, pow(-1, 1.2) просто не определено. Нет степеней с дробными показателями отрицательных чисел, и я надеюсь, что нет библиотеки, которая просто вернет какое-либо произвольное значение для такого выражения. Будете ли вы ожидать такие вещи, как

pow(-1, 0.5) = ((-1)^2)^(1/4) = 1

что явно не желательно.

Более того, число с плавающей запятой 1.2 даже не совсем равно 6/5. Ближайшее число двойной точности к 1.2 равно

1.1999999999999999555910790149937383830547332763671875

Учитывая это, какой результат вы ожидаете сейчас для pow(-1, 1.2)?

9 голосов
/ 13 июня 2011

Если вы хотите увеличить отрицательные числа до степеней, особенно дробных, используйте метод cpow().Вам нужно будет включить <complex>, чтобы использовать его.

3 голосов
/ 13 июня 2011

Похоже, вы ищете pow(abs(x), y).


Объяснение: вы, кажется, думаете с точки зрения

x y = (x N ) (y / N)

Если мы выберем это N === 2, то у вас будет

(x )2 ) y / 2 = ((x 2 ) 1/2 ) y

Но

(x 2 ) 1/2 = | x |

Подстановка дает

| x ​​| y

Это растяжение, потому что вышеупомянутые манипуляции работают только для неотрицательного x, но вы тот, кто решил использовать это предположение.

1 голос
/ 13 июня 2011

pow(a,b) часто считается, определяется и реализуется как exp(log(a)*b), где log(a) - натуральный логарифм a.log (a) не определен для <= 0 в действительных числах.Поэтому вам нужно либо написать функцию с особым регистром для отрицательного а и целого числа <code>b и / или b=1/(some_integer).Для целого числа b особый случай прост, но для b=1/(some_integer) он склонен к проблемам округления, как указывал Свен Марнах.

Может быть, для вашего домена pow(-a,b) всегда должно быть -pow(a,b)?Но тогда вы просто реализуете такую ​​функцию, поэтому я предполагаю, что вопрос требует большего объяснения.

Как и предполагал duskwuff, гораздо более надежное и «математическое» решение состоит в использовании сложных функций log и exp, но это намногоболее "сложный" (извините за каламбур), чем кажется на первый взгляд (хотя есть функция cpow).И это будет намного медленнее, если вам придется вычислять много pow () s.

Теперь есть важный улов с комплексными числами, которые могут или не могут иметь отношение к вашей проблемной области: когда все сделано правильно,результат pow(a,b) - это не одно, а часто несколько комплексных чисел , но в тех случаях, которые вас интересуют, одним из них будет комплексное число с почти нулевой мнимой частью (это будет не- ноль из-за ошибок округления), которые вы можете просто игнорировать и / или не вычислять в своем коде.

Чтобы продемонстрировать это, рассмотрите, что такое pow(-1,.5).Это число X такое, что X^2==-1.Угадай, что?Есть 2 таких числа: i и -i.Как правило, pow(-1, 1/N) имеет ровно N решений, хотя вас интересует только одно из них.

Если мнимая часть всех результатов pow(a,b) значительна, это означает, что вы передаете неправильные значения,Для значений с плавающей запятой одинарной точности в диапазоне, который вы описываете, 1e-6 * max (abs (a), abs (b)) будет хорошей отправной точкой для определения «достаточно значительного» порога.Крайние «неправильные значения» будут pow(-1,0.5), которые будут возвращать 0 + 1i (0 в реальной части, 1 в мнимой части).Здесь мнимая часть огромна относительно входной и реальной части, так что вы знаете, что испортили свои входные значения.

В любой разумной реализации с одним возвращаемым результатом cpow(), cpow(-1,0.3333), вероятно, вернет что-то вроде -1+0.000001i и проигнорирует два других значения со значительными мнимыми частями.Так что вы можете просто принять это реальное значение, и это ваш ответ.

1 голос
/ 13 июня 2011

Звучит так, будто вы хотите выполнить сложную мощность (cpow()), а затем взять величину (abs()) этого значения после.

>>> abs(cmath.exp(1.2*cmath.log(-1)))
1.0
>>> abs(cmath.exp(1.2*cmath.log(-293.2834)))
913.57662451612202
0 голосов
/ 13 июня 2011

Используйте std::complex.Без этого корни единства не имеют особого смысла.С этим они имеют большой смысл.

...