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

Вниз

Округление   Найти похожие ветки 

 
Vick ©   (2003-03-31 16:06) [0]

Доброго всем дня! Может кто знает, как в Делфи округлить число до 2-х знаков после запятой, при чем, чтобы округлялось в большую сторону, или нужно свое что-то писать, а то ф-ции типа FormatFloat и FloatToStrF, и т.д. округляют в меньшую сторону :((((
Заранее спасибо за ответ.


 
Anatoly Podgoretsky ©   (2003-03-31 16:10) [1]

Значит что то/кто то поменял контрольное слово процессора.


 
Vick ©   (2003-03-31 16:11) [2]

> Anatoly Podgoretsky
Это как? А как его на место вернуть?


 
Anatoly Podgoretsky ©   (2003-03-31 16:16) [3]

Переинсталлировать Виндоус, если конечто ты точно описал и понял проблему. А так в системе есть сопроцессор, который занимается округлением, и который можно заставить округлять по разному, в том числе и в меньшую сторону и есть плохие программы, которые это сделают. Но мне кажется, что ты где то, что то перепутал.


 
Андрей Сенченко ©   (2003-03-31 16:20) [4]

Только заменой процессора вместе с материнкой, памятью и клвиатурой. Монитор можешь оставить.

ну или написать FORMAT правильно

Например так:
Edit1.Text := FormatFloat("0.00",StrToFloat(Edit1.Text));


 
Alexander Vasjuk   (2003-03-31 16:20) [5]

Vick ©
По правилам округления
до *.*5 округляется в меньшую сторону
а с *.*5 включительно - в большую


или я что то не понял


 
Vick ©   (2003-03-31 16:21) [6]

> Anatoly Podgoretsky
Обижаешь девушку, начальник! :)))) Да ну на самом деле пишу FormatFloat("0.00", 9.245), получаю 9.24.


 
Anatoly Podgoretsky ©   (2003-03-31 16:26) [7]

А теперь попробуй 9,255 и прочитай правила округления, я не зря сомневался, что путаешь.
Округление до четного!, потом нельзя одназначно сказать, что 9.245 хранится как 9.245000000000000000, а не 9.244999999999999999

Чмсла с плавующей запятой, не являются точными, в отличии от чисел с фиксированной запятой. А насчет программ я не шутил, такое встречается и Микрософт об этом предупреждает.


 
Mystic ©   (2003-03-31 16:30) [8]

function UpRoundTo(const AValue: Double; const ADigit: TRoundToRange = -2): Double;
var
LFactor: Double;
const
NINES = 0.999999999999999999999999999999999999999999999999;
begin
LFactor := IntPower(10, ADigit);
Result := Trunc((AValue / LFactor) + NINES) * LFactor;
end;


При этом

procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Lines.Add("0.035 - " + FormatFloat("0.000", UpRoundTo(0.035)));
Memo1.Lines.Add("0.045 - " + FormatFloat("0.000", UpRoundTo(0.045)));
Memo1.Lines.Add("0.049 - " + FormatFloat("0.000", UpRoundTo(0.049)));
Memo1.Lines.Add("0.051 - " + FormatFloat("0.000", UpRoundTo(0.051)));
end;


возвращает

0.035 - 0,040
0.045 - 0,050
0.049 - 0,050
0.051 - 0,060


Это Вас удовлетворит?


 
Vick ©   (2003-03-31 16:31) [9]

> Anatoly Podgoretsky

А могло это контрольное слово испортиться, когда комп круто завис?


 
Alexander Vasjuk   (2003-03-31 16:32) [10]

Anatoly Podgoretsky © (31.03.03 16:26) Округление до четного!,

Русские правила - см. выше
IMHO в Delphi "русские правила".

9.245000000000000000, а не 9.244999999999999999
100%


 
Anatoly Podgoretsky ©   (2003-03-31 16:35) [11]

Vick © (31.03.03 16:31)
Не конечно, да и нарваться на такую неприятную программу редкость, так что тебе дала проверка для 9,255


 
Vick ©   (2003-03-31 16:40) [12]

Я выяснила, что это у меня навреное что-то с самим приложением, потому что создала новое и проделала то же самое - все нормально...


 
Anatoly Podgoretsky ©   (2003-03-31 16:44) [13]

Тогда вполне возможно, что мое предположение насчет контрольного слова спопроцессора было верным.


 
Alexander Vasjuk   (2003-03-31 16:44) [14]

Vick © (31.03.03 16:40)
:) Классный способ устранять ошибки! Надо бы свои программы переписать пару раз!


 
Vick ©   (2003-03-31 16:52) [15]

Фигня происходит, когда я пишу
FormatFloat("0.00", (64.5 * cdsDOC_TABLESNACENKA.AsFloat) / 6),
где cdsDOC_TABLESNACENKA.AsFloat - это значение поля ClientDataSet, на самом деле оно равно 0.86, но судя по всему какую-то фигню передает... потому что если я пишу
FormatFloat("0.00", (64.5 * 0.68) / 6), то все нормально


 
blackman ©   (2003-03-31 17:09) [16]

Удалено модератором


 
Старшина   (2003-03-31 17:29) [17]

Проблема с cdsDOC_TABLESNACENKA.AsFloat
На самом деле там не 0.68
см. Anatoly Podgoretsky © (31.03.03 16:26)


 
Anatoly Podgoretsky ©   (2003-03-31 17:35) [18]

Vick © (31.03.03 16:52)
ShowMessage(cdsDOC_TABLESNACENKA.AsFloat)


 
NickBat ©   (2003-03-31 18:14) [19]

> округлить число до 2-х знаков после запятой,
> при чем, чтобы округлялось в большую сторону
_______________________________^^^^^^^
Нельзя ОКРУГЛЯТЬ в большую сторону! Можно или округлять по правилам или писать что-то свое. :))

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


 
Mystic ©   (2003-03-31 18:34) [20]

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


У Д. Кнута есть по этому поводу цитата: что все законы, которые теоретически открыли математики, не имеют практического применения: если сложить числа в столбик, а потом сложить их в обратном порядке --- то все время получаются разные результаты.


 
Vick ©   (2003-04-01 10:18) [21]

Доброго всем утра!!!

Обнаружила такую вещь, что если написать
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(FormatFloat("0.00", 9.245));
end;
, то получаем результат 9.25,

а если так
procedure TForm1.Button1Click(Sender: TObject);
var fl: double;
begin
fl:=9.245;
ShowMessage(FormatFloat("0.00", fl));
end;
, получается 9.24.
Как это объяснить?


 
Vick ©   (2003-04-01 10:25) [22]

Что самое интересное, что
procedure TForm1.Button1Click(Sender: TObject);
var fl: Extended;
begin
fl:=9.245;
ShowMessage(FormatFloat("0.00", fl));
end;, получается 9.25.
Возникает другой вопрос, как из real или double преобразовать в Extended?


 
Anatoly Podgoretsky ©   (2003-04-01 10:40) [23]

Очень просто, первый случай - высчитывается на этапе компиляции, второй случай на этапе выполнения. При этом в ячейке памяти fl совсем не обязательно 9.2450000000000000, проверить можно в отладчике, поставив точку останова и начать Ctrk+F5 на слове fl, тогда узначешь точное значение в памяти.
При переходе на повышенную точность Extended, представление немного другое, это означает, что данное число нельзя представить в виде двоичной дроби, это примерно так же как для десятичной дроби 1/3


 
BorisKb ©   (2003-04-01 10:44) [24]

Найди на сайте http://delphi.vitpc.com/index.htm отличную статью про округление и вообще про арифметику в Delphi. Не найдешь - могу выслать.


 
Anatoly Podgoretsky ©   (2003-04-01 10:50) [25]

http://www.delphikingdom.ru/helloworld/reals.htm


 
BorisKb ©   (2003-04-01 10:51) [26]

<Anatoly Podgoretsky > - Она самая :)


 
Vick ©   (2003-04-01 11:00) [27]

> BorisKb ©
Пришли пожалуйста, пролистала все статьи ненашла там.


 
Anatoly Podgoretsky ©   (2003-04-01 11:09) [28]

Vick © (01.04.03 11:00)
Ну я же дал прямую ссылку


 
Vick ©   (2003-04-01 11:12) [29]

Нашла, громное спасибо!!!!


 
Спрашивающий   (2003-04-02 02:34) [30]

Я согласен с NickBat © что работать нужно не с числами а со строкой и кстати это не так то просто как кажется на первый взгляд. Я такую функцию писал около нелели! Хотя поверьте со строками работать умею. Пример не привожу потрму что он соизмерим с исходником проги. И собственно функций используется много, так как много в этом деле подводных камней. Со стандартными функциями округления ничего не сделаете путного для вашего примера.


 
Alexander1966 ©   (2003-04-02 13:20) [31]

У Борланда есть такой хитрый тип: BCD
он округляется по правилам математики.

Пример на C++Builder

double Round(double v,int prec)
{
bcd a=bcd(v,prec); // Вот оно округление
double aa=real(a); // обратно в нужный тип
return aa;
}


 
Anatoly Podgoretsky ©   (2003-04-02 13:33) [32]

С BCD проблем не бывает, поскольку абсолютная точность, а не относительная, но поддержка BCD появилась только в Д6 и то не знаю в каком виде, есть еще предопределенный тип Currency, это BCD 20.4


 
Style   (2003-04-02 13:33) [33]

begin
Caption := FloatToStr(FlRound(3.754545,2));
end;

function FlRound(Fl: double; M: Integer): double;
var
z,i: integer;
begin
z := 1;
for i:= 1 to M do
z:= z * 10;
Result := Ceil(fl * z) / z;
end;


 
NickBat ©   (2003-04-02 14:35) [34]

> Style
Если протестировать твой способ на реальных цифрах, то в некоторых случаях возможны ошибки. :(


 
Style   (2003-04-02 14:40) [35]

>> Ты имеешь в виду Тип Real????



 
NickBat ©   (2003-04-02 15:01) [36]

Нет :)) Я говорил о рабочей программе с которой работает несколько пользователей.
Например в программе произошел подсчет цены за какой-то товар.
Получилось, например, 13.3456 рублей - то есть для бухгалтерии надо показать: 13 руб. 34 коп.
И вот при твоем способе периодически вылетают ошибки, которые зависят от внутреннего представления полученной суммы в компьютере.


 
Nic_B   (2003-04-02 15:46) [37]

Я пользуюсь такой функцией (не помню уже где выдрал :)))
Вроде пока глюков не наблюдалось

function TPLAT.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;



 
NickBat ©   (2003-04-02 16:48) [38]

Одно время пользовался примерами приведенными Nic_B и Style. По логике они похожи. Периодически прибегали пользователи и говорили - "вижу не ту цифру".

Сейчас пользуюсь таким решением:

ss:=FloatToStr(Sum);
if pos(",",ss)>0 then delete(ss,pos(",",ss)+1+Sign,255);
Result:=StrToFloat(ss);

Где разделитель целой и дробной части "," а Sign - сколько знаков после запятой оставить.


 
pasha676   (2003-04-02 17:25) [39]

2NickBat

А не пробывал умножать брать trunc и делить. Имхо ничуть не хуже, а решение более простое.


 
NickBat ©   (2003-04-02 17:36) [40]

Ухх..
Пусть есть число: 14.34
В компьютере оно может храниться как 14.339999999999, но отражаться на экране оно будет как 14.34!!
Если попробывать отбросить третий знак после запятой, то получим на выходе 14.33 - вот и вся математика.



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

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

Наверх




Память: 0.56 MB
Время: 0.015 c
14-54824
Num Lock
2003-04-01 07:54
2003.04.17
Поздравляю всех с Днём Чупа-Чупса!


3-54499
malkolinge
2003-03-28 18:51
2003.04.17
Filter? Filtered IBX


3-54463
kos
2003-03-29 11:41
2003.04.17
Каким образом можно узнать, существует ли какое-либо значение в т


14-54832
Dimodim
2003-03-29 08:51
2003.04.17
Как вычислить в Дельфи интеграл?


1-54706
AlexMax
2003-04-04 21:59
2003.04.17
Как програмно показать Hint...