Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
1-38780
staryx
2004-02-03 16:21
2004.02.13
WML 1.1


1-38887
h0use
2004-02-04 15:49
2004.02.13
Организация стэка


1-38849
Janbolat
2004-02-02 14:22
2004.02.13
Export to html


14-39013
Тимохов
2004-01-27 10:12
2004.02.13
Почуму не обновляется орешник?


1-38845
Mazer
2004-02-02 15:34
2004.02.13
Как добавить в стандартное контекстное меню свои пункты?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский