Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Фокусы Delphi, Простая функция Round фокуснечает. 
:(
    Опции темы
Poseidon
  Дата 10.3.2005, 03:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Значит так друзья. Пишу программу и столкнулся с "детской" процедуркой. Код немного переделанный (что бы понятно было), но суть ясна. Значит вот он:
Код
var
str: string;
x,y: real;
begin
x:= 0.5;
y:= 1.5;
str:= IntToStr( Round(x) + Round(y) );
Label1.Caption:= str ;
end;

Так вот сколько вы ожидаете увидеть в Label1? А ожидал 3. А там 2!
Вроде встречался с функцией Round и знаю, что она должна округлять по извесным правилам. Т.е. 0.5 округляется до 1, а 1.5 до 2. Но почему же тогда 1 + 2 = 2 ?
Может кто встречался с таким? Это хорошо, что у меня так получилось, что я сразу нашел. А ведь из-за этого погут все расчеты пойти на смарку. smile


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
RA
Дата 10.3.2005, 04:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Брутальный буратина
****


Профиль
Группа: Участник Клуба
Сообщений: 3497
Регистрация: 31.3.2002
Где: Лес

Репутация: 14
Всего: 115



Цитата(Poseidon @ 10.3.2005, 03:41)
Т.е. 0.5 округляется до 1


0.5 округляется до 0.

Добавлено @ 04:45
попробуй вместо Round использовать Ceil, ибо чеил округляет число в сторону увеличения, а round до ближайшего целого.


Код


... модуль Math

//Округление в сторону увеличения
function Ceil(const X: Extended): Integer;
begin
  Result := Integer(Trunc(X));
  if Frac(X) > 0 then
    Inc(Result);
end;

//Округление в сторону уменьшения
function Floor(const X: Extended): Integer;
begin
  Result := Integer(Trunc(X));
  if Frac(X) < 0 then
    Dec(Result);
end;



Это сообщение отредактировал(а) RAdmin - 10.3.2005, 04:56
PM   Вверх
SPrograMMer
Дата 10.3.2005, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Спамер :)
**


Профиль
Группа: Участник
Сообщений: 442
Регистрация: 5.11.2004
Где: Краснодар

Репутация: 2
Всего: 6



Из того модуля Math:
Код

Function RoundTo(const AValue:Double;const ADigit:TRoundToRange):Double;

Попробуй сказать:
Код

...
str:= IntToStr( RoundTo(x,0) + RoundTo(y,0) );
...



--------------------
животное = зверь
законченный гентушник
PM MAIL ICQ Jabber   Вверх
Poseidon
Дата 11.3.2005, 04:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



RAdmin
Цитата
0.5 округляется до 0.
Это в этой процедуре. А если мы, к примеру, возьмем
Код
x:= 1.5;
y:= 2.5;

то получим не желанные 5, а 4!
Цитата
попробуй вместо Round использовать Ceil

Не подходит! Нужно именно округлять по правилам (< 5 в меншую, >=5 в большую сторону). Конечно можно устроить проверку символа после запятой и по нему определять, куда округлять в большую (Ceil) или меншую (Trunc) сторону. Но все же хотелось бы разобраться, почему так происходит? smile Ведь по правилам 0,5 округляется до 1. А Delphi округляет до 0. При этом 1,5 округляется до 2 и 2,5 до 2 !!! 3,5 до 4 и 4,5 до 4 !!! И так далее. Что это? Ошибка Borland? Или какая-то неизвестная тонкость функции Round?

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

Есть у кого мнение по этому поводу?


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
<Spawn>
Дата 11.3.2005, 06:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Око кары:)
****


Профиль
Группа: Экс. модератор
Сообщений: 2776
Регистрация: 29.1.2003
Где: Екатеринбург

Репутация: 44
Всего: 64



Цитата
Целью было узнать, почему так происходит. Почему Round округляет не так, как от нее ждут?

Это не ошбика Борладн это особенность представления дробных чисел в FPU, и, если я правильно помню, то именно от того, что 0.5(и некоторые другие, приведенные тобой числа), не могут быть представлены конечной двоичной дробью, в результате чего в реальности число ставновится чем то вроде - 0.499999999999999999999999999999999.

Где то на этом форуме недавно была ссылка на статью, хорошо это обьясняющюю, но найти ее, к сожалению, я не могу.

Это сообщение отредактировал(а) <Spawn> - 11.3.2005, 06:06


--------------------
"Для некоторых людей программирование является такой же внутренней потребностью, подобно тому, как коровы дают молоко, или писатели стремятся писать" - Николай Безруков.
PM MAIL ICQ   Вверх
Alex
Дата 11.3.2005, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

Репутация: 80
Всего: 162



Цитата
Где то на этом форуме недавно была ссылка на статью, хорошо это обьясняющюю, но найти ее, к сожалению, я не могу.

http://forum.vingrad.ru/index.php?showtopic=44001&hl=


--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
Akina
Дата 11.3.2005, 09:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: нет
Всего: 454



Цитата(Poseidon @ 11.3.2005, 05:05)
При этом 1,5 округляется до 2 и 2,5 до 2 !!! 3,5 до 4 и 4,5 до 4 !!! И так далее. Что это? Ошибка Borland? Или какая-то неизвестная тонкость функции Round?

Хотя это - следствие представления числа в бине, но попутно замечу, что есть термин "бухгалтерское округление" - то что ОБЯЗАНО использоваться в любых денежных расчетах. Так вот, по нему половинка округляется не вниз и не вверх, а к БЛИЖАЙШЕМУ ЧЕТНОМУ. И это определено соотв. стандартом, международным кстати. Вот такие пироги...


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
RST8
Дата 11.3.2005, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 232
Регистрация: 8.12.2004

Репутация: 1
Всего: 1



Так чем же можно округлить число по правилам до какого нибудь знака после запятой?
--------------------
Посадка, с места которой можно уйти на собственных ногах, считается удачной!
PM   Вверх
Петрович
Дата 11.3.2005, 22:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

Репутация: 25
Всего: 55



Цитата(RST8 @ 11.3.2005, 21:59)
Так чем же можно округлить число по правилам до какого нибудь знака после запятой?

Дык неужели из темы не стало ясно что все зависит от того какие правила имеются ввиду. Много их, правил-то, и все разные.



--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
SPrograMMer
Дата 11.3.2005, 22:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Спамер :)
**


Профиль
Группа: Участник
Сообщений: 442
Регистрация: 5.11.2004
Где: Краснодар

Репутация: 2
Всего: 6



Цитата
Дык неужели из темы не стало ясно что все зависит от того какие правила имеются ввиду. Много их, правил-то, и все разные.

smile
У меня что-то родилось:
Пусть наше 0.5 представляется в виде 0.499999999999999999999, а нам нужно всё это округлить до целых. Поступаем следующим образом:
1. Округлаем до того знака, до которого задавли число, то есть, в числе 0.5 одна цифра после запятой => округляем до одного знака после запятой (можно RondTo`ом воспользоваться).
Вот только что при этом получится? по идее 0.49999999999999 должно превратиться в 0.5
2. Округлаем (тут же) полученное число до нужного.

Код

  X:=0.5;
  Y:=Round(RoundTo(X,-1));  // оч хочется что б в y стало 1.




--------------------
животное = зверь
законченный гентушник
PM MAIL ICQ Jabber   Вверх
Петрович
Дата 12.3.2005, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

Репутация: 25
Всего: 55



Посмотри описания функций RoundTo и SimpleRoundTo:

Цитата
RoundTo uses “Banker’s 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 rounds to an even number in the case that AValue is not nearer to either value.

The following examples illustrate the use of RoundTo:

Expression Value

RoundTo(1234567, 3) 1234000
RoundTo(1.234, -2) 1.23
RoundTo(1.235, -2) 1.24
RoundTo(1.245, -2) 1.24

Note: The behavior of RoundTo can be affected by the Set8087CW procedure or SetRoundMode function.

Цитата
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.

The following examples illustrate the use of SimpleRoundTo:

Expression Value

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


А если проще:

Функции RoundTo и SimpleRoundTo используют несколько разные алгоритмы в случаях, когда округляемое число расположено точно посередине между двумя значениями, имеющими заданное число значащих разрядов. Функция RoundTo в этом случае округляет до четного числа. А функция SimpleRoundTo в этом случае округляет до большего числа.

Так что выбирай то что тебе надо.



--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Santer
Дата 12.3.2005, 02:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 10.3.2005

Репутация: нет
Всего: нет



Вот вам еще один способ округления: к округляемому числу прибавляем 0.5 и отбрасываем дробную часть
PM MAIL   Вверх
Poseidon
Дата 12.3.2005, 04:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Всем спасибо за ответы smile
В заключении темы хотелось бы все-таки выяснить, так есть ли в Delphi функция, каторая выполняла бы то, что задокументировано для Round ? Т.е. функция, каторая округляла бы по общепринятым правилам, а не по каким-либо бухгалтерским или еще. Чтоб <?,5 округляло к меншему, а >=?.5 - к большему. Или все таки придется написать такую функцию самому?


Santer
Цитата
Вот вам еще один способ округления: к округляемому числу прибавляем 0.5 и отбрасываем дробную часть
Интересный способ. Как говорится, все гениальное - просто. Не плохо начал (это ведь твое парвое сообщение)! Так и держи.


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
Alex
Дата 12.3.2005, 10:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

Репутация: 80
Всего: 162



Цитата(Poseidon @ 12.3.2005, 04:37)
В заключении темы хотелось бы все-таки выяснить, так есть ли в Delphi функция, каторая выполняла бы то, что задокументировано для Round ? Т.е. функция, каторая округляла бы по общепринятым правилам, а не по каким-либо бухгалтерским или еще. Чтоб <?,5 округляло к меншему, а >=?.5 - к большему. Или все таки придется написать такую функцию самому?

Ты так и не понял проблемы.


--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
Poseidon
Дата 12.3.2005, 20:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Alex
Цитата
Ты так и не понял проблемы.
Пожет быть и не понял полностью. Вот что понял, так это то, что Round не округлит так, как в школах учат. Может потому, что
Цитата
половинка округляется не вниз и не вверх, а к БЛИЖАЙШЕМУ ЧЕТНОМУ
может потому, что
Цитата
0.5(и некоторые другие, приведенные тобой числа), не могут быть представлены конечной двоичной дробью, в результате чего в реальности число ставновится чем то вроде - 0.499999999999999999999999999999999.
может еще по какой причине.
Это действительно проблема, т.к. в книге по Delphi написано буквально следующее:
Цитата
  Функция Round(n) возврещает целое, полученное путем округления n по известным правилам
Может быть следует задать авторам этой книги вопрос, а что значит "известные правила"? Думаю это будет лишним. Если спросить у любого школьника (старших классов): "К чему округлиться 3,5?", то он сразу же ответит к 4." А к чему округлиться 3,4?" - "К трем." Это я думаю и есть известные правила.
Даже в справке Delphi написано
Цитата
Round returns an Int64 value that is the value of X rounded to the nearest whole number
На сколько я понял, перевод этого звучит так: "Round возвращает значение Int64, каторое является значением Х, округленным к самому близкому целому числу. Коментарии я думаю излишни.

PS. Хотелось бы все таки узнать, есть ли та функция, что округлит 3,5 к 4 ("по известным правилам"). Как видно Round не справляется.
Alex, лично к тебе: В одной из других тем (не так давно) ты писал следующее:
Цитата
А я в душе человек ленивый и ужасно не люблю изобретать велосипеды я ищу уже написанное стандартное и им пользуюсь (хотя иногда на поиски уходит не один месяц  ).
Так вот подскажи, может нашел что? Или может в FAQ что-нибудь есть по этому поводу? Написать такую функцию не проблема, но
Цитата
Дело в том, что достаточно грамотные и знающие программиста порой не знают о существовании таких нужных и полезных функций. Но их можно понять, эти функции появились в Delphi не так давно, по-моему, начиная с 5 версии

и
Цитата
Если уж учить так, учить и если показывать пример то самый правильный и может быть самый навороченный, но в нем учтены все подводные камни, о которых вам известно.


Как говорится: "Модератор всегда прав" (p0s0l)

Это сообщение отредактировал(а) Poseidon - 12.3.2005, 20:21


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1176 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.