Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.11.21;
Скачать: [xml.tar.bz2];

Вниз

Мат, округлние   Найти похожие ветки 

 
pasha_golub ©   (2004-10-28 14:59) [0]

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


 
GuAV ©   (2004-10-28 15:07) [1]

pasha_golub ©   (28.10.04 14:59)

SetRoundMode

rmNearest Rounds to the closest value.
rmDown Rounds toward negative infinity.
rmUp Rounds toward positive infinity.
rmTruncate Truncates the value, rounding positive numbers down and negative numbers up.

AFAIK, это всё что есть - математического нет.


 
GuAV ©   (2004-10-28 15:14) [2]

15                     8    7                    0
+-----------------------++-----------------------+
¦  ¦  ¦  ¦  ¦     ¦     ¦¦  ¦  ¦  ¦  ¦  ¦  ¦  ¦  ¦
¦  ¦  ¦  ¦IC¦ RC  ¦ PC  ¦¦IE¦  ¦PM¦UM¦OM¦ZM¦DM¦IM¦-- Control word
¦  ¦  ¦  ¦  ¦     ¦     ¦¦  ¦  ¦  ¦  ¦  ¦  ¦  ¦  ¦
+-----------------------++-----------------------+

IC--Infinity Control
 0 = Projective (default on 8087 and 80287)
 1 = Affine
 On 80387 and 80486, affine closure (distinguishing between positive
 and negative infinity) is used regardless of setting.

RC--Rounding Control
 00 = Round to nearest or even (default)
 01 = Round down toward -infinity
 10 = Round up toward +infinity
 11 = Chop by truncating toward 0

PC--Precision control
 00 = 24-bit mantissa (single precision)
 10 = 53-bit mantissa (double precision)
 11 = 64-bit mantissa (extended precision)

IE - Interrupt Enable Mask
 Only on 8087; undefined on 80287, 80387, and 80486.

Exception Masks
 PM = 1 to mask precision
 UM = 1 to mask underflow
 OM = 1 to mask overflow
 ZM = 1 to mask zero divide
 DM = 1 to mask denormalized operand
 IM = 1 to mask invalid operation


 
pasha_golub ©   (2004-10-28 15:14) [3]

Есть, есть... Блин, мать его за ногу.


 
pasha_golub ©   (2004-10-28 15:17) [4]

Вот те раз... Вот те два... Спасибо.


 
pasha_golub ©   (2004-10-28 15:22) [5]

Лана, а как же его тогда реализовать? Блин.


 
Jeer ©   (2004-10-28 15:28) [6]

function RoundUp(Value: Extended): Int64;
const
 RoundUpCW = $1B32;
var
 OldCW: Word;
begin
 OldCW := Default8087CW;
 try
   Set8087CW(RoundUpCW);
   result := Round(Value);
 finally
   Set8087CW(OldCW);
 end;
end;

end;


 
GuAV ©   (2004-10-28 16:06) [7]

Да, выставить округление вверх, а перед округлением отнять .5

Только рекомендую не кодом Jeer ©, а через SetRoundMode, чтоб лишние биты не менять.


 
GuAV ©   (2004-10-28 16:09) [8]

GuAV ©   (28.10.04 16:06) [7]
То есть наоборот, вниз и добавить .5 и в коде Jeer ©  ничего плохого...


 
GuAV ©   (2004-10-28 16:20) [9]

Точнее ещё сложнее :( для положительных округление вверх, а перед округлением отнять .5 для отрицательных добавить .5 и вниз.

Хотя не уверен что есть мат. округление для отр чисел.


 
pasha_golub ©   (2004-10-28 16:50) [10]

Спасибо, ребят.


 
Verg ©   (2004-10-28 17:52) [11]

Может такая подойдет:

function RoundUp(X: Extended): Extended;
begin
 Result := Trunc(X) + Trunc (Frac(X) * 2);
end;


 
Defunct ©   (2004-10-28 18:10) [12]

pasha_golub ©   (28.10.04 15:22) [5]

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

Const E = 0.000000000001;

Round( Число + E );


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


 
GuAV ©   (2004-10-28 18:22) [13]

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;


 
GuAV ©   (2004-10-28 18:34) [14]

Вот мой вариант. Можно конечно избавится от 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;


 
Defunct ©   (2004-10-28 18:50) [15]

GuAV ©   (28.10.04 18:22) [13]

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

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

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


 
Defunct ©   (2004-10-28 18:56) [16]

GuAV ©   (28.10.04 18:22) [13]

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


 
GuAV ©   (2004-10-28 19:14) [17]

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 19:22) [18]

> Тогда для каждого числа надо подбирать своё 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:33) [19]

Defunct ©   (28.10.04 19:22) [18]

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

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

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


 
Defunct ©   (2004-10-28 19:56) [20]

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

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

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

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

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


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

Round( Число + 0.1)


 
Verg ©   (2004-10-28 20:45) [21]


>  Defunct ©   (28.10.04 19:56)


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


 
GuAV ©   (2004-10-28 21:14) [22]

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


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

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


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


 
Defunct ©   (2004-10-28 21:32) [23]

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

-1


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

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

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

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


 
sniknik ©   (2004-10-28 22:12) [25]


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;


 
GuAV ©   (2004-10-28 22:15) [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]. А вообще никакой неприязни не испытываю.


 
GuAV ©   (2004-10-28 22:22) [27]

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.


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

В этом месте полезно напомнить правила округления десятичных дробей до определенного разряда. Округление состоит в отбрасывании, точнее в замене нулями, всех цифр, стоящих правее цифры данного разряда. Если при этом первой из отбрасываемых цифр является 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


 
Verg ©   (2004-10-28 22:40) [29]


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


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


 
sniknik ©   (2004-10-28 23:25) [30]

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 23:29) [31]


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


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


 
Defunct ©   (2004-10-28 23:33) [32]

GuAV ©   (28.10.04 22:15) [26]
> Я уже доказал.
Не не доказал.
Док-во - конкретный пример где такое округление даст сбой, а ваш способ и ф-ция Verg округлит правильно.


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

Давайте без допустим. Допустим в мантиссу не влазит дробная часть вообще. В общем это чушь а не доказательство.


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

В математике все же округление идет к большему целому.

Просто и со вкусом:

Const E = 0.01;

procedure TForm1.Button8Click(Sender: TObject);
begin
 ShowMessage( Format("]-2.5[ = %D",[ Round(-2.5 + E) ] ));
 ShowMessage( Format("]-1.5[ = %D",[ Round(-1.5 + E) ] ));
 ShowMessage( Format("]1.5[ = %D",[ Round(1.5 + E) ] ));
 ShowMessage( Format("]2.5[ = %D",[ Round(2.5 + E) ] ));
end;


 
sniknik ©   (2004-10-28 23:54) [33]

> а на 2.001 что получим?
обана, а мужики то не в курсе. ;о)

сорри, действительно ерунда получилась.


 
Defunct ©   (2004-10-28 23:56) [34]

> Verg

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

Извини, но я там не нашел ни слова про округление..

То, что по второй ссылке -1.5 = -2 я поверю наслово.


 
False_Delirium ©   (2004-10-29 00:04) [35]

Defunct ©   (28.10.04 23:56) [34]  
 Математическое округление -1.5 даёт -1

и кто говорит обратное - идёт в туман :))


 
Verg ©   (2004-10-29 00:04) [36]


> [34] Defunct ©   (28.10.04 23:56)


http://www.sgu.ru/ie/mehmat/matin/R1-4.htm


 
Defunct ©   (2004-10-29 00:31) [37]

Verg ©   (29.10.04 00:04) [36]

ага нашел.

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

Давайте применим это правило к числам около нуля.

-0.6 = -1
-0.5 = -1
-0.4 = 0
-0.3 = 0
-0.2 = 0
-0.1 = 0
0    = 0
0.1  = 0
0.2  = 0
0.3  = 0
0.4  = 0
0.5  = 1

Получается почему-то 9 нулей хотя должно быть 10. ведь целое складывается из десяти десятых, а не из девяти.
Выводы:
1. 0 - не целое число (но это не так).
2. метод округления указан не точно. И действительно в приведенной статье нет правила округления отрицательных чисел.


 
GuAV ©   (2004-10-29 00:35) [38]

Defunct ©   (28.10.04 23:33) [32]
Док-во - конкретный пример где такое округление даст сбой

procedure TForm1.FormCreate(Sender: TObject);
var X, X1, Z, Z1: Extended;  S: string; OldMode: TFPURoundingMode;
begin
 Z:=212432313499856792.5;
 X:=212432313.4998567925;

 Memo1.Lines.Add("Defunct");

 Z1:=Round(Z + 0.001);
 X1:=Round(X + 0.001);
 Memo1.Lines.Add(FloatToStrF(Z1, ffFixed, 22, 2));
 Memo1.Lines.Add(FloatToStrF(X1, ffFixed, 22, 2));

 Memo1.Lines.Add("Verg");

 Z1:=Trunc(Z) + Trunc (Frac(Z) * 2);
 X1:=Trunc(X) + Trunc (Frac(X) * 2);
 Memo1.Lines.Add(FloatToStrF(Z1, ffFixed, 22, 2));
 Memo1.Lines.Add(FloatToStrF(X1, ffFixed, 22, 2));

 Memo1.Lines.Add("GuAV");

  OldMode := SetRoundMode(rmDown);
  try
    Z1:=Round(Z + 0.5);
    X1:=Round(X + 0.5);
  finally
    SetRoundMode(OldMode);
  end;

 Memo1.Lines.Add(FloatToStrF(Z1, ffFixed, 22, 2));
 Memo1.Lines.Add(FloatToStrF(X1, ffFixed, 22, 2));

end;


 
Verg ©   (2004-10-29 00:41) [39]

Можете еще с excel-ом поиграться. Тот использует математическое округление без правила "четной цифры". Функция =ОКРУГЛ().

А


>В математике все же округление идет к большему целому.
> Const E = 0.000000000001;
>
> Round( Число + E );


Образует какое-то "альтернативное" понятие математического округления :))


 
Defunct ©   (2004-10-29 00:53) [40]

GuAV ©   (29.10.04 00:35) [38]

Извините, но вы показываете свое неумение слушать.

X:=212432313.4998567925;

Конкретно в этом числе порядок наименьшего значащей цифры (5) = 10(-10). Соответственно E = 10(-11).
Все упирается в точность.

Опять же

Z:=212432313499856792.5;

при E=0.01 округлит верно.

для полноты картины надо бы добавить еще и
Y = 3212432313499856792.5;

В общем если вы пытаетесь показать ограниченность мантиссы, так с этим никто не спорит.



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

Форум: "Основная";
Текущий архив: 2004.11.21;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.04 c
8-1092423656
TRyaSS
2004-08-13 23:00
2004.11.21
воспроизвести WAV с помощью DXSound???


1-1099990037
VIo
2004-11-09 11:47
2004.11.21
<<< Прервать задержку >>>


14-1099565233
КаПиБаРа
2004-11-04 13:47
2004.11.21
Оформление заголовков модулей


6-1095128280
inkarik
2004-09-14 06:18
2004.11.21
Internet


1-1100020933
kooop
2004-11-09 20:22
2004.11.21
массив Edit- компонентов





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский