Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.09.23;
Скачать: CL | DM;

Вниз

Бага в IntPower для F_P   Найти похожие ветки 

 
Galkov ©   (2007-02-03 13:44) [0]

//[function IntPower]
function IntPower(Base: Extended; Exponent: Integer): Extended;
{$IFDEF F_P}
begin
 if Exponent = 0 then
 begin
   Result := 1.0;
   Exit;
 end;
 if Exponent < 0 then
 begin
   Exponent := -Exponent;
   Base := 1.0 / Base;
 end;
 Result := Base;
 REPEAT
   Result := Result * Base;
   Dec( Exponent );
 UNTIL Exponent <= 0;
end;
{$ELSE DELPHI}


Даже и комментировать неудобно :((
либо так:

 Result := Base;
 WHILE Exponent>1 do begin
   Result := Result * Base;
   Dec( Exponent );
 end;


либо эдак:

 Result := 1.0;
 REPEAT
   Result := Result * Base;
   Dec( Exponent );
 UNTIL Exponent <= 0;


но уж не так, как в дистрибутиве :((


 
Vladimir Kladov   (2007-02-04 09:00) [1]

хорошо. Вопрос встречный: 2**0 = ? по вашему варианту получается 2. Математика утверждает, что 1. А чему будет равно 2**(-1). В моем варианте 0.5, как и должно быть. А в вашем?


 
Galkov ©   (2007-02-05 01:41) [2]


> А чему будет равно 2**(-1). В моем варианте 0.5, как и должно
> быть

Не правда
В Вашем варианте 0.25 !!!


 
Dilma   (2007-02-05 01:56) [3]

//[function IntPower]
function IntPower(Base: Extended; Exponent: Integer): Extended;
{$IFDEF F_P}
begin
if Exponent = 0 then  {-1 = 0 - нет}
begin
  Result := 1.0;
  Exit;
end;
if Exponent < 0 then   {-1 < 0 - да}
begin
  Exponent := -Exponent;   {Exponent := 1}
  Base := 1.0 / Base;         {Base := 1.0 / 2 }
end;
Result := Base;                 {Result := 0.5 }
REPEAT
  Result := Result * Base;   {Result := 0.5 * 0.5}
  Dec( Exponent );            {Exponent := 0}
UNTIL Exponent <= 0;        {0 <= 0 - да}
end;
{$ELSE DELPHI}


ответ 0.25


 
Vladimir Kladov   (2007-02-05 15:20) [4]

экий дотошный :)
Ну да, 0.25.

Надо теперь сообразить, как это поправить.
Наверное, if Exponent < 0 then
Exponent := -Exponent -1;


 
Galkov ©   (2007-02-05 15:35) [5]


> экий дотошный :)


А я предупреждал: у нас одна школа (альмаматер по ихнему) :))


> Надо теперь сообразить, как это поправить.


Вот те раз :shock:
Написал же [0]: либо так, либо эдак
Могу даже сказать что оба варианта проверены, дальше просто вопрос стиля...
И минус в Exponent тут ни причем: 2**1 тоже 4, вместо 2 выдаст


 
Unknown Mystic ©   (2007-02-05 16:07) [6]

А зачем отдельная проверка Exponent = 0? Почему бы не сделать так:

if Exponent < 0 then
begin
  Exponent := -Exponent;
  Base := 1.0 / Base;
end;
Result := 1.0;
WHILE Exponent>0 do begin
  Result := Result * Base;
  Dec( Exponent );
end;


И еще. Не совсем уверен, насколько это надо, но если не в начале выполнять 1.0 / Base, а после всех перемножений 1.0 / Result, то в таком варианте точность должна быть выше...


 
Galkov ©   (2007-02-05 17:39) [7]

1) Отрабатывается вариант 0**0. Насколько я помню, Владимир придерживается мнения, что пусть это будет 1 (а не исключение Overflow), как в виндячем калькуляторе. Математически - это хоть и неопределенность, но и не утверждение о бесконечности :)

2) На точность это не влияет аж никак. В FPU просто биты порядка будут соответствовать другому знаку, а мантисса содержит ровно столько же знаков.

3) Плюс к этому: при большой отрицательной степени и Base>1 (ну скажем 500**-500) в Вашем варианте получится исключение Overflow. А в базовом - Underflow. Которое в Дельфях по умолчанию замаскировано, и результат есть простенький 0. Что есть правильно, ИМХО.

4) Безусловно, код "причесываеся" самыми разными способами. Ну скажем Ваш вариант, с учетом вышеперечисленного, вполне работоспособен.

Result := 1.0;
if Exponent = 0 then exit;
if Exponent < 0 then begin
 Exponent := -Exponent;
 Base := 1.0 / Base;
end;
WHILE Exponent>0 do begin
 Result := Result * Base;
 Dec( Exponent );
end;


Не более чам вопрос стиля, как мне кажется. Проблем никаких. Кроме одной: даже если этот код почти никем не используется, то ВСЕ РАВНО, гораздо лучше, если он правильный.

Собственно, я на это "наступил" при: а) использовании Str2Double б) строках типа "1.2e-3" в) еще и режиме F_P
Вот такая была адская смесь :))


 
Galkov ©   (2007-02-05 19:51) [8]

хотя мне лично кажется (не более того), что такой код будет на самую малость более эффективен (repeat, в отличии от while, содержит на один jmp меньше)

Result := 1.0;
if Exponent = 0 then exit;
if Exponent < 0 then begin
Exponent := -Exponent;
Base := 1.0 / Base;
end;
REPEAT
Result := Result * Base;
Dec( Exponent );
UNTIL Exponent=0;


 
Barloggg   (2007-02-06 10:09) [9]

хм... а этот код может возвести отрицательное число в дробную степень?
мне как-то понадобилось и пришось сделать такое:
Function FullPOWER(num,step:real):real;
var r2:real;
begin
  result:=0;
  if (step<>trunc(step))and (num<0) then begin
 //если сложный случай
     r2:=step-trunc(step);
     result:=power(num,trunc(step));
     result:=result*power(abs(num),r2);
     exit;
  end;
 //если нормальный случай
  result:=power(num,step);
end;

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


 
Unknown Mystic ©   (2007-02-06 16:07) [10]

>> Galkov
А в чем проблема с 0**0? Тот код который я предложил должен прекрасно выдавать 1... Соответственно код с repeat мне кажется будет менее эффективен из-за лишнего if"а, да еще и с exit"ом вместо лишнего прохода цикла и уж всяко больше :)

>> Barloggg
function IntPower = целочисленная степень
А что такое отрицательное число в дробной степени? Если не ошибаюсь, то в дробную степень возводить можно только положительные числа.


 
Galkov ©   (2007-02-06 18:13) [11]

2Unknown Mystic
приношу извинения - поспешил. Ваш код АБСОЛЮТНО рабочий
НО
вы зря так про эффективность:
1) грамотные компиляторы while делают входом внутрь тела цикла, на проверку условия цикла, которое заканчивается условным переходом на начало цикла (так делается, потому что лишняя команда вне тела это лучше, чем внутри). Т.е. это лишний jmp, в сравнении с repeat. С неграмотными компиляторами дело гораздо хуже. :)
2) первые два условия - это один cmp, плюс два условных перехода jz и jge
Т.е., разница опять в одну команду.
3) Как вывод - разница в эффективности между нашими кодами почти неуловима, и в большей степени определяется умом компилятора. Который, кстати говоря, в нашем случае (F_P) не очень высокий...

Бог его знает, чего там у FPC будет на уме.
Никаких претензий - пусть только правильно работает :)))


 
Galkov ©   (2007-02-07 09:35) [12]

2Unknown Mystic

А если Вас беспокоит вопрос накапливающихся ошибок, при очень многократном умножении, то надо делать как в ASM-версии. В Вашем варианте это выглядело бы так:

if Exponent < 0 then
begin
  Exponent := -Exponent;
  Base := 1.0 / Base;
end;
Result := 1.0;
WHILE Exponent>0 do begin
  if (Exponent and 1) <> 0 then
    Result := Result * Base;
  Base := Base*Base;
  Exponent := Exponent div 2;
end;

2Barloggg
Возведение отрицательного числа в дробную степень - это нонсенс, в аспекте действительных (в смысле не комплексных) чисел.
Фаза комплексного числа УМНОЖАЕТСЯ на степень. И, в случае дробной степени, нулевой она будет только при нулевой исходной. И ровно ПИ (что соответствует отрицательным действительным числам) при дробной экспоненте, вообще-то говоря, никогда не станет.

Читаем ТФКП, ибо знания - сила :))


 
Unknown Mystic ©   (2007-02-08 10:25) [13]

>> Galkov

Да не особо. Это я так к слову написал. Пользоваться ею пока вообще не приходилось.
Кстати последний вариант и работать должен по быстрее из-за меньшего числа итераций.


 
Barloggg   (2007-02-09 10:13) [14]


> Возведение отрицательного числа в дробную степень - это
> нонсенс, в аспекте действительных

хмм... что есть возведение в степень? умножение числа само на себя, верно?
любое возведение в степень можно разложить.
скажем 2 в степени 2,5 есть 2*2*(2^0,5)
то есть дробная степень от отрицательного числа улетает в зону действия комплексных чисел. Логично. Даже верно.

а как насчет графика функции? на что он должен быть похож? В зоне действительных числе график будет представлять собой отдельные точки расходящиеся по степенному графику по обе стороны от нулевой линии, а где находится график между ними? и вот я подумал, а что если эти точки соделинить? получилось прикольно, в результате график получился неразрывным и что самое интересное в поставленной задаче (расчет термических и температурных параметров рабочего тела двигателя внутреннего сгорания) график стал соответствовать экспериментальным значениям, тогда как ругнись возведение в степень на недопустимость такой операции и график тоже получился бы, но рваным и при интерполяции результат был бы идентичным.

о как я высказался. ы. короче главное что работает.
а своими законами меня пожалуйста не ограничивайте, Пифагор знаете ли тоже подогнал свою сумму квадратов катетов под квадрат гипотенузы, в результате чего работает это только для одного единственного частного случая треугольников. :)
хи-хи...


 
Unknown Mystic ©   (2007-02-09 13:31) [15]


> то есть дробная степень от отрицательного числа улетает
> в зону действия комплексных чисел. Логично. Даже верно.


Если не ошибаюсь, то вроде бы не всегда... Например, (-2^0,2) - вполне себе действительное, разве нет?


 
Galkov ©   (2007-02-09 14:08) [16]

2Barloggg да не мои это законы - это правда жизни
И про теорему Пифагора: у меня идеология исключительного физика, а они такие вещи "доказывают" в уме (совсем не так как нас учили в школе), на столько прост и очевиден их подход :)
И говорят после этого, что именно так устроен мир.

2Unknown Mystic
1) конечно лучше :) во всех режимах, кроме F_P используется ASM код в котором именно так и сделано.
2) огорчу Вас: число 0.2 в FPU абсолютно точно не попадает :)
Только с округлениями (периодическая дробь в двоичном исполнении)

Тут ситуация-то очень простая: фаза комплексного числа определена с точностью до константы кратной двум ПИ.
Умножаешь фазу на степень, следовательно и умножаешь эту кратную константу.
Если степень рациональная дробь, то количество таких "корней" будет конечно (грубо говоря равно знаменателю дроби).
А если иррационально - туши свет
Для степени 0.2 - получится пять корней :)
Если это АБСОЛЮТНО точное 0.2


 
Vladimir Kladov   (2007-02-09 19:03) [17]

Для комплексных у нас есть модуль cplxmath.


 
Unknown Mystic ©   (2007-02-09 19:44) [18]

Но ведь один из этих 5 корней - действительный, что я собственно и имел ввиду. ;)
Без условно я говорил о точном 0,2 без учета того, что в двоичной системе счисления это бесконечная дробь, хотя подошла бы любая дробь 1/x, где x - любое нечетное положительное число.


 
Galkov ©   (2007-02-09 21:58) [19]

Флудим конечно :))

Все правильно вы говорите, конечно же
Но это же не применимо алгоритмически.
Просто 1/x, где x - любое нечетное положительное число не укладывается в формат чисел сопроцессора.
Без округлений.
Укладываются только когда x - степень двойки.
Не можем мы записать 1/3 без округлений - и поэтому отметаем вариант для отрицательной базы


 
Unknown Mystic ©   (2007-02-12 10:38) [20]

конечно :)

С округлениями то все понятно...

>> Но это же не применимо алгоритмически.
А корень нечетной степени для отрицательных чисел не реализован что ли?...

Но вообще-то я это больше для Barloggg говорил с его идеей отбрасывать это вообще...


 
Vladimir Kladov   (2007-02-12 15:47) [21]

никаких проблем с целой степенью. Речь идет об отрицательном основании.


 
Galkov ©   (2007-02-12 16:26) [22]


> А корень нечетной степени для отрицательных чисел не реализован
> что ли?

Насколько я понимаю - нет
Именно потому, что это вопрос - определить по экспоненте, что это именно корень именно нечетной степени.
Ну хорошо, сделаем мы проверку для значения 1/Exponent. И даже сообразим как сделать округление, чтобы иметь приемлимую достоверность.

Но какой практический смысл в этих напрягах ????

Почти наверняка, если чел пытается в реальной задаче извлекать корни из отрицательных чисел, то в его задаче проблемы с математикой.
Ничего беспричинного не бывает: либо у него какие-то ошибки с формулами, либо данные попадают в физически недопустимые диапазоны, либо задача глубоко комплексная.

:))



Страницы: 1 вся ветка

Текущий архив: 2007.09.23;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.096 c
15-1187846202
Ega23
2007-08-23 09:16
2007.09.23
Для тех, кто в курсе


2-1188472359
kudatsky
2007-08-30 15:12
2007.09.23
Можно-ли ввести данные в TStringGrid в Design Time ?


15-1187943714
ArtemESC
2007-08-24 12:21
2007.09.23
Как научить ребёнка четырех лет играть в шахматы?


10-1132784192
Nortsov
2005-11-24 01:16
2007.09.23
запись вариантного массива в файл


2-1187935208
Женя_кэт
2007-08-24 10:00
2007.09.23
Сохранение рисунков в MSSQL





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский