Форум: "Основная";
Текущий архив: 2004.02.13;
Скачать: [xml.tar.bz2];
ВнизГрязь в округлении Найти похожие ветки
← →
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;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.012 c