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

Вниз

Вещественные числа...   Найти похожие ветки 

 
Viktoria ©   (2003-06-16 11:20) [0]

Добрый день уважаемые Мастера!

Помогите пожалуйста разобраться с вещественными числами.

Я получила задание, в котором необходимо в теле цикла представить следующее

procedure TForm1.Button1Click(Sender: TObject);
var S:Single;
begin
S:=0;
while S<=0.1 do begin
Memo1.Lines.Add(floattostr(S));
S:=S+0.01;
end;
end;

К сожалению переменная должна быть обязательно типа Single
(Currency и Double к примеру меня полностью выручили, но их нельзя использовать :((( )

После прогона цикла получаю

0
0,00999999977648258
0,0199999995529652
0,0299999993294477
0,0399999991059303
0,0500000007450581
0,0600000023841858
0,0700000002980232
0,0799999982118607
0,0899999961256981
0,0999999940395355

Еще в моем задании сказано, что значения переменной были получены с точностью до 4 знаков,
после запятой.

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

К сожалению я, не очень хорошо умею работать с вещественными числами.

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

Пожалуйста не смейтесь надо мной, но я даже не могу выделить следующие составляющие из вещественного
числа:

Знак Экспонента Мантисса

А что говорить уже о сравнении чисел с необходимой точностью.

Если кто чем может, помогите пожалуйста.
Любая помощь приветствуется.


 
icWasya ©   (2003-06-16 11:23) [1]

Memo1.Lines.Add(FormatFloat("0.0000",S));


 
Skier ©   (2003-06-16 11:25) [2]


> Никаких статей по этому поводу не нашла, видела только статьи
> по проблематике, но по
> решению конкретных задач не встречала.

http://www.delphikingdom.com/helloworld/reals.htm
+ FloatToStrF(...)


 
Viktoria ©   (2003-06-16 11:30) [3]


> icWasya © (16.06.03 11:23)
> Memo1.Lines.Add(FormatFloat("0.0000",S));


Это уже представление числа на выходе, а в программе оно так и остается не преобразовынным.



> http://www.delphikingdom.com/helloworld/reals.htm
> + FloatToStrF(...)


Статью эту читала, но она только описывает проблему.


 
Skier ©   (2003-06-16 11:34) [4]

>Viktoria © (16.06.03 11:30)

> Статью эту читала, но она только описывает проблему.

"Знать проблему значит на половину её решить" :)


> Это уже представление числа на выходе, а в программе оно
> так и остается не преобразовынным.

Да. Оно занимает 10 байт и является Extended.


 
Viktoria ©   (2003-06-16 11:34) [5]

Очень прошу помогите разобраться с разложением числа, т.е. извлечением из переменной типа Single, её мантису, знак и экспоненту.


 
Skier ©   (2003-06-16 11:37) [6]

Милая барышня, а Вы вообще внимательно смотрели на
функцию FloatToStrF(...) и её параметры ?


 
alexvan ©   (2003-06-16 11:49) [7]

FloatToStrF(Value: Extended; Format: TFloatFormat; Precision, Digits: Integer): String;

type
TFloatFormat = (ffExponent, ffFixed, ffGeneral, ffNumber, ffCurrency);


 
Viktoria ©   (2003-06-16 12:40) [8]


> Skier © (16.06.03 11:37)
> Милая барышня, а Вы вообще внимательно смотрели на
> функцию FloatToStrF(...) и её параметры ?


> alexvan © (16.06.03 11:49)
> FloatToStrF(Value: Extended; Format: TFloatFormat; Precision,
> Digits: Integer): String;
>
> type
> TFloatFormat = (ffExponent, ffFixed, ffGeneral, ffNumber,
> ffCurrency);


Да но эта функиция переводит вещественное число в строку,
в принципе извлечь отсюда можно всё, что угодно.

Но как же быть с моим заданием

> Еще в моем задании сказано, что значения переменной были
> получены с точностью до 4 знаков,
> после запятой.


var S:Single;
begin
S:=0.1;
if S=0.1 then begin
end;


Проверок подобного типа не провести со строкой.
Или просто необходимо проверить два числа

if Singl1=Singl2 then ...

С точностью 4-х знаков после запятой.

Может условие можно изменить как-то?

Помогите пожалуйста.


 
alexvan ©   (2003-06-16 12:44) [9]

Я не совсем понял суть задания. Но строку-то тоже можно вернуть обратно StrToFloat()


 
Skier ©   (2003-06-16 12:45) [10]


> Или просто необходимо проверить два числа
>
> if Singl1=Singl2 then ...

Именно так и делай !


 
Skier ©   (2003-06-16 12:50) [11]


> значения переменной были
> > получены с точностью до 4 знаков,
> > после запятой.

Были получены в строке.
Как же ещё ты из получишь ?! :)
Или я что-то не понимаю ?


 
Viktoria ©   (2003-06-16 14:13) [12]

Singl1 - переменная эталон.

К примеру:

0.0001

А Singl2 - переменная которая получена

0.00013

При сравнении таких чисел мы равно не получим, но так как по заданию точность у нас 4 десятичных цифры, значит остальное нужно обнулить, чтобы Singl2 тоже получилась 0.000100000000...

Насколько я поняла нужно два раза перед тем как Singl2 передать в условие, сделать
FloatToStrF (обрезать) и
StrToFloat и только потом уже передавать...

Но можно ли изменить условие так, чтобы проверка осуществлялась должным образом, без ошибок, и чтобы StrTo два раза не вызывать?


 
Skier ©   (2003-06-16 14:22) [13]

>Viktoria © (16.06.03 14:13)
Можно поиграться с управляющим словом сопроцессора,
т.е. с 8 и 9 битами этого слова
(Если ты читала статью ты знаешь о чём речь).
Только не забудь потом восстановить всё как было
(используй try-finally-end)


 
icWasya ©   (2003-06-16 15:52) [14]

>... просто необходимо проверить два числа
> if Singl1=Singl2 then ...
>С точностью 4-х знаков после запятой.

if (abs(Singl1-Singl2)<0.0001 then ...



 
_ALEXey_ ©   (2003-06-16 16:52) [15]

А если так проверять: If Trunc(Singl1*10000)=Trunc(Singl2*10000) then ......

Экспонетна: Trunc(Singl1)
Мантисса: Frac(Singl1)
Знак: If Singl1 < 0
then <значит "минус">
else <значит "плюс">;


По-моему должно работать, если я правильно понял задание.


 
Anatoly Podgoretsky ©   (2003-06-16 17:12) [16]

Viktoria © (16.06.03 11:30)
А в программе и не получится, это же числа с плавающей запятой, а не с фиксированной.
Жталоном являяется число 0,02 - его как не окнугляй все равно 0,02 никогда не получишь, а только 0,02+-дельта


 
Александр-И ©   (2003-06-16 17:58) [17]

В модуле Math есть такие функции и процедуры:
1. function RoundTo(const AValue: Double; const ADigit: TRoundToRange): Double; - округление вещественных чисел до заданной точности.
2. procedure Frexp(const X: Extended; var Mantissa: Extended; var Exponent: Integer; - Вычисление мантиссы и порядка заданной величины/
3. Учтите матчасть, милая барышня!



 
Александр-И ©   (2003-06-16 18:06) [18]

Ваш пример:

procedure TForm1.Button1Click(Sender: TObject);
var S:Single;
E:Extended;
begin
S:=0;
E:=S;
while S<=0.1 do begin
E:=RoundTo(S,-4);
Memo1.Lines.Add(floattostr(E));
S:=S+0.01;
end;
end;


 
Viktoria ©   (2003-06-16 18:12) [19]


> Anatoly Podgoretsky © (16.06.03 17:12)
> Viktoria © (16.06.03 11:30)
> А в программе и не получится, это же числа с плавающей запятой,
> а не с фиксированной.
> Жталоном являяется число 0,02 - его как не окнугляй все
> равно 0,02 никогда не получишь, а только 0,02+-дельта


А откуда вы взяли такой эталон?
Мне не совсем понятно.


 
Anatoly Podgoretsky ©   (2003-06-16 21:07) [20]

Опытном путем, на самом деле конечно не только это число, а любое производное от него, деленое/умноженное на 2^N, что равносильно сдвину порядка на один разряд, просто подобное число невозможно представить в виде двоичной дробе, как нельзя представить 1/3 в виде десятичноей дроби. Его подлая сущность проясляется очень наглядно для Single, для другой точности тоже самое, только наблюдать надо отладчиком, поскольку при выводе производится округление.


 
Viktoria ©   (2003-06-16 22:54) [21]


> Anatoly Podgoretsky © (16.06.03 21:07)
> Опытном путем, на самом деле конечно не только это число,
> а любое производное от него, деленое/умноженное на 2^N,
> что равносильно сдвину порядка на один разряд, просто подобное
> число невозможно представить в виде двоичной дробе, как
> нельзя представить 1/3 в виде десятичноей дроби. Его подлая
> сущность проясляется очень наглядно для Single, для другой
> точности тоже самое, только наблюдать надо отладчиком, поскольку
> при выводе производится округление.


А можно примерчик? Расскажите пожалуйста, как вы наблюдаете это через отладчик?

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


> if (abs(Singl1-Singl2)<0.0001 then ...


Этот мне кажется наиболее применительным, так как позволяет варьировать различной точностью.

А если говорить про неправильные двоичные дроби, то если я вас правильно поняла, то округляй я 0.02 до 3-х чисел, 5-ти и т.д.,
все равно на выходе будет неправильная дробь. Таким образом, мои первые предположения об округлении функциями FloatToStrF были неверны.

Всех хочу поблагодарить, за то, что приняли участие и помогли мне разобраться.

Если у кого-то еще есть подобные схемы проверок в условиях, циклах и т.д., то со своей стороны я была бы очень признательна за любую помощь.



 
Anatoly Podgoretsky ©   (2003-06-17 08:02) [22]

Ну поступим проще
var
S: Single;
begin
S := 0.02;
Label1.Caption := FloatToStr(S);
S := Trunc(S*100)/100; // часто рекомендуют именно этот путь
Label2.Caption := FloatToStr(S);
end;

Поставь точку останова на первой строке, а на S нажми F5 и дальше по шагам наблюдай в окне отладчика значения переменной, тоже проделай для Double и Extended


 
Anatoly Podgoretsky ©   (2003-06-17 09:48) [23]

Вот еще один наглядный пример "округления" до двух знаков


procedure TForm1.Button1Click(Sender: TObject);
var
I : Integer;
S : Single;
D : Double;
E : Extended;
begin
S := 0;
D := 0;
E := 0;
for I := 1 to 100 do begin
S := Trunc((S + 0.02) * 100) / 100;
D := Trunc((D + 0.02) * 100) / 100;
E := Trunc((E + 0.02) * 100) / 100;
Memo1.Lines.Add(FloatToStr(S));
Memo2.Lines.Add(FloatToStr(D));
Memo3.Lines.Add(FloatToStr(E));
end;
Label1.Caption := FloatToStr(S);
Label2.Caption := FloatToStr(D);
Label3.Caption := FloatToStr(E);
end;


 
Viktoria ©   (2003-06-17 13:35) [24]


> Anatoly Podgoretsky © (17.06.03 09:48)


Результат выполнения первой программы

Label1 - 0,0199999995529652
Label2 - 0,00999999977648258

Результат выполнения второй программы

Для Single

...
1,39999997615814
1,4099999666214
1,41999995708466
1,42999994754791

Для Double

...
1,43
1,44
1,45

Для Extended

...
1,81
1,83
1,85

В первом случае округления не произошло, даже число изменилось, так и должно быть? Почему число изменилось.

Во втором случае наглядно видно на Single...

Подскажите пожалуйста, как вызвать отладчик, когда поставлен Break Point и идет трассировка.




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

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

Наверх




Память: 0.54 MB
Время: 0.022 c
14-97879
Видеоман
2003-06-09 23:08
2003.06.30
Как склеить mpg-файлы?


1-97590
Helium
2003-06-19 03:52
2003.06.30
Интерфейс Win XP (Luna)


14-97824
BaRToV
2003-06-02 02:43
2003.06.30
HTML Help WorkShop 4.74


3-97539
niko4543
2003-06-06 15:30
2003.06.30
BLOB


11-97563
lamachok
2002-10-19 14:27
2003.06.30
о нем