Баг с FPU???

Тема в разделе "WASM.BEGINNERS", создана пользователем CrazyFun, 26 сен 2005.

  1. CrazyFun

    CrazyFun New Member

    Публикаций:
    0
    Регистрация:
    26 сен 2005
    Сообщения:
    129
    прога под делфи(в универе тока оно стоит). При отладке выявился баг.



    procedure TForm1.Button1Click(Sender: TObject);



    // по нажатию на кнопку рисуется график функции

    // y=sqrt(x+10)+exp(x)



    var x:integer;

    p,pp:dword;

    a,b,c,d,nx,f,k,t,m,n,y:extended;

    begin

    a:=-10; //[a,b]-область определения

    b:=3;



    c:=-5; //[c,d]-область значений.

    d:=10;



    //t,k,m,n - вычисляемые смешения и маштабные множители.

    t:=(b-a)/(form1.ClientWidth);

    k:=(a*form1.ClientWidth)/(a-b);

    m:=form1.ClientHeight/(c-d);

    n:=(d*form1.ClientHeight)/(d-c);



    // оси координат:

    form1.Canvas.MoveTo(0,round(n));

    form1.Canvas.lineto(form1.ClientWidth,round(n));

    form1.Canvas.MoveTo(round(k),0);

    form1.Canvas.LineTo(round(k),form1.ClientHeight);



    // вычмсляем значение первой точки графика:

    x:=0;

    nx:=(x-k)*t;

    f:=sqrt(nx+10)+exp(nx); (***)

    f:=f*m+n;

    form1.Canvas.MoveTo(x,round(f));

    form1.canvas.pen.color:=clred;



    /************************************************

    так вот при B=3 а=-10 в строке (***) возникает ошибка

    типа неверное значение аргумента для ф-ции.

    при отладке(бряк на сроку с формулой и дальше в

    окне CPU) выяснилось что складывая числа

    10 и -10 FPU получает число -8.****** и при попытке

    выполнить fsqrt FPU возбуждает исключения.

    при b=1 b b=3 такого нет.



    вопрос:какого хера оно так?



    **************************************************/



    //дальнейший код для завершонности картины.

    for x:=0 to (form1.ClientWidth) do begin

    nx:=(x-k)*t;

    y:=nx+10;

    pp:=p;

    f:=sqrt(nx+10)+exp(nx);

    f:=f*m+n;

    p:=round(f);







    //form1.canvas.Pixels[x,p]:=clRed;

    if pp<=form1.ClientHeight then begin

    form1.canvas.LineTo(x,p);

    form1.Canvas.MoveTo(x,p);

    end;

    end;

    form1.Canvas.TextOut(0,round(n)+5,floattostr(a));

    form1.Canvas.TextOut(form1.ClientWidth-15,round(n)+5,

    floattostr(b));

    form1.Canvas.TextOut(round(k)+5,0,floattostr(d));

    form1.Canvas.TextOut(round(k)+5,form1.ClientHeight-15,

    floattostr(c));

    form1.Canvas.TextOut(round(k)+5,round(n)+5,'0');

    end;
     
  2. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.331




    По моему, при B=3 и а=-10 (nx+10) будет отрицательным.

    Хотя может я невнимательно смотрел.
     
  3. CrazyFun

    CrazyFun New Member

    Публикаций:
    0
    Регистрация:
    26 сен 2005
    Сообщения:
    129
    в стек он грузи 10 и -10(если вместо sqrt(nx+10) записать sqrt(nx+zz) где zz - extended со значением +10)

    а сложив командой fadd эти значения имеет -8.***



    <font color="red]первое предупреждение за мат. изучаем Правила</font><!--color-->
     
  4. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Это не баг, а твое неумелое обращение с FPU ;)

    Если у тебя на бумажке все сокращается и результат получается точно nx = 10, то в процессоре в результате делений умножений может получиться число 10 ± e, где е погрешность вычисления ~2^(-63) для extended. Самый простой совет - не используй переменные типа extended, где это не нужно. Extended используется внутри процессора для промежуточных расчетов, а переменные обычно используют double и при округлении extended до double эти мизерные ошибки исчезают. Это во-первых, а во-вторых из-за тех же мизерных погрешностей в ответсвенных ситуациях (деление на 0, sqrt,ln) нельзя сравнивать вещественные числа на точное равенство - нужно брать диапазон. В твоем случае, если не поможет double, то придется ввести проверку temp:=nx+10; if temp > 0 then f:=sqrt(temp) else f:=0; f:=f+exp(nx);
     
  5. CrazyFun

    CrazyFun New Member

    Публикаций:
    0
    Регистрация:
    26 сен 2005
    Сообщения:
    129
    а то что в стеке после сложения чисел 10 и -10 получаестся -8.***? или это отладчик гонит?

    в окне фпу так и написано

    st(0)=10

    st(1)=-10

    после fadd

    st(0)=-8.*****



    т.е. погрешность больше?
     
  6. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    За дельфи не ручаюсь, а вот OllyDbg по умолчанию все значения выводит в формате double (53 бита мантиссы, а не полные 64) и ты не первый кто сталкивался с этой "проблемой". В результате вместо 10+e ты видишь 10, но после вычитания эта разница проявляется и получаешь свои -8.***

    Вообще все интеловские и амд-ишные мануалы рекомендуют работать с точностью double, но процессор при инициализии finit устанавливает точность вычислений extended и дельфи ее на double для твоей проги не изменяет.

    Нельзя говорить, что погрешность "большая", просто при огравниченной разрядности и точность ограничена. Например с какой точностью не записывай число 1/3=0.333333.. все равно при умножении на 3 ты получишь не 1.0, а 0.999999.. и только при округлении до меньшего числа разрядов получится 1.0. Поэтому основное назначение extended это промежуточные вычисления и в младших битах могут накапливаться ошибки, которые как правило исчезают при округлении к основному типу double. А вот для чего тебе extended с 64-битной мантиссой - я совершенно не могу понять, т.к. для стандартного разрешения экрана и single за глаза хватвет ;)))



    PS: Прежде чем писать очередной ответ в защиту своей версии о наличии бага в FPU, подумай - как с такими багами америкосы умудряются ракеты к марсу запускать :))
     
  7. CrazyFun

    CrazyFun New Member

    Публикаций:
    0
    Регистрация:
    26 сен 2005
    Сообщения:
    129
    вопщем спасибо, как понял проблема в том что икстендед отображается как дабл в отладчике.

    для чего extended? Я решил что по аналогии с рекомендацией использовать в 32х битном alu 32х битные одиночные переменные неплохо было бы использовать в 80ти битном fpu 80ти битные переменные. Ну и ещё все числа с плавающей точной в проге используются только для вычисления значений, а дальше все приводится к маштабу экрана(хотя конечно и singl хватит иначе график просто выродиться, но всеже).

    хмм а это не в тему но пример мне нравится:):

    0.9(9)=1 точно т.к. 0.9=3*0.3(3)=3*(1/3)=1

    но при ограниченной точности это конечно не так, ведь понятия периодической дроби тогда нет.
     
  8. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    В мануалах по оптимизации переменные типа 80-бит extended вообще не рекомедуют использовать, т.к. размер получается не кратным 32битам и читаются\пишутся в память такие переменные почти вдвое дольше чем 32 и 64 битные. Extended только для промежуточных вычислений или для специальных задач, где нужна повышенная точность - но там уж спецы все погрешности должны оценивать.