Проблема с FPU

Тема в разделе "WASM.BEGINNERS", создана пользователем Sfinks, 18 мар 2006.

  1. Sfinks

    Sfinks New Member

    Публикаций:
    0
    Регистрация:
    18 мар 2006
    Сообщения:
    9
    Написал тут одну прогу на Delphi, посмотрел на размер и ужаснулся - 600кб. Плюнул, решил сделать на ассемблере. Программа считывает с сайта провайдера данные о траффике пользователя за текущий месяц и считает его стоимость.

    Проблема в части расчета стоимости. Вот этот кусок кода:
    Код (Text):
    1.   fldz
    2.     fstp cost
    3.     xor ecx,ecx
    4.     mov esi, @ ad
    5.     mov edi, @ ap
    6. @@:
    7.     mov eax, [esi+4*ecx]
    8.     mov f_adk, eax          ;ad[k]
    9.     mov eax, [edi+4*ecx]
    10.     mov f_apk, eax          ;ap[k]
    11.     .if ecx==0
    12.     mov f_tmp, 50
    13.     fild f_tmp
    14.     fst f_d ;d:=50
    15.     .else
    16.     dec ecx
    17.     mov ebx, [esi+4*ecx] ;ad[k-1]
    18.     inc ecx
    19.     mov eax, f_adk
    20.     mov f_tmp,ebx
    21.     fld f_adk
    22.     fsub f_tmp
    23.     fld1
    24.     fsub
    25.     fst f_d  ;d:=ad[k]-ad[k-1]-1
    26.    .endif
    27.     ;if t>=ad[k]
    28.     fld f_t
    29.     fild f_adk
    30.     fcom
    31.     fstsw ax
    32.     sahf
    33.     .if CARRY?
    34.         fld f_d               ;<---- error  ST(0) = -NAN
    35.         fld f_apk
    36.         fmul
    37.         fld cost
    38.         fadd
    39.         fst cost               ;c:=c+d*ap[k]
    40.     .else
    41.         ;if t>(ad[k]-d)
    42.         fld f_d
    43.         fld f_adk
    44.         fsub
    45.         fld f_t
    46.         fcom
    47.         fstsw ax
    48.         sahf
    49.         .if !CARRY?            ;c:=c+(t-ad[k]+d)*ap[k]
    50.             fld f_d
    51.             fld f_adk
    52.             fadd
    53.             fld f_t
    54.             fsub
    55.             fld f_apk
    56.             fmul
    57.             fld cost
    58.             fadd
    59.             fst cost
    60.         .endif
    61.     .endif
    62.     inc ecx
    63.     cmp ecx, 7
    64.     jne @B
    65. Переменные заданы так:
    66.     f_t         REAL4 ?
    67.     f_d         REAL4 ?
    68.     f_tmp       REAL4 ?
    69.     f_apk       REAL4 ?
    70.     f_adk       REAL4 ?
    71.     cost        REAL4 ?
    72.     ap          REAL4 1.0, 1.8, 1.5, 1.3, 1.2, 1.1, 1.0
    73.     ad          dd 50, 100, 300, 500, 1024, 2048, 5120


    Ошибка возникает в время второго исполнения цикла при fld f_d в ST(0) оказывается -NAN, хотя f_d=42440000h (или 49,0).

    Второй день мучаю отладчик :)

    Вот работающий код на Delpi:
    Код (Text):
    1. ap: array [0..6] of real = (1,1.8,1.5,1.3,1.2,1.1,1);
    2. ad: array [0..6] of integer = (50,100,300,500,1024,2048,5120);
    3. c := 0;
    4.   for k:=0 to 6 do begin
    5.     if k=0 then d:=50 else d:=ad[k]-ad[k-1]-1;
    6.     if t>=ad[k] then
    7.         c:=c+d*ap[k]
    8.     else if t>(ad[k]-d) then
    9.         c:=c+(t-ad[k]+d)*ap[k];
    10.   end;
     
  2. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Замени все fld f_adk на fild f_adk

    Или измени копирование ad в f_adk (fild ad + fstp f_adk), но тогда не забудь исправить одну затесавшуюся fild f_adk
     
  3. Sfinks

    Sfinks New Member

    Публикаций:
    0
    Регистрация:
    18 мар 2006
    Сообщения:
    9
    Прошу прощения, не ту строчку запостил :)

    Должно быть вот так: ad REAL4 50.0, 100.0, 300.0, 500.0, 1024.0, 2048.0, 5120.0 Соответственно все операции с fld.
     
  4. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Честно говоря лень в твоей писанине разбираться ;)

    Достаточно того что у тебя вместо fstp везде fst стоят - переполнение стека FPU гарантировано. Да и бесконечные загрузки\выгрузки в память тут совершенно ни к чему



    Одним словом проще заново переписать. Но сначала стоит разобраться с формулами, чтобы упростить\унифицировать вычисления. Путем элементарных подстановок приходим к выводу, что величина d тут вообще не нужна и все вычисления сводятся к
    Код (Text):
    1. c = c+(b-e)*ap[k],
    2. где e = ad[k-1]+1, начальное значение = 0
    3.     b = ad[k] при t >= ad[k]
    4.           t   при e <= t < ad[k]
    5.           0   при t < e
    Если расчитывать на процы не ниже P6 family (PII,PIII), то все легко и просто реализуется на fcomi и fcmovXX:
    Код (Text):
    1.   lea edi,[ap]
    2.   lea esi,[ad]
    3.   fld f_t                ;f_t
    4.   fldz                   ;c
    5.   fldz                   ;e=ad[k-1]+1
    6. @@:
    7.   fild dword [esi+ecx*4] ;ad[k], для целых fild, для REAL4 fld
    8.   fld st3                ;b=f_t
    9.   fcomi st0,st2          ;сравниваем f_t и e
    10.   fcmovb st0,st2         ;f_t < e -> b=e
    11.   fcomi st0,st1          ;сравниваем f_t и ad[k]
    12.   fcmovnb st0,st1        ;f_t >= ad[k] -> b=ad[k]
    13.   fsub st0,st2           ;b-e
    14.   fmul dword [edi+ecx*4] ;(b-e)*ap[k]
    15.   faddp st3,st0          ;c=c+(b-e)*ap[k]
    16.   fld1
    17.   fadd                   ;новое значение е=ad[k]+1
    18.   fstp st1               ;выбрасываем предыдущее значение е
    19.   inc ecx
    20.   cmp ecx 7
    21.   jl @B
    22.   fstp st0               ;выбрасываем e
    23.   fstp c                 ;сохраняем c
    24.   fstp st0               ;выбрасываем f_t
     
  5. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Sfinks



    На сайте Ms Rem есть туториал по минимизации размера экзешника на Delphi. Ваш пример должен уместиться в 5-6Кб.
     
  6. Sfinks

    Sfinks New Member

    Публикаций:
    0
    Регистрация:
    18 мар 2006
    Сообщения:
    9
    Большое спасибо за помощь. Наконец-то разобрался :) Дело было в переполнении стека FPU