Возведение числа в действительную степень
Как, никто этого еще не придумал?
Взглянем на исходный код функции Power из модуля Math, любезно предоставленный Borland Software:
Примечательно, что в благих целях оптимизации процессор оставляют наедине с целой толпой ветвлений, приводящих его, в конце концов, в общем случае к пресловутому решению пятиклассника, а именно, к тривиальной формуле
(1) x**y = exp(ln(x**y)) = exp(y*ln(x)).
Что плохого в таком подходе к решению? Во-первых, в набор инструкций FPU не входит ни операция вычисления exp(x), ни взятия натурального логарифма ln(x). Соответственно, результат вычисляется в несколько этапов, в то время как можно пойти более прямым путем, как будет показано ниже. За счет этого падает скорость вычисления; кроме того, здесь действует интуитивное правило, которое грубо можно сформулировать так: чем больше операций выполняется над числом с плавающей запятой в регистрах сопроцессора, тем больше будет и суммарная погрешность результата.
Давайте проведем инвентаризацию. Какие инструкции сопроцессора связаны с возведением в степень или взятием логарифма? Приведу краткую выдержку из [1] и [2]:
Вот, в общем-то, и все. Но уже на первый взгляд этого хватает, чтобы понять, что задача может быть решена более прямо, чем предлагает RTL Borland Delphi.
Действительно, почему не заменить показатель степени в (1) на 2? Ведь неперово число отнюдь не является родным для двоичной арифметики! Тогда получится
Это выражение для x**y в соответствии с вышеозначенными пятью инструкциями можно представить как композицию функций в таком виде:
Так как вычислить f(z) в одно действие невозможно, приходится считать так:
Формулы (4)-(6) естественно выражаются таким ассемблерным кодом:
Перед выполнением этого фрагмента кода нужно убедиться, что биты управления округлением в слове управления FPU установлены в режим округления к нулю. В Delphi это проще всего сделать при помощи функции SetRoundMode (модуль Math):
Так как на процессорах Intel Pentium IV последовательное многократное переключение между двумя (но не более) состояниями слова управления FPU выполняется гораздо быстрее, чем на ранних моделях, можно рассчитывать, что даже в тех ситуациях, когда придется перемежать вызов этого фрагмента кода с действиями, требующими иного режима округления, при работе на современной технике это не приведет к чрезмерным дополнительным временным затратам. Подробности см., например, в [3].
Полный код работоспособной функции на Object Pascal выглядит так:
Имеет смысл создать перегруженные версии функции для различных типов аргументов FLOATTYPE, так как на практике часто главным недостатком встроенной функции является то, что она (как и все вызываемые ею функции) принимает в качестве аргументов действительные числа типа Extended, что приводит к весьма существенным затратам на конвертирование форматов при загрузке в стек FPU.
Эксперименты показали, что предложенный вариант функции возведения в степень повышает точность вычислений на один-два знака после запятой. Так как автору было несколько лень писать медленный код для сверхточного возведения в степень с целью проверки точности предложенного алгоритма, то эксперимент заключался в сравнении результатов со значением, получающемся в стандартном калькуляторе Windows. Если верить его справочной службе, вычисления в нем производятся с точностью до 32 десятичных знаков после запятой, что позволяет полагаться на него как на источник эталонных значений.
К сожалению, выигрыш в скорости абсолютно не ощущается. Это вполне объяснимо: согласно приложению C ( “IA-32 Instruction Latency and Throughput” ) документа [3], из всего этого фрагмента основная вычислительная нагрузка ложится на трансцендентные (ответственность за не вполне корректное применение термина ложится не на меня, а на господ из Intel) операции, а именно – FYL2X, FRNDINT, F2XM1 и FSCALE. Количество же этих операций в предложенном алгоритме и их общее число в реализации функций ln(x) и exp(x) в RTL Delphi одинаково.
Конечно, хотелось бы увеличить и скорость вычислений. Но мир не идеален, и за это придется расплачиваться все той же точностью. Как правило, в каждой ситуации существует предел допустимых погрешностей при расчетах. В иллюстративных целях я задался максимальной допустимой относительной погрешностью 0,0001=0,1%. В действительности, как будет видно из графиков относительной погрешности, удалось достичь еще большей точности.
Дальнейшие наши действия должны состоять в том, чтобы исключить трансцендентные математические операции. Ясно, что всякое представление в виде конечной композиции элементарных арифметических операций некоторой функции, неразложимой в такую композицию, является приближением исходной функции. То есть задача ставится так: нужно приблизить используемые трансцендентные функции композициями элементарных операций, оставаясь при этом в допустимых для погрешности пределах.
Аппроксимация функции 2x
Эта мера позволит нам избавиться сразу и от длительной F2XM1, и от выполняющейся ненамного быстрее FSCALE.
Вот как это сделал я.
Как и для предыдущей функции, нужно обеспечить установку бит управления округлением в режим округления к нулю.
Выполнение этого фрагмента изменяет содержимое регистра EAX.
Если построить график относительной погрешности, становится видно, что в пределах каждого из 1998 отрезков он имеет форму кривой с одним максимумом, сходящей к нулю на концах отрезка. При этом пределы колебаний величины погрешности остаются постоянными на всех отрезках, кроме нескольких последних – на них погрешность возрастает. Если не принимать во внимание эти отрезки, и ограничить область допустимых значений аргумента числом 990 (т.е. x x достаточно показать ее график на двух последних допустимых для значений x отрезках:
Рисунок 1. Максимальная погрешность приближения функции Exp2=2**x (при x менее 990) не превышает 0,004%.
Мы отсекли отрезки, лежащие правее точки x =990. Следовательно, размер таблицы коэффициентов можно несколько сократить: индекс последнего элемента должен быть 990*2=1980, а не 1998. “Лишние” 19 последних строк таблицы можно просто удалить. Логично также изменить текст комментария в начале функции Exp2.
Новый вариант функции возведения в степень
Изменим реализацию возведения в степень в соответствии с предложенной аппроксимацией для 2**x:
В этом фрагменте используется инструкция FCOMIP, впервые появившаяся на процессорах Pentium Pro. Любителям антиквариата придется использовать вместо пары команд FCOMIP / JE блок
Вдобавок в этом случае изменяется регистр EAX.
Результаты тестирования отражены на графиках:
Рисунок 2. Временные затраты: New_Power – новая функция, Power – из состава RTL Borland Delphi.
Подпись X-0.511 на оси абсцисс отражает тот факт, что при проведении испытаний брались значения целые значения X, к которым затем прибавлялось число 0.511, чтобы гарантировать, что основание степени – число нецелое (т.е. чтобы рассматривать по возможности общий случай).
Черная линия поверх красного набора – сглаженные временные затраты функции Power, фиолетовая поверх синего – функции New_Power.
Замеры временных затрат производились с помощью инструкции RDTSC (процессоры начиная с Pentium):
RDTSC возвращает в регистровой паре EDX:EAX число тактов процессора, прошедших с момента последнего сброса (reset). Машинный код инструкции – 0Fh, 31h.
Относительная погрешность ведет себя на удивление стабильно, изменяясь в пределах от 0 до 0,0040%. Поэтому достаточно представительным множеством значений аргумента является, к примеру, промежуток (0, 1000).
Рисунок 3.
В случае показателя степени 17 колебания становятся намного чаще, однако общая картина та же.
Аппроксимация функции log2x и “специализация” возведения в степень
Логарифмирование плохо поддается аппроксимации с помощью кубических сплайнов – точнее, мне удалось это сделать, причем с весьма высокой точностью, но лишь ценой проигрыша по времени в сравнении с использованием FYL2X. Однако здесь есть что предпринять и не прибегая к сплайнам.
Как известно, функция ln(1+x) при |x| ln(1+x)=x-x 2 /(1*2)+x 3 /(1*2*3)+…+ x i /i!+…
Это позволяет построить еще один вариант функции возведения в степень для значений основания, близких к 1. В нем нет инструкции FYL2X, а вместо нее присутствует блок инструкций, помеченных символом “ * ” (знак “
” означает приближенное равенство):
Таким образом, нам в этом случае (при x, близких к 1) удается избавиться от всех инструкций FPU, принадлежащих к группе трансцендентных, что приводит к впечатляющему росту производительности:
Рисунок 4. Временные затраты: New_Power_XNear1 – специализированный вариант New_Power.
К сожалению, с ростом показателя степени максимальная погрешность растет, оставаясь, впрочем, в оговоренных пределах (т.е. меньше 0,1%; более того – меньше 0,01%) даже при очень больших показателях:
Рисунок 5.
Для тех же случаев, когда необходима высокая точность вычислений, в качестве первого камня фундамента была рассмотрена функция, исправляющая недостаток Delphi RTL. Несомненно, это направление также достойно дальнейших исследований с целью ускорить заведомо медленные вычисления с повышенной точностью.
Очень познавательно чтение следующих документов:
Источник
Как написать степень в delphi
Здравствуйте, aleckstein, Вы писали:
A>Не подскажите каким образом в Delphi можно возвести некоторую переменную (или число) в n-ую степень?
Здравствуйте, aleckstein, Вы писали:
A>Не подскажите каким образом в Delphi можно возвести некоторую переменную (или число) в n-ую степень?
| От: | defrag |
Дата: | 09.10.03 13:28 | |
Оценка: | +1 |
Здравствуйте, aleckstein, Вы писали:
A>Не подскажите каким образом в Delphi можно возвести некоторую переменную (или число) в n-ую степень?
Функции Power и IntPower в юните Math
| От: | akasoft |
Дата: | 09.10.03 17:36 | |
Оценка: |
Здравствуйте, aleckstein, Вы писали:
A>Не подскажите каким образом в Delphi можно возвести некоторую переменную (или число) в n-ую степень?
Ну и я влезу. Со старинной формулой, что тянется что-ли с D3. Весь смысл в математике, ну а реализация такова, какова была нужна мне самому.
Вывод: надо учить математику.
| От: | Hacker_Delphi |
Дата: | 09.10.03 18:21 | |
Оценка: |
| От: | s.ts |
Дата: | 10.10.03 06:24 | |
Оценка: |
Здравствуйте, akasoft, Вы писали:
A>Здравствуйте, aleckstein, Вы писали:
A>>Не подскажите каким образом в Delphi можно возвести некоторую переменную (или число) в n-ую степень?
A>Ну и я влезу. Со старинной формулой, что тянется что-ли с D3. Весь смысл в математике, ну а реализация такова, какова была нужна мне самому.
A>
A>Вывод: надо учить математику.
Это точно
| От: | Аноним |
Дата: | 10.10.03 12:01 | |
Оценка: |
Здравствуйте, aleckstein, Вы писали:
A>Не подскажите каким образом в Delphi можно возвести некоторую переменную (или число) в n-ую степень?
Power(Base, Exponent);
or
IntPower(Base, Exponent);
| От: | Dimonka |
Дата: | 10.10.03 12:47 | |
Оценка: |
Здравствуйте, DanilB, Вы писали:
DB>Здравствуйте, aleckstein, Вы писали:
DB>chis = 1;
DB>ch = 2;
DB>for(i = 0; i
DB> chis = chis * ch;
Ваша степень больше на логический сдвиг смахивает..
Poprobuyte ispolzovat’ Automation dlya svyazi s Excel, a v Excel nuzhno sodat’ vremennuyu tablizu iz N stolbzov i soschitat’ proizvedenie.
Edinstvenniy minus takogo podhoda — neobhodimost’ rasprostranyat’ vmeste s programmoy instolnik MS Office. Takim obrazom, predlozhennoe reshenie priemlemo tolko dlya bolshih kommercheskih proektov.
| От: | Sinclair | http://corp.ingrammicro.com/Solutions/Cloud.aspx |
Дата: | 12.10.03 12:04 | ||
Оценка: |
| От: | DanilB |
Дата: | 13.10.03 02:37 | |
Оценка: |
Здравствуйте, Dimonka, Вы писали:
D>Здравствуйте, DanilB, Вы писали:
DB>>Здравствуйте, aleckstein, Вы писали:
DB>>chis = 1;
DB>>ch = 2;
DB>>for(i = 0; i
DB>> chis = chis * ch;
D>Ваша степень больше на логический сдвиг смахивает..
| От: | Аноним |
Дата: | 13.10.03 05:17 | |
Оценка: |
Так точно, господин Злыгостев. А где бы найти нормальный online-перекодировщик, не подскажете? А то вот что выходит:
Попробуыте исползовать Аутоматион для связи с Ехцел, а в Ехцел нужно содать временнуыу таблизу из Н столбзов и сосчитать произведение.
Единственниы минус такого подхода — необходимость распространять вместе с программоы инстолник МС Оффице. Таким образом, предложенное решение приемлемо толко для болших коммерческих проектов.
| От: | Sinclair | http://corp.ingrammicro.com/Solutions/Cloud.aspx |
Дата: | 13.10.03 08:10 | ||
Оценка: |
Попробуйте исползовать Аутоматион для связи с Ехцел, а в Ехцел нужно содать временную таблизу из Н столбзов и сосчитать произведение.
Единственний минус такого подхода — необходимость распространять вместе с программой инстолник МС Оффице. Таким образом, предложенное решение приемлемо толко для болших коммерческих проектов.
| От: | Slicer [Wirkwood] | https://ru.linkedin.com/in/maksim-gumerov-039a701b |
Дата: | 13.10.03 09:58 | ||
Оценка: |
Thanx.
будет день — будет пища, а пока inet из мест общегo пользoвания.
Источник
Создайте кнопку для возведения X в целочисленную степенью написать прогу на delphi с формой
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Создайте кнопку для возведения X в целочисленную степеньY
Помогите пожалуйста решить задачу, знаю что это очень простая задача, но я только начал изучать.
Функция возведения целого числа а в целочисленную степень b
/*Функция возведения целого числа а в целочисленную степень b*/ #include int.
В целочисленном массиве найти и напечатать те элементы, которые являются степенью 2. Написать функцию, проверяющую, является ли число степенью 2.
В целочисленном массиве найти и напечатать те элементы, которые являются степенью 2. Написать.
как написать прогу быстрого сканирования портом компа на delphi
как написать прогу быстрого сканирования портом компа на delphi:help::help:
Записывайтесь на профессиональные IT-курсы здесь
Решение
DenNik, давно, так что запамятовал.
Решение
Обучайтесь IT-профессиям с гарантией трудоустройства здесь.
Написать функцию для возведения в степень
Написать функцию для поднесения в степень и написать решение примера. Pascal.
Создайте кнопку для нахождения значений функции Z=Arcsin(2X+5Y).
Здраствуйте создал на Делфи калькулятор в него нужно добавить кнопку для нахождения данной функций.
Создайте кнопку для нахождения значений функции Z=Cos(4X-2Y)
Здравствуйте, создала на Делфи калькулятор, в него нужно добавить кнопку для нахождения данной.
Изменить программу для возведения в куб вместо возведения в квадрат
нужно изменить программу в турбо ассемблере так чтобы она не в квадрат возводила а в куб!! str1 DB.
Создайте кнопки для выбора двух цветов и кнопку Старт
Создайте кнопки для выбора двух цветов и кнопку Старт. После нажатия кнопки Старт надпись должна.
Написать рекурсивную функцию для возведения числа в степень
Написать рекурсивную функцию для возведения числа в степень.
Или воспользуйтесь поиском по форуму: