Главная страница
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 - вот и вся математика.


 
UDS   (2003-04-02 18:59) [41]

Ну и навертели!!! Я всегда использую самый простой и быстрый способ:

(round(rez*10)/10) // rez-это значение(real),которое округляем до десятых
(round(rez*100)/100) // до сотых
(round(rez*1000)/1000) // до тысячных

и т.д.
а может я не правильно понял вопрос?


 
Style   (2003-04-03 08:24) [42]

NickBat © >>
Я же делаю Ceil округление в большую сторону.
поэтому если число 13.4499999 получиться 13.45..

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


 
Style   (2003-04-03 09:09) [43]

Вот так все отлично работает!

function FlRound(Fl: double; M: Integer): double;
var
z,i: integer;
f: double;
begin
z := 1;
for i:= 1 to M do
z:= z * 10;

f := fl*z;
f := Ceil(f);

Result := f / z;
end;

Проблемма была в следующем фунцкция Ceil это
Result := integer(trunc(x));
If(Frac(x) > 0) then Inc(Result);

Входной параметр trunc - это Extended т.е. если
мы пишем
Ceil(3.77 * 100) то получиться 388. т.е. в Extended появляеться Frac часть и Count возрастает

а если вычисление проводить в отдельной переменной типа Double
то ответ получаеться правильным!



 
Style   (2003-04-03 10:02) [44]

А если нужны большие число то вот так :)

Народ у меня все работает если и 1,999999999 и 1,0000000000001
все округляет вродеправильно посмотрите

function FlRound(Fl: double; M: Integer): double;
var
a,z,i: integer;
j,f: double;
s : string;
begin
z := 1;
for i:= 1 to M do
z:= z * 10;
a := trunc(int(fl));
j := Frac(Fl);
f := j*z;
s := floattostr(f - trunc(Int(f)));
if(s[1] = "0") then
f := Ceil(f);
f := f / z;

if(trunc(int(f)) > 0) then Inc(a);
Result := a + f;
end;


 
Style   (2003-04-03 10:40) [45]

Вот как можно )

function FlRound(Fl: double; M: Integer): double;
var
d : double;
begin
d := intpower(10,M);
if(Fl>0) then
result := Round(fl * d + 0.5) / d else
result := Round(fl * d - 0.5) / d;
end;


 
phantom2040 ©   (2003-04-08 11:59) [46]

Я как-то бился с округлением, вот что я выйскал, в D7 есть функция, RoundTo округляет по мат правилам, но на его работу влияет функция SetRoundMode, SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode;
ее постоянные
rmNearest
rmDown это в меньшую сторону
rmUp это в большую сторону
rmTruncate
причем при значении rmUp округляется все в большую сторону даже если 3 знак =1


 
Silver_   (2003-04-08 12:10) [47]

RoundTo(a+0.001,-2);

результат должен быть:
1.111 = 1.11
1.144 = 1.14
1.145 = 1.15
1.149 = 1.15

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



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

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

Наверх




Память: 0.59 MB
Время: 0.014 c
1-54704
Ик сик
2003-04-03 15:19
2003.04.17
Как создать свой курсор


3-54491
Андрей Королёв
2003-03-30 16:34
2003.04.17
Не получается выполнить обработку Исключительной ситуации


3-54441
Pk
2003-03-28 15:40
2003.04.17
Запретить удаление записей в таблице


3-54403
me2
2003-04-01 11:30
2003.04.17
Как снести IB DescTop Edition


14-54835
handra
2003-03-28 16:00
2003.04.17
Технологии создания ПО