Комментарии 60
Потому что в математике возведение в степень правоассоциативно
Matlab, например, считает по другому: https://github.com/wyfinger/WEL-Script/wiki/Power-function-priority
Возможно из за того что: (a^b)^c = a^(b*c)
Если модуль не планируется брать, то следует выбирать оператор возведения в степень **
. Потому что использование встроенной функции pow
требует сначала найти её по имени, а потом уже вызвать. Вы можете вообще присвоить в имя pow
что-то своё, так работает Питон. Поэтому сначала из переменной берётся ссылка на функцию, и потом эта функция вызывается. А оператор таких телодвижений не требует, он вызывается сразу. Хотя у разных интерпретаторов Питона могут быть разные оптимизации, где-то может и не будет разницы и код скомпилируется в одно и то же. Но по классике разница есть и какие-то доли процента производительности на этом можно выиграть. Очень рекомендую модуль dis
, много интересного можно узнать, сравнивая похожий с виду код, во что он реально компилируется.
общепринятого символа каретки
^
Теперь общепринятый уже, видимо, **
, т.к. Питон, Жаваскрипт и Руби. :)
Теперь общепринятый уже, видимо, **
, т.к. Питон, Жаваскрипт и Руби. :)
Эх, молодежь ;-) Вообще-то в самых первых языках программирования, начиная с фортрана, было именно "**". Символ "^" стап использоваться заметно позже, и до сих пор уступает варианту "**" по количеству выбравших его "языков" (статья там длинная, см. подраздел "В языках программирования"):
x ** y
:Fortran, Ada, Z shell, KornShell, Bash, COBOL, CoffeeScript, FoxPro, Gnuplot, Groovy, JavaScript, OCaml, F #, Perl, PHP, PL / I, Python, Rexx, Ruby, SAS, Seed7, Tcl, ABAP, Mercury, Haskell (для показателей с плавающей запятой), Turing и VHDL.
x ^ y
:
AWK, BASIC, J, MATLAB, Wolfram Language (Mathematica), R, Microsoft Excel, Analytica, TeX (и его производные), TI-BASIC, bc (для целых показателей), Haskell (для неотрицательных целых показателей), Lua и большинство систем компьютерной алгебры.
А "второй древнейший" так и вовсе только через библиотечную функцию... Ну и особенно весело с бейсиком: там разные диалекты использовали разные символы ;-)
Думаю, оно из литературы "общепринятое", да.
В лагере x ^ y
еще Julia вроде.
Вот молодежью меня давненько не величали, спасибо :з
Эх, молодежь ;-) Вообще-то в самых первых языках программирования, начиная с фортрана, было именно "**". Символ "^" стап использоваться заметно позже, и до сих пор уступает варианту "**" по количеству выбравших его "языков" (статья там длинная, см. подраздел "В языках программирования"):
Эх, молодежь! 😁
Вапще-то эти символы одновременно появились - в Фортране и Алголе. Но Фортран был разработан IBM и использовал символы их клавиатуры - поэтому там был **.
А Алгол разработали в Швейцарии научным консорциумом - и там в качестве возведения в степень использовали стрелочку ↑. И у них из-за этого даже был конфликт с IBM, когда учёные его просили включить Алгол в их системы OS/2, потому что на клаве их компа не хватало символов для Алгола. Поэтому Америка осталась на айбиэмовском Фортране, а в Европе больше стал распространен Алгол.
Дальше уже дядя Кнут подобрал эту стрелочку и придумал из неё гипероператоры, типа тетрации. И те, кто читали Кнута, стали юзать стрелочки в степенях. А те, кто не читали - звёздочки 😁
Эх, молодежь ;-) Вообще-то в самых первых языках программирования, начиная с фортрана, было именно "**". Символ "^" стап использоваться заметно позже, и до сих пор уступает варианту "**" по количеству выбравших его "языков" (статья там длинная, см. подраздел "В языках программирования"):
Эх, молодежь! 😁
Вапще-то эти символы одновременно появились - в Фортране и Алголе. Но Фортран был разработан IBM и использовал символы их клавиатуры - поэтому там был **.
А Алгол разработали в Швейцарии научным консорциумом - и там в качестве возведения в степень использовали стрелочку ↑. И у них из-за этого даже был конфликт с IBM, когда учёные его просили включить Алгол в их системы OS/2, потому что на клаве их компа не хватало символов для Алгола. Поэтому Америка осталась на айбиэмовском Фортране, а в Европе больше стал распространен Алгол.
Дальше уже дядя Кнут подобрал эту стрелочку и придумал из неё гипероператоры, типа тетрации. И те, кто читали Кнута, стали юзать стрелочки в степенях. А те, кто не читали - звёздочки 😁
На самом деле все проще. До появления ASCII в 1963 году, ещё с лохматого 1928 года была популярна шестибитная кодировка BCDIC и её вариации, в которой, по понятным причинам, символа ^ просто не было. Даже в восьмибитном EBCDIC символа ^ в стандарте не было. Так же, как и в ДКОИ. Отсюда и возведение в степень **.
Мне довелось застать ЕСовские АЦПУ, которые символа ^ просто не знали.
А компилятор питона не может сам оптмизировать x ** y % z
до вызова pow(x, y, z)
если тот вариант более производительный? Выглядит как элементарная peephole-оптимизация
Такой оптимизации нет.
Интерпретатор)
Ну там как-то хитро. Вроде и интерпретатор, а вроде и компилируется исходник в какой-то промежуточный код. )
Cреда исполнения CPython состоит из компилятора, который преобразует исходный текст в байт-код (который даже можно сохранить в файл .pyc
), а также виртуальной машины, которая этот код дальше интерпретирует. Оптимизацию, о которой я говорил выше, было бы вполне уместно делать именно на уровне компилятора, хотя и в ВМ тоже можно
Выглядит как элементарная peephole-оптимизация
Возможно, что в интерпретаторе с динамической типизацией такие оптимизации не так уж и просто и безопасно реализовать.
Кстати, вот просто взял и проверил. В pow
третий аргумент доступен только для целых чисел.
Во-первых, не x ** y % z
, a (x**y)%z
. Во-вторых, может, но не хочет.
Вероятно, много геморроя, а запроса народного на это дело нет. К примеру, вот определили %
почти как fmod()
, а толку то? Народ не пользуется. Аналогично, (2.3**4.5)%math.pi
написать можно, а pow(2.3, 4.5, math.pi)
нельзя, ибо на хрен оно не надо, всё равно будут писать как в C/C++: math.fmod(pow(2.3, 4.5, math.pi)).
Кроме того, однако, до сих пор нет же оптимизации даже pow(x, y)
до x**y
., а Вы на (x**y)%z замахнулись. Улита едет, когда-то будет, быть может JIT компиляция это сможет, ну когда-нибудь.
Как известно, вещественные числа (тип float) не обладают высокой точностью и имеют ограниченный диапазон значений в отличие от тех же целых чисел (тип int).
Даже не знаю, как это можно прокомментировать. Наверное, автору стоит вернуться к изучению базовых типов.
А что не так то? В Питоне встроенный int
реально бесконечный тип, насколько я понимаю. А у float
и точность и диапазон ограничены выделенными на него байтами.
Теперь мне интересно, что имел в виду комментатор.
А как можно сравнить точность целого числа и вещественного? Может, действительно я чего-то не понимаю.
К примеру, в C++ для измерения точности есть std::numeric_limits<T>::digits10
, и, обычно, для int
- 9, а для double
- 15. В Python для float
есть sys.float_info.dig
, который тоже, обычно 15. А вот для int
его нет, поскольку, формально, он бесконечность, есть только sys.int_info.default_max_str_digits
, но это только для печати, а не для операций, к тому же его можно менять по ходу пьесы.
А неформально, точность int
в Python, обычно, насколько хватит памяти, ssize_t
цифр по 32 бита каждая, это до хрена ж.
Так они возвращают не точность, а мощности, диапазоны и границы.
MANT_DIG и EPSILON можно назвать точностью, по ним целые проигрывают, если для них найти аналогичные по сути значения.
Начнём с общепринятого, в котором мы, надеюсь, согласны. Общепринято, что при операциях вида:
float f = 244140625; // ipow(5, 12);
double d = 298023223876953125L; // lpow(5L, 25L);
Ну, или для Python:
f = float(5**25)
Происходит потеря точности (loss of precision) и может возникать исключение "inexact exception".
Поэтому обчуждаемая фраза автора:
Как известно, вещественные числа (тип float) не обладают высокой точностью и имеют ограниченный диапазон значений в отличие от тех же целых чисел (тип int).
Была совершенно корректна и не противоречит общепринятым воззрениям.
Он, к моему сожалению, её сейчас исправил на вариант:
Как известно, вещественные числа (тип float) имеют ограниченный диапазон значений в отличие от тех же целых чисел (тип int). Поэтому если результат возведения в степень окажется достаточно большим, то это приведет к возникновению ошибки переполнения.
Что менее корректно. Поскольку, да, в операции вида math.pow(5, 678)
происходит переполнение в отличии от 5**678
, но в операциях вида math.pow(5, 67)
как раз переполнения-то и не происходит, а происходит потеря точности, в отличии от 5**67
.
Что же касается вашего вопроса:
А как можно сравнить точность целого числа и вещественного?
Как известно, "точность" понятие многогранное. И, лично мне, не встречалось его формального определения. Обычно, и математики, и авторы стандартов формально определяют некоторые более узкие характеристики объектов.
Как я уже писал, к примеру, C++ определяет число значащих цифр (и число значащих бит). и для целых, и для плавающих. А число значащих цифр, это одна из возможных характеристик точности, так что сравнение возможно.
В принципе, в далёкие времена, в ЭВМ реализовали, либо целую, либо плавающую арифметику. Скажем, ЕМИП, в БЭСМ-4 было так, поэтому у целых и плавающих было одинаковое число значащих цифр, но сейчас, обычно они отличаются.
Для Python, IMHO, вполне себе можно говорить, что тип int
имеет неограниченное число значащих цифр или даже бесконечное число значащих цифр, а если совсем неформально, то и вообще - бесконечную точность.
Я вас правильно понял, так как в операциях с числами с плавающей точкой происходит loss of precision, а с целочисленными такого не происходит, целочисленный тип обладает большей точностью? То есть, тип, не обладающий таким свойством, точнее того, что обладает?
И как, если сам термин «точность» не определен в нашем разговоре, мы можем говорить о более высокой точности одних по сравнению с другими, я никак не возьму в толк. Мы описываем наши ощущения и впечатления?
Я вас правильно понял, так как в операциях с числами с плавающей точкой происходит loss of precision, а с целочисленными такого не происходит
Потеря точности, в данном случае, происходит при преобразовании из целого в плавающее:
double d = 298023223876953125LL; // llpow(5LL, 25LL);
Типа, если есть чего терять, то стало быть её (точности) было много, а стало мало! 😉
И как, если сам термин «точность» не определен в нашем разговоре, мы можем говорить о более высокой точности одних по сравнению с другими, я никак не возьму в толк.
Если мы возьмём число значащих цифр по C++, в качестве одной из общепринятых характеристик точности, то вполне можем не только сравнить, но даже упорядочить по числу значащих цифр.
Мы описываем наши ощущения и впечатления?
Мы обсуждаем ваш некорректный и, к сожалению, деструктивный комментарий:
Даже не знаю, как это можно прокомментировать. Наверное, автору стоит вернуться к изучению базовых типов.
Который, увы, привёл к тому, что, на настоящий момент, из статьи вообще исчезло указание на то, что при выполнении функции math.pow(x, y)
может происходить потеря точности без возникновения исключений.
Учитывая общепринятый стиль обработки ошибок Python: нет исключения - нет ошибки, сиё может привести к вредным заблуждениям.
Речь о том, сколько значащих цифр сохраняется точно. И какое минимальное и максимальное число может быть помещено в данный тип. Так вот целые числа в Питоне ограничены только доступной памятью, как тут уже писали. А числа с плавающей точкой ограничены стандартом. Есть даже много сайтов на эту тему, например https://0.30000000000000004.com/
Так и не могу понять, почему количество чисел называется точностью, а не диапазоном или чем-нибудь подобным. Видимо, по определению термина в данной сфере.
Диапазон - это когда мы говорим, что в данном типе могут быть представлены скажем числа от -1e100
до 1e100
. А точность - это когда мы говорим, что точно могут быть представлены скажем 6 значащих цифр. Это значит, что числа 123456
или 1.23456
могут быть представлены в данном типе точно, а вот 1234567
или 1.234567
уже могут не сохранить правильно последнюю цифру и превратятся в 1234566
и 1.234566
или в 1234568
или 1.234568
. Или не превратятся - как повезёт, но гарантии сохранности данных в точности для 7 значащих цифр уже нет. Так что диапазон и точность - это разное. Число 1.23456789012345678901234567890
может прекрасно входить в диапазон чисел, представимых данным типом, но представить это число точно данный тип не может, после какого-то знака довольно быстро начнётся отсебятина.
А для целочисленного типа как определяется точность?
Пожалуй, для целых чисел точно представим весь диапазон чисел, который они могут сохранить, т.е. для них точность и диапазон - это одно и то же. Но если вы прочтёте исходную цитату, на которую вы отвечали, то она написана в этом смысле достаточно корректно. Там насчёт целых чисел упомянут только диапазон.
Пожалуй, для целых чисел точно представим весь диапазон чисел, который они могут сохранить
И для вещественных это верно ведь. Те числа, которые не представимы точно, мы сохранить не можем в данном смысле.
для них точность и диапазон - это одно и то же
А есть общее определение точности, применимое и к тем, и к другим? Как иначе их вообще можно сравнивать по такому признаку.
вещественные числа (тип float) не обладают высокой точностью ... в отличие от тех же целых чисел
Прочитал, все ещё не могу понять.
Те числа, которые не представимы точно, мы сохранить не можем в данном смысле.
Ну тогда все эти float
можно выкидывать вообще )) Почитайте вот это хотя бы: https://habr.com/ru/articles/541816/ Если мы 0.1 + 0.2
не можем с абсолютной точностью во float
посчитать как 0.3
, это не значит, что float
вообще бесполезный тип. У него есть границы применимости, и особенности, о которых нужно просто помнить.
Ну тогда все эти float можно выкидывать вообще ))
Я сделал вывод из ваших утверждений, чтобы как раз и показать их противоречивость. Я в курсе, что вывод абсурдный, вы или укажите на ошибочность моего логического построения, или откажитесь от того вашего утверждения, на котором оно базируется.
Что именно вы опровергаете? Я наверное тупой, я не понимаю. Давайте вернёмся к исходному утверждению из поста:
Как известно, вещественные числа (тип float) не обладают высокой точностью и имеют ограниченный диапазон значений в отличие от тех же целых чисел (тип int).
Это по сути два отдельных утверждения, соединённых союзом и:
Как известно, вещественные числа (тип float) не обладают высокой точностью
С чем здесь спорить? Тип float
действительно имеет ограниченную точность, весьма не высокую. Для большей точности в библиотеках Питона есть другие типы, например numpy.float128
или decimal.Decimal
.
и имеют ограниченный диапазон значений в отличие от тех же целых чисел (тип int).
Тип float
действительно имеет ограниченный диапазон значений - примерно от -1.8e+308
до 1.8e+308
. А если в мелкие по абсолюту числа пойти, то там ограничение примерно 2.2e-308
. У целых чисел Питона нет таких формальных ограничений. Пока физической памяти хватит для хранения числа, Питон будет хранить целое число. Хорошо, тут можно поспорить, что ограничение есть - размер памяти. Но такие целые числа мало кому нужны по идее.
Итак, с чем именно вы спорите?
А, вы так читаете? Я читаю вот так
вещественные числа (тип float) не обладают высокой точностью... в отличие от тех же целых чисел
Если читать по-вашему, то все корректно.
Тогда тут проблема в неоднозначном синтаксисе, однородность членов можно и так, и так трактовать.
Самая явная неточность типа float
уже в том, что не известно хранящееся в этом формате число четное или нечетное, когда мантисса заполнится.
возведение в степень по модулю - базовая и безопасная вещь при работе с битовыми полями - и принципиальным здесь является то, что модуль берется внутри функции
Есть ещё способ возведения в степень - используя цикл (но лишаясь при этом кода в одну строчку, увеличивая время выполнения подсчётов и возможности возведения в несколько разных степеней в простой реализации цикла).
А каким из трех способов лучше и быстрее найти полную десятичную запись числа 5 ** 9500000000? Подскажите, пожалуйста.
А зачем вам такое? Питон по идее такое наверное посчитает, но тут даже если последние 3 нуля отрезать, то считается 6 секунд и в результирующем числе получается 6640216
цифр. И время счёта растёт экспоненциально с каждым нулём. Куда вы все эти цифры девать будете? Судя по прогрессу, в искомом вами результате будет порядка 7 миллиардов цифр.
5 ** 95 -> 67 цифр за 0.00 сек.
5 ** 950 -> 665 цифр за 0.00 сек.
5 ** 9,500 -> 6,641 цифр за 0.00 сек.
5 ** 95,000 -> 66,403 цифр за 0.00 сек.
5 ** 950,000 -> 664,022 цифр за 0.16 сек.
5 ** 9,500,000 -> 6,640,216 цифр за 6.15 сек.
Так и да, однако, для числа цифр прогресс не нужен ceil(9500000000*math.log10(5))/1e9
.
А вот насчёт "экспоненциально" это Вам показалось. Вроде как, чистый Python использует алгоритм Карацубы, так что потребное время
, менее чем квадратично. А в абсолютных цифрах, на вашем компьютере, составит 4 дня. 😉
Именно ? А Вы, собственно, почему интересуетесь? Вы не из милиции, случайно?
Собственно, в чистом Python, что для , что для
, применимы только два способа из трёх:
**
и pow()
. Правда, на ноутбуке, для вашего странного числа потребуется два-три гигабайта ОЗУ для результата и два-три месяца.
Однако, можно за несколько часов выбрать и поставить какую-нибудь надстройку над Python, к примеру, sage
, которая будет умножать целые числа, уже не сравнительно простым методом Карацубы (), оптимальным для больших чисел более менее встречающихся в реальной жизни, а чем-нибудь самым продвинутым c
. Тогда, и
**
, и pow()
, справятся за две-три минуты.
P.S. Я лажанулся и немного преувеличил, не два-три месяца, а несколько дней.
ekvant-24-03.pdf Журнал "Квант" третий номер 2024 года.
7. Укажите явно такую степень пятерки, что в ее десятичной записи встретится подряд более 1000 нулей. А такую, чтобы встретилась комбинация ровно из 1000 нулей, идущих подряд?
8. Докажите, что найдется степень тройки, которая начинается теми же 1000 цифрами, что и кончается.
Первая же прикидка степени для 7-й задачи дает степень 9950000000. Думал, что для Python на современном компьютере проблем с таким числом быть не должно. Но практика показала, что ни нормального решения, ни нормального времени решения такой задачи никто не знает. Время должно быть не более 7 секунд на вычисление и не более минуты для сохранения на диск с проверкой условия этой задачи.
Для примера: 5**10000000 - 6 нулей, 5**20000000 - 7 нулей и далее... По идее, надо знать точно log10(5), и без sage тут решение об увеличении степени принять нельзя.
Хм, как бы, три вопроса, не один вопрос, стало быть очень надо, но...
на современном компьютере проблем с таким числом быть не должно
Как бы, увы. Оказалось, что Вы плохо представляли современные компьютеры. Всё что хреново распараллеливается, всё нешустро.
Для примера:
- 6 нулей,
- 7 нулей и далее...
Как бы, да, казалось бы (1000-6)*10_000_000
, но, увы, для инженерной индукции - неудачный день.
Похоже, морковка висит гораздо дальше, ну, или, полоть надо гораздо плотнее (что тоже самое). Так и что мы можем сделать за пару минут?
import decimal
import math
import time
t = []
for b, p in [(5, (2**n)*10_000_000) for n in range(8)]:
#(5, 9_950_000_000)
pl10b = math.ceil(p*math.log10(b))
with decimal.localcontext(prec = pl10b, Emax=pl10b) as ctx:
t.append(time.process_time())
bp = decimal.Decimal(b)**p
t.append(time.process_time())
print(f"{b: 3} {p: 14_} time bp: {t[-1] - t[-2]: .3}")
sbp = str(bp)
t.append(time.process_time())
print(f"{b: 3} {p: 14_} time sbp: {t[-1] - t[-2]: .3}")
l = 0
while sbp.find('0'*(l+1)) >= 0:
l += 1
t.append(time.process_time())
print(f"{b: 3} {p: 14_} {l: 4} time find('0'*(l+1)): {t[-1] - t[-2]: .3}")
5 10_000_000 time bp: 0.443
5 10_000_000 time sbp: 0.0217
5 10_000_000 6 time find('0'*(l+1)): 0.0055
5 20_000_000 time bp: 0.832
5 20_000_000 time sbp: 0.026
5 20_000_000 7 time find('0'*(l+1)): 0.00833
5 40_000_000 time bp: 1.67
5 40_000_000 time sbp: 0.0497
5 40_000_000 8 time find('0'*(l+1)): 0.0305
5 80_000_000 time bp: 3.42
5 80_000_000 time sbp: 0.107
5 80_000_000 8 time find('0'*(l+1)): 0.058
5 160_000_000 time bp: 7.22
5 160_000_000 time sbp: 0.297
5 160_000_000 9 time find('0'*(l+1)): 0.111
5 320_000_000 time bp: 14.9
5 320_000_000 time sbp: 0.618
5 320_000_000 8 time find('0'*(l+1)): 0.142
5 640_000_000 time bp: 31.2
5 640_000_000 time sbp: 1.31
5 640_000_000 8 time find('0'*(l+1)): 0.275
5 1_280_000_000 time bp: 64.8
5 1_280_000_000 time sbp: 2.62
5 1_280_000_000 9 time find('0'*(l+1)): 0.84
Но, это и правильно, это ж задачи для воспитания подрастающего поколения, более менее, умных школьников, которым, пока ещё, в индивидуальном порядке, предстоит распараллеливать последние задачи этого мира. 😉
Если нужно именно десятичную запись, то лучше (проще) реализовать длинную арифметику самому. Потому что в Python (как и в Java/C#/JS и других популярных решениях) длинные числа хранятся по основанию 2 (технически - по основанию 2**32, но это неважно). И число 5 ** 9500000000 в таком виде займёт порядка 2,6 ГБ - что, кстати, само по себе может стать проблемой (Java и C# откажутся работать с такими в принципе, Python, насколько я знаю - сможет). Но после вычисления его еще надо вывести, а вот тут надо будет делить много раз на 10**n. В нынешнем Python по умолчанию ограничение 4300 цифр на такое преобразование. Но я бы и не пытался - деление в таких числах противная операция.
Если так припекло посчитать такую необычную операцию, то проще самому реализовать арифметику с основанием степени 10 (10**9, например - отличный выбор). Сложение "столбиком", умножение "столбиком" (для небольших чисел) и умножение Карацубы (для чисел больше 10**100) - задача на пару вечеров. Зато преобразование в десятичную запись линейное по времени и константа по дополнительной памяти.
PS: но я таки, как и предыдущие комментаторы замечу, что мне сложно представить задачу в которой это понадобилось бы.
Хм, как в воду глядели! 😉
Мало того, оказалось, что у Python 3.12 целочисленная арифметика реализованная в decimal
шустрее реализации int
. Единственное неудобство в том, что для decimal
надо заранее указать требуемое число цифр и максимальное значение. Поэтому в чистом Python 3.12 наилучший способ найти полную десятичную запись числа это
str(decimal.Decimal(5, context=ctx)**9_500_000_000)
.
С внешними пакетами, кто знает? Но мой любимый калькулятор sage не конкурент, ибо двоичный. Хотя у него алгоритмы умножения и возведения на порядок круче, чем у decimal
, но в деле преобразования в строку он пасует.
7. Укажите явно такую степень пятерки, что в ее десятичной записи встретится подряд более 1000 нулей. А такую, чтобы встретилась комбинация ровно из 1000 нулей, идущих подряд?
8. Докажите, что найдется степень тройки, которая начинается теми же 1000 цифрами, что и кончается.
пробовал я Питоне посчитать школьный пример 9 в степени 9 в степени 9 т.е. 9 ** 9 ** 9
Подсчитал он то относительно быстро (отсчет на 140 мегабайт получился), но заставить вывести его в 10-ом виде не получилось - ждать сутками не хотел. Так в бинарном виде сохранил в файл только.
import decimal
import math
b = 9
p = b ** b
with decimal.localcontext() as ctx:
ctx.Emax = math.ceil(p*math.log10(b))
ctx.prec = ctx.Emax + 2
ctx.traps[decimal.Inexact] = True # Исключение при потере точности
p999 = decimal.Decimal(b, context=ctx)**p
sp999 = str(p999)
print(len(sp999), "...", sp999[-20:], "cmp", pow(b, p, 10**20))
369693100 ... 99359681422627177289 cmp 99359681422627177289
7. Укажите явно такую степень пятерки, что в ее десятичной записи встретится подряд более 1000 нулей. А такую, чтобы встретилась комбинация ровно из 1000 нулей, идущих подряд?
8. Докажите, что найдется степень тройки, которая начинается теми же 1000 цифрами, что и кончается.
Как бы, наверное, можно было бы рассматривать средства языка **
и pow()
с одной стороны, и средства стандартной библиотеки math.pow()
и cmath.pow()
. Да, последнее, как бы, незаслуженно забыто.
Кроме того, тема частных случаев возведения в степень Python, x**0.5
и x**(1/3)
против math.sqrt(x)
и math.cbrt(x)
, или скорость против точности, местами, так же не раскрыта.
Сделанное Вами исправление:
Как известно, вещественные числа (тип float) имеют ограниченный диапазон значений в отличие от тех же целых чисел (тип int). Поэтому если результат возведения в степень окажется достаточно большим, то это приведет к возникновению ошибки переполнения.
IMHO, выплеснуло ребёнка с водой из ванны. Этот абзац, возможно и стал менее спорным, но определённо стал менее корректным.
Поскольку, да, в операциях вида math.pow(5, 678)
происходит переполнение (OverflowError: math range error) в отличии от 5**678
, и описание такого варианта осталось.
Но в операциях вида math.pow(5, 67)
как раз переполнения-то и не происходит, и исключений, обычно, не возникает, а происходит потеря точности, в отличии от 5**67
(к примеру, 5**67%7 != math.pow(5, 67)%7
).
В общем, новая редакция этого абзаца норовит ввести в заблуждение, что если нет исключения OverflowError, от всё хорошо, а это не совсем так.
Способы возведения в степень в Python