Использование функции квадратного корня из математического модуля

Я знаю, что могу найти квадратный корень из выражения, используя math.sqrt(x).

Я также знаю, что могу найти квадратный корень с помощью x**0.5.

Но почему оба? Разве это не питонический? Какая польза от math.sqrt(), когда мы можем просто возвести его в 0.5 степень?


person defunct-user    schedule 29.03.2018    source источник
comment
То же самое можно сказать о math.pow(x,2) и x**2.   -  person Dan    schedule 29.03.2018
comment
Вы бы утверждали, что + тоже можно удалить?   -  person Jongware    schedule 29.03.2018


Ответы (2)


Это, по-видимому, уже до полусмерти обсуждалось при переполнении стека. Вот краткое изложение наиболее интересных моментов:

Что быстрее?

Вывод: math.sqrt значительно быстрее в большинстве версий / реализаций Python.

Что более точно?

Заключение: ни то, ни другое, они оба одинаково (с довольно замечательным уровнем точности) плохи несколько по-разному.

Редактировать:

По причинам, обсуждаемым @MarkDickinson в комментариях ниже, информация в приведенном выше вопросе «Какой более точный» является неточной и устаревшей. Что имеет смысл, так как ему почти 10 лет.

Я могу подтвердить, что тесты, перечисленные в принятом ответе, теперь возвращают разные ответы:

    (8885558**0.5)**2: 8885558.000000002
math.sqrt(8885558)**2: 8885558.000000002

                2**1023.99999999999: 1.7976931348498497e+308
(math.sqrt(2**1023.99999999999))**2: 1.7976931348498495e+308
    ((2**1023.99999999999)**0.5)**2: 1.7976931348498495e+308

    ((2**1023.99999999999)**0.5)**2 - 2**1023.99999999999: -1.99584030953472e+292
(math.sqrt(2**1023.99999999999))**2 - 2**1023.99999999999: -1.99584030953472e+292

Попробуйте тесты для себя онлайн < / а>. Я получил те же результаты на онлайн-интерпретаторе, что и на нескольких моих лабораторных машинах (которые, по общему признанию, все x86-64).

Слово бога (т.е. Гвидо)

Гвидо (доброжелательный диктатор на всю жизнь Python) ответил на электронное письмо, отправленное OP на более быстрый вопрос:

pow и ** эквивалентны; math.sqrt не работает с комплексными числами и ссылается на функцию C sqrt (). Я понятия не имею, какой из них быстрее ...

Хотя он прямо не рассматривает причины дублирования, он явно знает об этом и указывает, что, по крайней мере, в некоторых случаях они действительно ведут себя по-разному.

person tel    schedule 29.03.2018
comment
Более точный ответ, на который вы ссылаетесь, глубоко ошибочен. На обычных машинах разумно ожидать, что функция sqrt в конечном итоге будет использовать sqrt процессора (например, SQRTSD на машинах x86-64 с SSE2), которая, вероятно, будет правильно округлена. Было бы довольно удивительно найти случаи, когда sqrt менее точен, чем x**0.5, и совсем не удивительно найти случаи, когда верно обратное. Короче говоря, на типичной машине sqrt будет не менее точным, чем x**0.5, и, скорее всего, будет более точным в некоторых случаях. - person Mark Dickinson; 29.03.2018
comment
@MarkDickinson ¯_ (ツ) _ / ¯ Может быть, этому вопросу уже почти десять лет. Я опробую перечисленные ими тесты на паре машин и опубликую результаты. - person tel; 29.03.2018
comment
Как указано в комментариях к этому вопросу, тесты на самом деле не имеют никакого смысла для определения того, что является более точным. Для этого вам нужно сравнить вывод math.sqrt(x) с истинным квадратным корнем из x, возможно, вычисленным с использованием какого-нибудь пакета с плавающей запятой высокой точности. Затем сделайте то же самое для x**0.5 для тех же значений x. Я только что сделал это на своей машине (MacBook Pro конца 2013 года): из 1000000 случайно сгенерированных чисел с плавающей запятой было 1413, для которых sqrt(x) и x**0.5 различались; sqrt(x) был точнее во всех случаях. - person Mark Dickinson; 29.03.2018
comment
Честно говоря, я обманул маленький бит и не использовал высокоточный пакет с плавающей запятой: если x - это число с плавающей запятой, y - это результат с плавающей запятой для sqrt(x), а z - это < i> истинный квадратный корень (который обычно не может быть точно представлен как число с плавающей запятой), нам нужна ошибка y - z. Это равно (y*y - z*z) / (y + z), что равно (y*y - x) / (y + z), что должно быть очень близко к (y*y - x) / 2y. Последнее количество можно точно рассчитать с помощью fractions.Fraction. Это не совсем строго из-за очень близкого вышесказанного. - person Mark Dickinson; 29.03.2018
comment
Хорошо сделано. Вы также можете записать предпоследний термин как (y*y - x) / (2y + d), где d = z - y. Учитывая, что y велико, 2y >> d и d в основном исчезнут, давая вам ваш последний срок. Это приближение, которое определенно прошло бы проверку в моей области (физике), хотя я не могу не чувствовать, что где-то все еще есть потенциальная ловушка, специфичная для FP. - person tel; 29.03.2018
comment
Ваш более строгий план звучит так, как будто это был бы хороший (и, возможно, несколько сложный) исследовательский проект для кого-то. - person tel; 29.03.2018

Я бы не стал слишком много думать об этом. sqrt - это просто упрощение, если поднять до 1/2; некоторые программисты на Python могут этого не знать, и на мой взгляд, это более идиоматично.

person Brandon Mowat    schedule 29.03.2018