Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Мат, округлние [D4]


Страницы:   1 2 3

pasha_golub ©   (2004-10-28 14:59:00) 

Люди, добрые подскажите параметр для FPU 8087, которое нужно кинуть в Set8087CW для того, чтобы округление было не банковским, а математическим. Спасибо.


Verg   (2004-10-28 23:29:00) [21]


> [30] sniknik ©   (28.10.04 23:25)


а на 2.001 что получим?


sniknik   (2004-10-28 23:25:00) [22]

GuAV ©   (28.10.04 22:22) [27]
procedure TForm1.Button2Click(Sender: TObject);
var
 S, S1: extended;
begin
 S:= 1.5;
 S1:= 2.5;
 Set8087CW($1B72);
 Edit1.Text:=IntToStr(Round(S)); // получим 2
 Edit2.Text:=IntToStr(Round(S1)); // получим 3
end;

надо разделять, что считается на этапе компиляции а что в рантайме.


Verg   (2004-10-28 22:40:00) [23]


> [23] Defunct ©   (28.10.04 21:32)


Вот и получается: как не крути, а ОКРУГЛЕНИЕ(-1.5)  = -2


Verg   (2004-10-28 22:25:00) [24]

В этом месте полезно напомнить правила округления десятичных дробей до определенного разряда. Округление состоит в отбрасывании, точнее в замене нулями, всех цифр, стоящих правее цифры данного разряда. Если при этом первой из отбрасываемых цифр является 0, 1, 2, 3 или 4 , последняя остающаяся цифра не меняется; если же первой из отбрасываемых цифр окажется 5, 6, 7, 8 или 9 , последняя остающаяся цифраувеличивается на 1, а если этой цифрой была 9, то увеличение на 1 произойдет в предшествующем ей разряде, а сама она заменится на 0. Старинное "правило четной цифры": когда отбрасывается только цифра 5, последняя остающаяся цифра не меняется, если она четная, и увеличивается на 1, если она нечетная.

http://www.sgu.ru/ie/mehmat/matin/

http://www.ibase.ru/devinfo/round.htm


GuAV   (2004-10-28 22:22:00) [25]

sniknik ©   (28.10.04 22:12) [25]
procedure TForm1.Button2Click(Sender: TObject);
begin
Set8087CW($1B72);
Edit1.Text:=IntToStr(Round(1.5)); // получим 2
Edit1.Text:=IntToStr(Round(2.5)); // получим 2
end;


и вообще кроме 10 и 11 битов не следует ничего торгать, особенно exception mask.


GuAV   (2004-10-28 22:15:00) [26]

Я уже доказал.

Ещё раз

Вот допустим ххх.5 и .5 в последнем знаке, прибавление 0.1 не изменит число, и если оно нечётноё, оно округлится в меньшую сторону ка и просто Round.

При том, что может быть в том же месте и ххх.49, прибавив 0.1 получим ххх.59

Defunct ©   (28.10.04 22:03) [24]
Понимаю, что вам немного неприятно, что вы не заметили такого простого способа решения.


Это могло бы быть применимо к Verg ©   (28.10.04 17:52) [11], но не к Defunct ©   (28.10.04 18:10) [12]. А вообще никакой неприязни не испытываю.


sniknik   (2004-10-28 22:12:00) [27]


procedure TForm1.Button1Click(Sender: TObject);
var
 Table: array[word] of double;
 i: integer;
 S, S1, S2: extended;
begin
 randomize;
 S := 0;
 for i := low(Table) to high(Table) do begin
   Table[i] := Random * 10;
   S := S + Table[i]; // это будет точная сумма
 end;

 Set8087CW($1372); // включаем "бухгалтерское" округление
 S1 := 0;
 for i := low(Table) to high(Table) do S1 := S1 + Round(Table[i]);

 Set8087CW( $1B72); // включаем "школьное" округление
 S2 := 0;
 for i := low(Table) to high(Table) do S2 := S2 + Round(Table[i]);

 Edit1.Text:= FloatToStr(S);
 Edit2.Text:= FloatToStr(S1);
 Edit3.Text:= FloatToStr(S2);
end;


Defunct   (2004-10-28 22:03:00) [28]

> но правильное (в отличии от Вашего).

Чтобы так говорить надо доказать, что мое решение - неправильное.
Вперед, жду доказательства.

Понимаю, что вам немного неприятно, что вы не заметили такого простого способа решения.


Defunct   (2004-10-28 21:32:00) [29]

> -1.5 - это сколько должно получится после округления?

-1


GuAV   (2004-10-28 21:14:00) [30]

Defunct ©   (28.10.04 19:56) [20]
В случае бесконечно больших чисел округление не имеет значения вообще


Мы не говорим о бесконечно больших числах, а о просто больших. Я говорю о том что могут существовать и болшие числа, где Вашим способом меньше 0.01 не получится и малые, где 0.0001 внесёт искажение.

Defunct ©   (28.10.04 19:56) [20]
Это "красивое" решение как минимум в 2 раза медленнее моего и даже медленнее вашего решения


Мы не меряемся скоростью мы решаем задачу. Оно красивое, несмотря на то что возможно и самое медленное, т.к. простое (в отличии от моего) но правильное (в отличии от Вашего).


Verg   (2004-10-28 20:45:00) [31]


>  Defunct ©   (28.10.04 19:56)


Ты лучше вот что скажи:
-1.5 - это сколько должно получится после округления?


Defunct   (2004-10-28 19:56:00) [32]

Уж кто как не вы, зная asm, должны понимать что:

> Не говоря уже о красивомрешении Verg

Это "красивое" решение как минимум в 2 раза медленнее моего и даже медленнее вашего решения (которое не блещет).

> Согласитесь Ваша идея даже хуже моей.
Не соглашусь, потому что мы живем в реальном мире и мат расчеты имеют дело с реальными числами а не с бесконечностью. И для реальных чисел метод [12] самый быстрый и его нельзя упрекнуть в недостатке точности.

В случае бесконечно больших чисел округление не имеет значения вообще. Какая разница будет там 1 или 2 в последнем разряде если число состоит из 50-ти цифр?


"Программист! ДЕЛАЙ ВСЕ ПРОЩЕ".
В данном конкретном случае, когда у нас точность до "целого" подойдет и:

Round( Число + 0.1)


GuAV   (2004-10-28 19:33:00) [33]

Defunct ©   (28.10.04 19:22) [18]

Вы идею вообще поняли

Идею понял. Но она не очень хорошая. Допустим у нас есть числа где точность 10(-6) и есть те у которых не может быть такой точности (из-за ограничения мантиссы extended). Для них уже нужны разные E.

Согласитесь Ваша идея даже хуже моей. Не говоря уже о красивом решении Verg ©   (28.10.04 17:52) [11].


Defunct   (2004-10-28 19:22:00) [34]

> Тогда для каждого числа надо подбирать своё E.
E подбирается под точность, а не для каждого числа.

Для точности 10(-6), порядок E должен быть меньше либо равен 10(-7).

> Дело в том что для числа xxxxxx.5 этот самый .5 может быть в
> последнем разряде, т.е. прибавление 0.1 не изменит того числа.
> Искать можество таких чисел не буду, но оно есть.

А и не нужно ничего изменять.

должно быть:
Round(xxxxx.5 + 0.01)
или
Round(xxxxx.5 + 0.001)
Главное, что порядок единицы ниже.

Вы идею вообще поняли или просто видите какие-то ошибки, понятные только вам?


GuAV   (2004-10-28 19:14:00) [35]

Defunct ©   (28.10.04 18:50) [15]
Тогда для каждого числа надо подбирать своё E.
Дело в том что для числа xxxxxx.5 этот самый .5 может быть в последнем разряде, т.е. прибавление 0.1 не изменит того числа. Искать можество таких чисел не буду, но оно есть.

Defunct ©   (28.10.04 18:56) [16]
но поверьте наслово Mat округление делаем приведенным в [12] методом еще с 8087.


На здоровье !

Но всё же пока я вижу ошибку в Вашем методе, я не стал бы его использовать/рекомендовать его, и автор векти вероятно тоже.


Defunct   (2004-10-28 18:56:00) [36]

GuAV ©   (28.10.04 18:22) [13]

PS: в общем у меня сегодня жутко плохое настроение чтобы привести нормальные аргументы, да и тема заезженная и неинтересная, но поверьте наслово Mat округление делаем приведенным в [12] методом еще с 8087.


Defunct   (2004-10-28 18:50:00) [37]

GuAV ©   (28.10.04 18:22) [13]

Вам что надо все разжевать?

Порядок единички E должен быть меньше порядка самой младшей цифры после запятой. Если мы работаем с точностью до 10(-6) = 0.000001 тогда E дожно быть E=10(-7) = 0.0000001.

ПРИЧЕМ ВСЕГДА.


GuAV   (2004-10-28 18:34:00) [38]

Вот мой вариант. Можно конечно избавится от try...finally убедившись что исключений не будет (замаскировать все FPU исключения)

function MathRound(const X: Extended): Extended;
var OldRMode: TFPURoundingMode;
begin
 if X > 0 then
 begin
   OldRMode := SetRoundMode(rmDown);
   try
     Result:=Round(X + 0.5);
   finally
     SetRoundMode(OldRMode);
   end;
 end
 else
 begin
   OldRMode := SetRoundMode(rmUp);
   try
     Result:=Round(X - 0.5);
   finally
     SetRoundMode(OldRMode);
   end;
 end
end;

procedure TForm1.Button1Click(Sender: TObject);
var ValueToRound: Extended;
begin
 ValueToRound := 0;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));

 ValueToRound := 1.499999999999;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));
 ValueToRound := 1.5;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));
 ValueToRound := 2.499999999999;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));
 ValueToRound := 2.5;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));

 ValueToRound := -1.499999999999;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));
 ValueToRound := -1.5;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));
 ValueToRound := -2.499999999999;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));
 ValueToRound := -2.5;
 memo1.Lines.Add(FloatToStr(MathRound(ValueToRound)));
end;


GuAV   (2004-10-28 18:22:00) [39]

Defunct ©   (28.10.04 18:10) [12]

Не всегда.

procedure TForm1.FormCreate(Sender: TObject);
Const E = 0.000000000001;
var ValueToRound: Extended;
begin
 ValueToRound := 1.499999999999;
 memo1.Lines.Add(FloatToStr(Round(ValueToRound)));
 memo1.Lines.Add(FloatToStr(Round(ValueToRound+E)));
end;


Defunct   (2004-10-28 18:10:00) [40]

pasha_golub ©   (28.10.04 15:22) [5]

Уже честно сказать надоело попугайничать, но так уж и быть специально для вас:

Const E = 0.000000000001;

Round( Число + E );


Будет вам мат. округление.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо