LINUX.ORG.RU

Как устранить влияние погрешности при вычислениях с использованием типа Real в Pascal?

 ,


0

1

Решил написать на Pascal свой вариант процедуры str, которая переводит число в строковое представление и при вводе str(12.5:9:3, s) занесет в переменную s строку " 12.500" длиной 9 символов с 3-мя символами после запятой и 3-мя пробелами вначале.

Так вот, при написании процедуры, ответственной за перевод в строковое представление части числа после запятой, возникла проблема.

program Example;

function
    FracPart(n: real): real;
begin
    if n - round(n) >= 0 then
        FracPart := n - round(n)
    else
        FracPart := 1 + n - round(n)
end;

function
    IntPart(n:real): integer;
begin
    if n - round(n) >= 0 then
        IntPart := round(n)
    else
        IntPart := round(n) - 1
end;

function
    IntToChr(n: shortint): char;
begin
    IntToChr := chr(n + 48)
end;

var
    n: real;
    b,i: byte;
    s2: string;
begin
    writeln('Enter a number');
    readln(n);
    writeln('Enter a number of digits after the point');
    readln(b);
    n := FracPart(n);
    s2 := '';
    if n = 0 then
    begin
        if b > 0 then
        begin
            s2 := '.';
            for i := 1 to b do
            begin
                s2 := s2 + '0';
            end
        end
    end
    else
    begin
        if b > 0 then
        begin
            s2 := '.';
            for i := 1 to b do
            begin
                s2 := s2 + IntToChr(IntPart(n * 10));
                n := FracPart(n * 10)
            end
        end
    end;
   writeln(s2)
end.

При b=3 и n равном 5.5 или 5.4 программа выдает корректные ответы .500 и .400. Однако при b=3 и n равном 5.6 или 5.3 программа выдает ошибки вида .599 и .299.

Насколько я понял, ошибка происходит в подпрограмме IntPart, ответственной за выделение целой части дробного числа. В определенной ситуации я ожидаю, что в условии if значение n - round(n) будет 0, а на практике, из-за погрешности вычислений типа real, значением будет -0,00000000001. Из-за этого оператор ветвления отработает не так, как я изначально этого ожидал.

Как устранить влияние погрешности при вычислениях с использованием типа Real в этой и в других моих будущих программах?

Не заниматься ананизмом и взять Trunc Int Frac ?

Morin ★★★★
()

Сама идея изначально неверная. Ты пытаешься одновременно вычислить и записать в нужном формате. А сначала нужно вычислить, а уж потом записать. Скорее всего непонятки в этом, второе выполняется раньше первого.

cadaber ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.