Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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 - вот и вся математика.



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

Форум: "Основная";
Текущий архив: 2003.04.17;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.53 MB
Время: 0.012 c
3-54426
MishaS
2003-03-28 17:02
2003.04.17
Обработка Событий TTable


8-54761
Pat
2003-01-08 02:50
2003.04.17
MediaPlayer


6-54781
Malamba
2003-02-21 09:59
2003.04.17
запуск команд операционной системы из своей проги


7-54930
Andy Eremin
2003-02-27 07:27
2003.04.17
удаление файлов и папок


1-54737
spogi
2003-04-04 00:41
2003.04.17
конкретный символ в TMemo ...





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский