RoundTo
От: mlecter  
Дата: 15.09.04 13:57
Оценка:
Доброго времени суток!
Есть такая проблема:
Делаю

SetRoundMode(rmNearest);
RoundTo(123.345, -2)

Получаю

123.34

причем, если передаю 1.245, то выдает 1.25

Может дело в том, что 123.345 он понимает как 123.3449999999999 и делает потом Trunc?
Как нормально округлить число? Писать свою функцию с использованием Round?
Re: RoundTo
От: mlecter  
Дата: 15.09.04 14:37
Оценка:
Проблема в RoundMode
Если даже стоит rmNearest округление происходит банковским методом.
Можно ли округлять не банковским методом?
Re: RoundTo
От: Diouzshev Россия  
Дата: 15.09.04 15:05
Оценка:
Hello, mlecter!
You wrote on Wed, 15 Sep 2004 13:57:07 GMT:

m> Делаю


m> SetRoundMode(rmNearest);

m> RoundTo(123.345, -2)

m> Получаю


m> 123.34


m> причем, если передаю 1.245, то выдает 1.25


m> Может дело в том, что 123.345 он понимает как 123.3449999999999 и

m> делает потом Trunc?
m> Как нормально округлить число? Писать свою функцию с использованием
m> Round?

Ого-го... Вот это да! Глюк у RoundTo на таких маленьких числах!
Помогло изменение функции RoundTo:
function RoundTo(const AValue: Extended {было Double}; const ADigit: TRoundToRange): Extended; {было Double}
var
LFactor: Extended; {было Double}
begin
LFactor := IntPower(10, ADigit);
Result := Round(AValue / LFactor) * LFactor;
end;

После изменений 1.245 стало округлять правильно — до 1.24 %)

Народ! У кого D7 скажите, этот глюк сохранился?

With best regards, Alexander Diouzshev-Maltsev.
Posted via RSDN NNTP Server 1.9 gamma
Re[2]: RoundTo
От: Diouzshev Россия  
Дата: 15.09.04 15:07
Оценка:
Hello, mlecter!
You wrote on Wed, 15 Sep 2004 14:37:23 GMT:

m> Проблема в RoundMode

m> Если даже стоит rmNearest округление происходит банковским методом.
m> Можно ли округлять не банковским методом?
Можно!
Ручками. Но зачем?

With best regards, Alexander Diouzshev-Maltsev.
Posted via RSDN NNTP Server 1.9 gamma
Re: RoundTo
От: AMogil Россия  
Дата: 15.09.04 15:09
Оценка:
Здравствуйте, mlecter, Вы писали:

M>Доброго времени суток!

M>Есть такая проблема:
M>Делаю

M>SetRoundMode(rmNearest);

M>RoundTo(123.345, -2)

M>Получаю


M>123.34


M>причем, если передаю 1.245, то выдает 1.25


M>Может дело в том, что 123.345 он понимает как 123.3449999999999 и делает потом Trunc?

M>Как нормально округлить число? Писать свою функцию с использованием Round?

SimpleRoundTo?

Алексей.
Re[2]: RoundTo
От: AMogil Россия  
Дата: 15.09.04 15:10
Оценка:
Здравствуйте, AMogil, Вы писали:

AM>Здравствуйте, mlecter, Вы писали:


M>>Доброго времени суток!

M>>Есть такая проблема:
M>>Делаю

M>>SetRoundMode(rmNearest);

M>>RoundTo(123.345, -2)

M>>Получаю


M>>123.34


M>>причем, если передаю 1.245, то выдает 1.25


M>>Может дело в том, что 123.345 он понимает как 123.3449999999999 и делает потом Trunc?

M>>Как нормально округлить число? Писать свою функцию с использованием Round?

AM>SimpleRoundTo?


AM>Алексей.


Она округляет до большего, т.е. для положительных чисел все делает как мы привыкли.

Алексей.
Re[3]: RoundTo
От: mlecter  
Дата: 15.09.04 15:16
Оценка:
Здравствуйте, AMogil, Вы писали:

AM>>Алексей.


AM>Она округляет до большего, т.е. для положительных чисел все делает как мы привыкли.


AM>Алексей.


Не до большего, а до ближайшего четного.
1.345 -> 1.34
1.355 -> 1.36

"Мы" так не привыкли
Re[2]: RoundTo
От: mlecter  
Дата: 15.09.04 15:19
Оценка:
Здравствуйте, AMogil, Вы писали:

AM>SimpleRoundTo?


AM>Алексей.


SimpleRoundTo(123.345, -2) = 123.34
RoundMode = rmNearest
Re[4]: RoundTo
От: AMogil Россия  
Дата: 15.09.04 15:31
Оценка:
Здравствуйте, mlecter, Вы писали:

M>Здравствуйте, AMogil, Вы писали:


AM>>>Алексей.


AM>>Она округляет до большего, т.е. для положительных чисел все делает как мы привыкли.


AM>>Алексей.


M>Не до большего, а до ближайшего четного.

M>1.345 -> 1.34
M>1.355 -> 1.36

M>"Мы" так не привыкли


Пример из справки Delphi

Expression Value

SimpleRoundTo(1234567, 3) 1234000
SimpleRoundTo(1.234, -2) 1.23 !!!!!!!
SimpleRoundTo(1.235, -2) 1.24
SimpleRoundTo(-1.235, -2) -1.23

И техт:

SimpleRoundTo uses asymmetric arithmetic rounding to determine how to round values that are exactly midway between the two values that have the desired number of significant digits. This method always rounds to the larger value.
Re[5]: RoundTo
От: AMogil Россия  
Дата: 15.09.04 15:36
Оценка: 2 (1)
Здравствуйте, AMogil, Вы писали:

AM>Здравствуйте, mlecter, Вы писали:


M>>Здравствуйте, AMogil, Вы писали:


AM>>>>Алексей.


AM>>>Она округляет до большего, т.е. для положительных чисел все делает как мы привыкли.


AM>>>Алексей.


M>>Не до большего, а до ближайшего четного.

M>>1.345 -> 1.34
M>>1.355 -> 1.36

M>>"Мы" так не привыкли


AM>Пример из справки Delphi


AM>Expression Value


AM>SimpleRoundTo(1234567, 3) 1234000

AM>SimpleRoundTo(1.234, -2) 1.23 !!!!!!!
AM>SimpleRoundTo(1.235, -2) 1.24
AM>SimpleRoundTo(-1.235, -2) -1.23

AM>И техт:


AM>SimpleRoundTo uses asymmetric arithmetic rounding to determine how to round values that are exactly midway between the two values that have the desired number of significant digits. This method always rounds to the larger value.


Попробуйте

SetRoundMode(rmDown);
Re[6]: RoundTo
От: mlecter  
Дата: 15.09.04 15:53
Оценка:
Здравствуйте, AMogil, Вы писали:


AM>>Пример из справки Delphi


AM>>Expression Value


AM>>SimpleRoundTo(1234567, 3) 1234000

AM>>SimpleRoundTo(1.234, -2) 1.23 !!!!!!!
AM>>SimpleRoundTo(1.235, -2) 1.24
AM>>SimpleRoundTo(-1.235, -2) -1.23

AM>>И техт:


AM>>SimpleRoundTo uses asymmetric arithmetic rounding to determine how to round values that are exactly midway between the two values that have the desired number of significant digits. This method always rounds to the larger value.


AM>Попробуйте


AM>SetRoundMode(rmDown);


Спасибо, заработало
Хотя странно, SimpleRoundTo вроде не должен использовать RoundMode


function SimpleRoundTo(const AValue: Double; const ADigit: TRoundToRange = -2): Double;
var
  LFactor: Double;
begin
  LFactor := IntPower(10, ADigit);
  Result := Trunc((AValue / LFactor) + 0.5) * LFactor;
end;


В чем причина?
Re[7]: RoundTo
От: mlecter  
Дата: 15.09.04 16:04
Оценка:
Здравствуйте, mlecter, Вы писали:

M>Здравствуйте, AMogil, Вы писали:



AM>>>Пример из справки Delphi


AM>>>Expression Value


AM>>>SimpleRoundTo(1234567, 3) 1234000

AM>>>SimpleRoundTo(1.234, -2) 1.23 !!!!!!!
AM>>>SimpleRoundTo(1.235, -2) 1.24
AM>>>SimpleRoundTo(-1.235, -2) -1.23

AM>>>И техт:


AM>>>SimpleRoundTo uses asymmetric arithmetic rounding to determine how to round values that are exactly midway between the two values that have the desired number of significant digits. This method always rounds to the larger value.


AM>>Попробуйте


AM>>SetRoundMode(rmDown);


M>Спасибо, заработало

M>Хотя странно, SimpleRoundTo вроде не должен использовать RoundMode


M>
M>function SimpleRoundTo(const AValue: Double; const ADigit: TRoundToRange = -2): Double;
M>var
M>  LFactor: Double;
M>begin
M>  LFactor := IntPower(10, ADigit);
M>  Result := Trunc((AValue / LFactor) + 0.5) * LFactor;
M>end;
M>


M>В чем причина?


Тем более, что после того как я сделаю SetRoundMode(rmDown), RoundTo начинает все округлять (естественно) вниз, в то время как SimpleRoundTo начинает округлять нормально. Получается путанница...
Re[7]: RoundTo
От: AMogil Россия  
Дата: 15.09.04 16:13
Оценка:
Здравствуйте, mlecter, Вы писали:

M>Здравствуйте, AMogil, Вы писали:

M>В чем причина?

Интересный фокус:
При вычислении SimpleRoundTo(1.345 , -2) по информации watch'a:



RoundMode rmUp rmDown

В исходном коде SimpleRoundTo
AValue / LFactor 134.5 134.5
(AValue / LFactor) + 0.5 135 135
Trunc((AValue / LFactor) + 0.5) 134 (!!!!!) 135

В моем коде (Trunc(135)) 135 135

Фокус, блин.

Алексей.
Re[8]: RoundTo
От: AMogil Россия  
Дата: 15.09.04 16:17
Оценка:
Здравствуйте, AMogil, Вы писали:

AM>Здравствуйте, mlecter, Вы писали:


Форматирование сбилось. Снова табличка.

Интересный фокус:
При вычислении SimpleRoundTo(1.345 , -2) по информации watch'a:



RoundMode                                                   rmUp            rmDown

В исходном коде SimpleRoundTo
AValue / LFactor                                        134.5                        134.5
(AValue / LFactor) + 0.5                        135                            135
Trunc((AValue / LFactor) + 0.5)        134 (!!!!!)            135

В моем коде (Trunc(135))                        135                            135

Фокус, блин.
Re[9]: RoundTo
От: Аноним  
Дата: 15.09.04 18:47
Оценка:
Здравствуйте, AMogil, Вы писали:

AM>
AM>Интересный фокус:
AM>При вычислении SimpleRoundTo(1.345 , -2) по информации watch'a:



AM>RoundMode                                                   rmUp            rmDown

AM>В исходном коде SimpleRoundTo
AM>AValue / LFactor                                        134.5                        134.5
AM>(AValue / LFactor) + 0.5                        135                            135
AM>Trunc((AValue / LFactor) + 0.5)        134 (!!!!!)            135

AM>В моем коде (Trunc(135))                        135                            135

AM>Фокус, блин.
AM>



Да, дело в IntPower.
rmNearest
lFactor := IntPower(10, -2) > 0.01 !
Frac((AValue / LFactor) + 0.5) = 1 !!!
отсюда и Trunc(...) = 134

rmDown
lFactor := IntPower(10, -2) < 0.01
дальше все нормально.


Явно борландовые фокусники
Re[3]: RoundTo
От: kavlad Россия http://www.wavesoft.ru
Дата: 16.09.04 06:05
Оценка:
Здравствуйте, Diouzshev, Вы писали:

m>> Проблема в RoundMode

m>> Если даже стоит rmNearest округление происходит банковским методом.
m>> Можно ли округлять не банковским методом?
D>Можно!

В семерке есть функия

SimpleRoundTo function
Rounds a floating-point value to a specified digit or power of ten using asymmetric arithmetic rounding.

... << RSDN@Home 1.1.4 @@subversion >>
Re[10]: RoundTo
От: mlecter  
Дата: 16.09.04 08:03
Оценка:
В итоге рабочая процедура выглядит так:


function RoundToEx(const AValue: Double; const ADigit: TRoundToRange = -2): double;
var
  LFactor: double;
  i: integer;
  s: string;
begin
  LFactor := IntPower(10, ADigit);
  i := Round(AValue / (LFactor / 10));
  s := IntToStr(i);
  Result := (Trunc(i/10) + ord(StrToInt(s[Length(s)]) >= 5)) * LFactor;
end;


Через одно место, зато работает всегда, без всяких rmDown...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.