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