Просьба проверить.

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ответить
Аватара пользователя
WAYFARER
энтузиаст
Сообщения: 567
Зарегистрирован: 09.10.2009 00:00:04
Откуда: г. Курган

Просьба проверить.

Сообщение WAYFARER »

Толи лыжи не едут, толи еще что?


Код: Выделить всё

 var
i, ii: Real;
b: integer;
begin
i := Frac(X)*100;
ii := Frac(i);
 


x=0.065 - ii=0.5 - Верный результат
x=11.085 - ii=0.5..7 - Верный результат
x=11.065 - ii=0.4999999999 (и так если во 2-ом символе от запятой число от 3 до 8 )
x=1.065 - ii=0.49999999999 и т.д. и т.п.

Ткните носом пожалуйста!

Добавлено спустя 34 минуты 30 секунд:
Если использовать тип Extended то кол-во ошибок сокращается, но погрешности все равно есть...
Последний раз редактировалось WAYFARER 19.02.2011 23:21:28, всего редактировалось 1 раз.
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

что это за адские вычисления, что вы вычисляете ? Через несколько последовательных преобразований ошибка будет накапливаться . И повышение разрядности переменной тут не спасет

Добавлено спустя 9 минут 44 секунды:
возможно, ошибка в логике вычисления
Аватара пользователя
WAYFARER
энтузиаст
Сообщения: 567
Зарегистрирован: 09.10.2009 00:00:04
Откуда: г. Курган

Сообщение WAYFARER »

Пост поправил, лишнее убрал, дабы понятней было. :)
Ism писал(а):что это за адские вычисления, что вы вычисляете

И нет там адских вычислений, обычное бухгалтерское (банковское) округление(если цифра перед пятеркой - четная, то округление вниз, иначе вверх )

Добавлено спустя 5 минут 43 секунды:
Мне собственно и хотелось бы выяснить причину погрешности.
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

попробуйте использовать ValReal

Добавлено спустя 1 минуту 32 секунды:
А вообще вот решение
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

может использовать функцию

http://4programmers.org.ua/programming/ ... posle.html

Код: Выделить всё

procedure TForm1.Button1Click(Sender: TObject);
var
  i,ii:real;
begin
  i := Frac(11.065)*100;
  ii := Frac(i);
  Edit1.Text:=FloatToStr(ii);
end;       


результат 0.5
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

под 32-х битной виндой может и так, а под 64-х битным линуксом или виндой результат будет другой. Это обусловлено работой функции Frac
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Что именно с frac ? Вообщето функции должны везде работать одинаково.
Аватара пользователя
WAYFARER
энтузиаст
Сообщения: 567
Зарегистрирован: 09.10.2009 00:00:04
Откуда: г. Курган

Сообщение WAYFARER »

Padre_Mortius писал(а):А вообще вот решение

К сожалению нет там решения:( Этого идиотизма в нужном виде нигде нет.
Padre_Mortius писал(а):попробуйте использовать ValReal

Гениально! Огромнейшее спасибо!
Но все таки интересно почему так происходит?

Ism писал(а):procedure TForm1.Button1Click(Sender: TObject);
var
  i,ii:real;
begin
  i := Frac(11.065)*100;
  ii := Frac(i);
  Edit1.Text:=FloatToStr(ii);
end;       


а попробовать поиграться с числами? 1111.065 у меня дает результат 0,49...
Padre_Mortius
энтузиаст
Сообщения: 1265
Зарегистрирован: 29.05.2007 17:38:07
Откуда: Спб

Сообщение Padre_Mortius »

Но все таки интересно почему так происходит?

В самой функции Frac входящее значение и результат объявлены как тип ValReal, который в свою очередь платформозависимый и описан в файле systemh.inc
Ism
энтузиаст
Сообщения: 908
Зарегистрирован: 06.04.2007 17:36:08

Сообщение Ism »

Да , ошибка имеет место, есть подозрение на глюк. Может прокатит i-trunc(i)

Хотя нет, и здесь ошибка в 10 м знаке. У меня подозрение, что вычисления правильные, а виновата функция FloatToStr она некорректно выводит результат.

Кстати есть еще функция FloatToStrF более умная. http://www.delphisources.ru/pages/faq/f ... F.php.html

Попробуйте положить результат i := Frac(11.065)*100; прямо в какую нибудь базу данных , если есть возможность (это один из па танца с бубном :))

как вариант можно работать с числами как со строками где возможно (например отделять дробную и целую часть)

Добавлено спустя 7 минут 51 секунду:
у меня 32 битная система
Аватара пользователя
WAYFARER
энтузиаст
Сообщения: 567
Зарегистрирован: 09.10.2009 00:00:04
Откуда: г. Курган

Сообщение WAYFARER »

В общем, по поводу банковского округления, гуглил, и кроме вопроса "как реализовать" от множества людей ничего не нагуглил.

может пригодится кому

Арифметическое округления:

Код: Выделить всё

function aRound(X: ValReal; Precision: Integer): ValReal;  
var
i, ii : ValReal;
begin
i := Frac(X)*Precision;
ii := Frac(i);
i := Int(i);
if ii >=  0.5 then i := i + 1;
if ii <= -0.5 then i := i - 1;
aRound := Int(X) + i/Precision;
end;


Банковское округление:

Код: Выделить всё

function bRound(X: ValReal): ValReal;   
var
   i, ii: ValReal;
   b: integer;
begin
i := Frac(X)*100;
ii := Frac(i);
i := Int(i);
if (ii >=0.5) and (ii < 0.6) then
 begin
  b:=StrToInt(Copy(floatToStr(frac(x)),4, 1));
  if (b and 1) = 0  then i := i  else i := i + 1 ;
 Result := Int(X) + i/100;
 end else
 begin
  Result := around(x,100);
 end;                             
end;   

Если кто то решит поправить буду только рад.


Интересная статья "Загадки округления"
Если бы бухгалтер был магом и чародеем, он несомненно решил бы проблему так, чтобы какой-нибудь саблезубый тигр откусил руку, или хотя бы нечетное количество пальцев нашему волосатому пращуру, придумавшему десятичную систему счисления, чтобы в ней не осталось "середины". Но он выкрутился хитрее - половину отбрасываемых пятерок стал округлять вверх, а половину - вниз. Чтобы его не обвинили в личных пристрастиях, критерием стала цифра перед пятеркой - если она четная, то округление вниз, иначе вверх. Это правило и называется правилом "Бухгалтерского" (или "Банковского") округления.


Добавлено спустя 2 минуты 29 секунд:
Ism
Спасибо! Завтра буду ломать голову дальше в чем именно причина.
Ism писал(а):у меня 32 битная система

У меня тоже, завтра еще если времени хватит попробую на других платформах.
Последний раз редактировалось WAYFARER 24.04.2015 23:55:30, всего редактировалось 1 раз.
Аватара пользователя
Иван Шихалев
энтузиаст
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург
Контактная информация:

Сообщение Иван Шихалев »

А зачем банковское округление реализовывать на плавающей точке? Есть же тип Currency.
Аватара пользователя
WAYFARER
энтузиаст
Сообщения: 567
Зарегистрирован: 09.10.2009 00:00:04
Откуда: г. Курган

Сообщение WAYFARER »

Иван Шихалев писал(а):Есть же тип Currency.

А как это сделать? Я с Currency не работал никогда.
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

WAYFARER
Currency - это почти целое число, но с четырмя знаками после запятой. Там округление (если цифр после запятой больше 4-ёх получается) происходит автоматом по бухгалтерскому принципу.
Работать так же, как и с другими простыми типами.
Ответить