Форум: "Основная";
Текущий архив: 2004.03.14;
Скачать: [xml.tar.bz2];
ВнизЯ, похоже, первый!!! Вопрос про округление. Найти похожие ветки
← →
Тимохов (2004-01-23 13:14) [0]Добрый день, уважаемые.
Вопрос такой.
Процессор (или сопроцессор, не знаю точно) округляет числа exctended по умолчанию до ближайшего четного с случае если число находится точно между целыми.
Т.е. round(1.5) = 2
и round(2.5) = 2
Есть метод setroundmode в параметрах которого я не нашел нужного мне способа окугления, а нужный, это тот, которому нас учили в школе, т.е. должно быть так
round(1.5)=2
round(2.5)=3
round(3.5)=4
round(-1.5)=-2
round(-2.5)=-3
round(-3.5)=-4
Ясно, что rmNearest, rmDown, rmUp, rmTruncate не подходят.
Вопрос: как заставить round работать так как мне нужно?
← →
Defunct (2004-01-23 13:21) [1]Прибавить в числу типа Extended какой-то хвостик Delta.
Например:
Const RoundDelta = 0.000001;
Function MyRound(X:Extended):Integer;
Begin
Result := Round(X + RoundDelta)
End;
ЗЫ: 0.5 округляет в сторону большего числа. Не могли Вас в школе учить так:
round(-1.5)=-2
round(-2.5)=-3
round(-3.5)=-4
т.к. должно быть так:
round(-1.5)=-1
round(-2.5)=-2
round(-3.5)=-3
Хотя, если хотите именно так как Вы написали меняем функцию:
Function MyRound(X:Extended):Integer;
Begin
If X>0 Then Result := Round(X + RoundDelta)
Else Result := Round(X - RoundDelta)
End;
← →
Тимохов (2004-01-23 13:24) [2]Пока есть время (вроде никто не проснуля еще от дауна форума :))) хочу добавить, почему меня это сильно заинтересовало.
Возьмем, например, мой любимый тип TDecimal. Такой же тип есть в MS SQL. Такой же, т.к. при возврате результата из БД vartype = 14, что есть Decimal. Т.е. есть значение в БД, хранимое в Decimal, возвращается как decimal, и работаю я с ним на клиенте как c Decimal. Использую для это стандартные виндовые библиотечные функции VarDecAdd, VarDecRound и т.д. из oleaut32.dll.
Эти функции работают с округлением до ближайшего четного.
При этом!!! Сервер БД с типом decimal работает, т.е. округляет "правильно", т.е. как я описал в исходном вопросе. Вопрос такой: как вы думаете сервер что сам написал реализацию работы с типом decimal или в windows можно установить порядок округления.
Еще хочу добавить, что тот же сервер "правильно" округляет любые дробные типы, например, float.
Интересно, почему такая разница сервера БД и дельфи.
Вообще говоря такое округление типа decimal я проверил в разных языках, например, в VBA. Так тоже округляется до ближайшего четного.
← →
Тимохов (2004-01-23 13:26) [3]
> Defunct © (23.01.04 13:21) [1]
> ЗЫ: 0.5 округляет в сторону большего числа. Не могли Вас
> в школе учить так:
В школе учили, что округление должно идти away from zero.
Разве я не прав?
Могу быть и не прав (давно учился). Но при постановке нам задания на исправление этого недостатка был именно термин "как учили в школе". Сам я не до конца помню, как учили в школе, потому могу и ошибаться.
← →
MBo (2004-01-23 13:33) [4]http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=17998
← →
Юрий Зотов (2004-03-03 17:45) [5]Насколько помню, round выполняет так называемое "бухгалтерское округление", а не обычное математическое. Там действительно в каких-то случаях (не помню точно, в каких) идет округление до ближайшего четного, а в других - до ближайшего целого.
← →
Тимохов (2004-03-03 17:46) [6]
> MBo © (23.01.04 13:33) [4]
Спасибо, вчера я там уже был, правда, почитать пока не успел.
Сейчас все-таки пойду почитаю.
Может будут идеи по поводу TDecimal?
← →
Тимохов (2004-03-03 17:51) [7]
> Юрий Зотов © (03.03.04 17:45) [5]
Round делает всегда до ближайшего четного. Это в доке есть.
← →
Defunct (2004-03-03 17:52) [8]Вообще говоря такое округление типа decimal я проверил в разных языках, например, в VBA. Так тоже округляется до ближайшего четного.
Не пойму причем тут ближайшее четное? Процессор округляется то, что ему дали. Если число будет иметь вид:
1.49999999999999999999999[9]
он округлит до 1,
если будет
1.5000000000000000000000[0]1 - округлит до 2
Добавляя или отнимая Delta вы снимаете неопереденность последнего знака. например:
1.49999999999999999999999[9] + 0.00000001 = 1.50000000999999999999999[9]
PS: Числа вида: 1.500000000000000000000000000000 большая редкость, такое число в Extended виде, впринципе не существует.
← →
Anatoly Podgoretsky (2004-03-03 17:54) [9]Что тогда скажешь про 0,5000000000000000000000
Это число точно представляется при любой точности
← →
Тимохов (2004-03-03 17:54) [10]
> такое число в Extended виде, впринципе не существует.
Как раз такое скорее всего существует. Вот 0.2 точно не существует.
> Не пойму причем тут ближайшее четное?
Почитайте про round
← →
Anatoly Podgoretsky (2004-03-03 17:56) [11]Тимохов © (03.03.04 17:54) [10]
Могу гарантировать 0,02 и производные от него /* 2^n
← →
TButton (2004-03-03 17:57) [12]>Процессор (или сопроцессор, не знаю точно) округляет числа
>exctended по умолчанию до ближайшего четного с случае если
>число находится точно между целыми.
такковы уж правила округления. если заканчивается на пятерку и после нее идет ноль или ваще уже нифига нету, то округляется до ближайшего четного. а по сабжу - Trunc(x+0.5), где х - округляемое число
← →
MBo (2004-03-03 17:57) [13]Trunc, Int и некоторые другие функции временно устанавливают контрольное слово 87 (Set8087CW или ассемблерный аналог), а Round использует то, что есть (штатно - банковское, X.5 к четному)
← →
Defunct (2004-03-03 17:57) [14]Anatoly Podgoretsky © (03.03.04 17:54) [9]
Частный случай.
Тимохов © (03.03.04 17:54) [10]
Вам нужно решить задачу с округлением или просто интересно почему так?
← →
Юрий Зотов (2004-03-03 17:58) [15]> Defunct © (03.03.04 17:52) [8]
> Не пойму причем тут ближайшее четное? Процессор округляется
> то, что ему дали.
При том, что округляет не только процессор. Алгоритм округления определяет еще и используемая функция (в данном случае - round).
> Если число будет иметь вид:...
Хм... Вы уверены, что в этой ветке стоит излагать всем хорошо известные азы арифметики с плавающей точкой? Дело в том, что к сабжу они имеют довольно слабое отношение - речь идет несколько о другом.
← →
TButton (2004-03-03 17:59) [16]>Trunc(x+0.5)
отрицательные будут кривоокругляться.
← →
Тимохов (2004-03-03 18:05) [17]
> Defunct © (03.03.04 17:57) [14]
> Вам нужно решить задачу с округлением или просто интересно
> почему так?
Наезд?
Всем.
Ясно, что взять и окургить готовое чило до нужного резульатат я могу (да хоть с помощью if и setroundmode up + down).
Но если подумать, например, о типе currency. Оно же не число с плавающей точкой. Это просто целое со смешенной точкой. Получается, что в процессе арифим операции может возникнуть ситуация когда появился пятый знак после запятой (в currency из 4). Куда бедет приведение?
Если еще раз сказать про проблему, то получается, что моя программа и, например, excel и MS Sql округляют по-разному.
На самом деле, я не верю, что в MS Sql сам реализовали работу в decimal и currency. Наверняка они пользуются стандартными виндовыми библиотеками. Вот у меня и возникает подозрение, что они умеют устанавливать опции для этих библиотек. Может кто знает?
← →
Defunct (2004-03-03 18:06) [18]Юрий Зотов © (03.03.04 17:58) [15]
> При том, что округляет не только процессор. Алгоритм округления определяет еще и используемая функция (в данном случае - round).
Прошу прошения но приходится представить это: (код функции Random) округление выпоняется одной командой сопроцессора FISTP:
SUB ESP,8
FISTP qword ptr [ESP]
FWAIT
POP EAX
POP EDX
← →
Defunct (2004-03-03 18:07) [19]Err... читать (код функции Round)
← →
Тимохов (2004-03-03 18:10) [20]
> Defunct © (03.03.04 18:07) [19]
А вот теперь, упрямец, наберите intel.ru + search + fistp и почитайте, про все методы округления, в частности про aray from zero. И может вы мне подскажете как этот away from zero учтановить из дельфи?
← →
Тимохов (2004-03-03 18:12) [21]прошу прощения intel.com
← →
Игорь Шевченко (2004-03-03 18:13) [22]Есть такая статья Антона Григорьева на "Королевстве Delphi", там вроде все написано...
http://www.delphikingdom.com/helloworld/reals.htm
← →
Юрий Зотов (2004-03-03 18:16) [23]> Defunct © (03.03.04 18:06) [18]
Вот именно. Здесь нет FLDCW. А если бы была, то это был бы уже другой алгоритм - о чем и было сказано.
← →
Юрий Зотов (2004-03-03 18:18) [24]> Тимохов © (03.03.04 18:10) [20]
Модуль System, функция Set8087CW.
← →
Тимохов (2004-03-03 18:18) [25]
> Игорь Шевченко © (03.03.04 18:13) [22]
И ее я знаю. В этом деле она реально не помошник :(((
Всем.
Представьте, что практически все что есть по этой теме я прочел. Даже нашел реализацию работы с decimal и currency, вроде как от самого майкрософта (в чем сомневаюсь).
Т.е. простые ответы не помогут :(((((
← →
MBo (2004-03-03 18:19) [26]>Тимохов
>как этот away from zero учтановить из дельфи?
По ссылке закачал файл?
← →
Тимохов (2004-03-03 18:22) [27]
> Юрий Зотов © (03.03.04 18:18) [24]
И ее знаю. Вопрос в том, какие флаги передавать. Реально setroundmode использует только 4 варианта. Судя по описанию на intel.com варинатов окрегления существенно больше. Я, к сожалению, не большой мастер в асме потому не могу понять что надо установить, чтобы было away from zero (т.е. в сторону целого дальше от нуля).
← →
Тимохов (2004-03-03 18:24) [28]
> MBo © (03.03.04 18:19) [26]
Закачал, изучаю.
Спасибо.
← →
Defunct (2004-03-03 18:25) [29]Тимохов © (03.03.04 18:10) [20]
Не понимаю кто из нас упрямец. Я вам кажется подсказал все что можно, более того даже привел команду округления. Теперь Вы знаете, что алгоритм округления осуществялется ни какой-то функцией, а аппаратно зашит в сопроцессор. И есть всего 4 типа округления, определяемых полем RC
RC Round Mode
00 Round to Nearest Closerselect
01 Round Down (toward -
← →
Тимохов (2004-03-03 18:34) [30]
> Defunct © (03.03.04 18:25) [29]
Вот за описание поля RC спасибо - вчера до него не докопался.
Пойду еще покопаю intel.
С типами double, single, extended понятно. Спасибо defunct и MBo.
По указанным типам вопросов более нет (если и есть, сам найду).
Про тип decimal вопрос остался. Как заставить библиотеку oleaut32.dll округлять decimal как-то по другому. Пока у этой библиотеки я наблюдаю всего один способ округления - до ближайшего четного.
При том никакие установки режима округления в процессоре на указанную библиотеку не влияют (проверено).
← →
Defunct (2004-03-03 18:44) [31]2 Тимохов, советую скачать с Intel.com:
Pentium® Processor Family
Developer’s Manual
Очень полезная вещь, весит около 10Mb
← →
Тимохов (2004-03-03 18:53) [32]
> Defunct © (03.03.04 18:44) [31]
Пойду качать...
Спасибо.
А Вы не плохой парень как я вижу :)))))
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.03.14;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.015 c