Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.02.13;
Скачать: CL | DM;

Вниз

Грязь в округлении   Найти похожие ветки 

 
Goida ©   (2004-02-02 17:52) [0]

Уже битый час пытаюсь избавиться от ошибок округления значений real. Например такой код:
Result := trunc(Num); //Num = 456.78888...889761
i := frac(Num); // i=0.7888...889761
i := 100*i; //i=78.88...89...
i := round(i);//i=80
i := i/100;//i=0.8000000...00000542541
Result := Result + i;

И, естественно, дальше всякие ошибки возникают. Как избавиться от этого мусорррррррра?


 
Тимохов ©   (2004-02-02 17:57) [1]

Не очень понятно в чем проблема,
но может это поможет http://www.delphikingdom.ru/helloworld/reals.htm


 
heady   (2004-02-02 17:58) [2]

function RoundEx(X: Double; Precision: Integer ): Double;
{
Precision :
1 - до целых
10 - до десятых
100 - до сотых
...
}
var
ScaledFractPart, Temp: Double;
begin
ScaledFractPart := Frac(X) * Precision;
Temp := Frac(ScaledFractPart);
ScaledFractPart := Int(ScaledFractPart);
if Temp >= 0.5 then
ScaledFractPart := ScaledFractPart + 1;
if Temp <= -0.5 then
ScaledFractPart := ScaledFractPart - 1;
RoundEx := Int(X) + ScaledFractPart / Precision;
end;

(c) DelphiWorld


 
tchn1 ©   (2004-02-02 18:33) [3]

trunc бьет дробную часть
round округляет
что еще нужно?


 
jack128 ©   (2004-02-02 18:44) [4]


> i := 100*i; //i=78.88...89...
> i := round(i);//i=80
любопытное у тя округление..Погрешности при операциях с вещ. числами, конечно, есть но явно не 2-3% ;-)


 
snake1977   (2004-02-02 18:58) [5]

вариант, если использовать целые числа , а потом конечный результат делить на соответсвенное 100 для сотых 1000 для тысячных и т.д.
например для выражения y=x^2+x+1 будет примерно так

y:=(SQR(Round(x*100))+Round(x*100)+1)/100;

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


 
heady   (2004-02-02 19:25) [6]

самое поганое, что round(4.5)=4


 
jack128 ©   (2004-02-02 19:46) [7]


> самое поганое, что round(4.5)=4
это банковское округление..Тип округления определяется какой то функцией в модуле system


 
heady   (2004-02-02 19:49) [8]

"нет такой хоккей нам не нужен" :)
кстати еще есть функция int


 
Verg ©   (2004-02-02 20:13) [9]


> jack128 © (02.02.04 19:46) [7]
>
> > самое поганое, что round(4.5)=4
> это банковское округление..Тип округления определяется какой
> то функцией в модуле system


Это не поганое, это нормальное округление - дробная часть точно равна 0.5 - округляем до ближайшего четного, а не в сторону большего.
Тип округления устанавливается и в слове управления сопроцом, а по-умолчанию оно именно такое 0.5 - к четному.


 
Yurko   (2004-02-03 09:51) [10]

function MyRound(x: Double): Integer;
begin
Result := Trunc(x) + Trunc(Frac(x) * 2);
end;


 
Goida ©   (2004-02-03 09:54) [11]

Все ерунда. Я по поводу грязи. Ничего не помогает:(( Ни int, ни trunc, ни frac - в результате я получаю одно и то же - МУСОР в где-нибудь в милионных долях.
Мне посоветовали перед присваиванием такого числа, присвоить ему сначала ноль. Попробую, может получится.


 
Goida ©   (2004-02-03 09:56) [12]

Спасибо Yurko ,но это пройденный этап. Не помогает.


 
Goida ©   (2004-02-03 09:57) [13]

Еще добавлю, что эта ошибка возникает имено в процессе длительных вычислений. Т.к. если просто взять мой код присвоить начальному числу значение, скажем 65632.7888...8889265, то после округления все пройдет гладко.


 
Romkin ©   (2004-02-03 10:49) [14]

Я бы рекомендовал просто ознакомиться со ссылкой в [1], или Кнута почитать. Накопление погрешностей в длительных вычислениях на цифровых ЭВМ неизбежно, а величина их зависит от алгоритма, формата чисел и тд...
И чем так беспокоит погрешность в миллионной доле? Траекторию спутника считаешь?
Округление половины к четному, кстати, как раз и повышает устойчивость вычислений, и довольно естественно, поскольку получается round(round(a + 0.5) - 0.5) = a для любого целого a. А если к большему, то такого не получится


 
Goida ©   (2004-02-03 10:55) [15]


> Romkin

Я не совсем правильно выразился. Длинные вичисления по количеству присваивания значений одной переменной... Вообщем, наверно, лучше будет объяснить ситуацию:
Из БД у меня берется число, скажем 36572.8, а в компе оно представляется как 36572.79999...98134 Думал, что с округлением получится избавиться от этой проблемы, ан нет... Вот такая проблема: нужно избавиться от такого мусора.


 
Тимохов ©   (2004-02-03 11:03) [16]


> Goida © (03.02.04 10:55) [15]

Уважаемый.
Вы не ознакомились со ссылкой из 1, а зря.
Как вы думаете, как будет представлена на компе число 1/5?
Есть мысли?
Правильный ответ: НЕ 0.2!
Удивлены?
См. ссылку 1.
Все.


 
Sandman25 ©   (2004-02-03 11:09) [17]

Из БД у меня берется число, скажем 36572.8, а в компе оно представляется как 36572.79999...98134

Вместо TFloatField нужно использовать TBCDField или TFMTBCDField. И AsString получите именно то, что записано в БД.


 
jack128 ©   (2004-02-03 11:12) [18]


> Из БД у меня берется число, скажем 36572.8, а в компе оно
> представляется как 36572.79999...98134
Ты почто мозги людям пудришь??
TNumericField.DisplayFormat + F1


 
Goida ©   (2004-02-03 11:16) [19]


> Тимохов

Я обязательно посмотрю. Я распечатал ее, но не было пока времени. Потому что занимаюся еще другими проблемами.

> Sandman25
> jack128

Я не использую никакие дополнительные типы. Я делаю это так:
MaxSumm := spPayorder_PayDetail_Get.FieldValues["Моё поле"];


 
Sandman25 ©   (2004-02-03 11:17) [20]

Хранимая что возвращает? DEC(x,y) или FLOAT?


 
jack128 ©   (2004-02-03 11:33) [21]


> MaxSumm := spPayorder_PayDetail_Get.FieldValues["Моё поле"

Label1.Caption := Format("%5.2f",[MaxSumm]);


 
Andriy Tysh ©   (2004-02-03 12:00) [22]

В модуле Math есть хорошая ф-ия RoundTo, но с "банковским округлением", что б ему. Сколько учился в школе, сколько использовал ф-ию Round в Turbo Pascal"е, сколько преподовал детям математику в школе - всегда округление 4.5 давало 5. Если кто-то не согласен, могу на следующий раз привести правило округления. Это ж как ломается детская душа Борлондовскими разработчиками с ихним взглядом на умолчание в округлении, а детя строить наше будущее. А как они будут формировать свою последовательную точку зрения, если им в школе говорят одно, а в программировании - другое. Мне больно и стыдно осознавать эту истину!

А тепер к делу. Я написал свою ф-ию, в которой только две строчки:
SetRoundMode(rmNearest);
Result:=Math.RoundTo(AValue, ADigits);


 
Romkin ©   (2004-02-03 12:10) [23]

Andriy Tysh © (03.02.04 12:00) [22] см Romkin © (03.02.04 10:49) [14] Кажется, я объяснил, зачем округляют половину к четному. Помимо этого и "школьного" округления можно .5 округлять и всегда к меньшему... И все три способа вполне применяются, в зависимости от ситуации.


 
Goida ©   (2004-02-03 18:32) [24]


> Тимохов

Прочитал, но появились новые вопросы. А для решения своей проблемы пользуюсь следующим: перед операцией ставлю Set8087CW(Default8087CE)


 
Тимохов ©   (2004-02-03 19:31) [25]

Может тебе воспользоваться советом 17?


 
Goida ©   (2004-02-04 00:08) [26]

У меня уже все работант. Только не до конца ясно действие этой процедуры Set8087CW(Default8087CE) Может растолкуете?



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

Текущий архив: 2004.02.13;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.032 c
3-38712
Volodya_
2004-01-22 13:02
2004.02.13
QReport


14-39028
NeyroSpace
2004-01-26 11:14
2004.02.13
Передача


8-38971
Layner
2003-10-02 09:38
2004.02.13
TVideoGrabber, поделитесь плз, можно более ранней, Free версией


1-38878
Senti
2004-02-04 15:55
2004.02.13
Как создать класс типа StringList


3-38742
Polevi
2004-01-21 13:56
2004.02.13
Способ хранения дат