Математические библиотеки

Discussing libraries simplifying applications development
  • Примеры конечно интересные, но больно уж накручено. Вот бы что-то попроще и помельче. Начать что ли свою библиотеку подобную Box_Lib и Proc_Lib. Единственный минус, что мне сейчас реально нужна бывает только процедура деления. Остальное и выделять то в библиотеку смешно как-то. В самом деле не будешь же выделять простейшее imul eax,ebx, а вот с делением приходится повозиться и тащить в каждую программу кусок вроде нижеприведенного:
    Spoiler:

    Code: Select all

    integer_division:
    ; eax = eax/ebx
    	test	ebx,ebx
    	jnz	@f
    	inc	ebx
    @@:
    	xor	edx,edx
    	div	ebx
    	shl	edx,1
    	cmp	ebx,edx
    	jb	@f
    	inc	eax
    ;@@:
    	ret
    
    Иногда просто хочется иметь простенькие и достаточно эффективные процедуры математики без задействования FPU. Тем более что в некоторых случаях он оказывается слабоватым, к примеру в eBox из-за этого проигрывание видео тормозится, да время расчета с использованием FPU не всегда гарантировано. В общем как воздух нужна библиотека лишенная этих недостатков.
  • Mario, я думаю, что при вызове библиотеки ради одного-двух таких кусочков, накладные расходы больно большими получаются. Ну а ежели таких кусков много используется (в том числе и более сложных), тогда уже да... В свою очередь предлагаю написанный мной алгоритм извлечения квадратного корня добавить в такую библиотеку, ежели кто займëтся оной:
    Spoiler:

    Code: Select all

    sqrt: ;24 code (not comments) strings
    ;in: eax-number; out: ebx-result of fullnumber sqrt,
    ; if eax wasn't changed, ebx is ideal result, else:
    ; ecx-(bigger-ideal), eax-(ideal-smaller);
    ; result is bigger than floatpoint if ecx<eax, else smaller;
    ; to find percentage, b=ecx/(ecx+eax), s=eax/(ecx+eax):
    ; ((b>>0)=>b is nearly to ideal, for s is same; always<1)
    cmp eax,0
    jne @f
        xor ebx,ebx
        ret
    @@:
    mov ebx,-1
    xor ecx,ecx
    @@:
        add ebx,2
        add ecx,ebx
    cmp ecx,eax
    je @f ; we don't need to find nearly result, ecx is this.
    jb @b
    ;now: ecx-bigger square, (ecx-ebx)-smaller, eax-ideal;
    ;need: check, what square mostly near to input number.
        sub ecx,eax
        mov eax,ebx
        sub eax,ecx ; eax=ebx-(ecx-eax)=eax-(ecx-ebx)=ideal-smaller.
        cmp ecx,eax ; cmp(bigger-ideal,ideal-smaller).
        jb @f ; ecx mostly near.
        sub ebx,2 ; it will be incremented soon, so lets annihilate this.
    ;crushed: eax; now: ecx,eax-see header.
    @@: ; ecx is better
        inc ebx
    shr ebx,1
    ret
    
    функция довольно неплохая, на мой взгляд, я потратил на неë довольно много времени
    И мы уже давно не пешки,
    Мы пули, мы орлы, и решки!
    Война ютит бинарный код,
    Умри, или иди вперед!
  • Gluk wrote:Mario, я думаю, что при вызове библиотеки ради одного-двух таких кусочков, накладные расходы больно большими получаются. Ну а ежели таких кусков много используется (в том числе и более сложных), тогда уже да...
    Ну, так собственно потому я и расплывался мыслью по древу по посту - ради одной функции это бессмысленно.
    Gluk wrote:В свою очередь предлагаю написанный мной алгоритм извлечения квадратного корня добавить в такую библиотеку, ежели кто займëтся оной:
    Вот за это спасибо! Еще бы реализовать синус.
  • А табличный метод не подходит?
  • Табличный метод ограничен размерами памяти.
  • Нужно в float или пойдет int в виде sin (x) * 100, к примеру? Какая точность нужна? Каких углов?
  • sin*255 мне видится логичнее, для одного байта
    И мы уже давно не пешки,
    Мы пули, мы орлы, и решки!
    Война ютит бинарный код,
    Умри, или иди вперед!
  • И как мы потом будем скрещивать ужа с ежом? ЯВУ код с асм кодом подружить в одной *.obj библиотеке проблематично.
    Насчет точности не знаю пока.
  • Можно и на ассемблере ведь. Быстро и экономично, мне кажется, так:
    1) Создание таблицы для 90*n значений (точность зависит от n), расчет через примитивное разложение x-(x^3)/6+(x^5)/120...
    Займет, допустим, 360*n байт памяти - не так уж и накладно
    2) Затем линейное интерполирование (прям из книжки пример)
    x1 = x*(количество_значений_в_массиве)/pi
    y1 = (элемент_массива_номер_x1)
    y2 = (элемент массива_номер_x1+1)
    Синус = y1 + (y2-y1)*(x*(количество значений в массиве)/pi-x1)
    Точность будет, скорее всего, достаточная. И зависеть будет от первого пункта - насколько точно разложили в ряд и сколько элементов в таблицу положили. И скорость будет хорошая.
  • а FPU не катит ?
  • Я уже имел счастье наблюдать, что на eBox таки хреново катит FPU.
  • Извините, что встреваю, могу рассказать баян. В FastMM для Delphi видел классную функцию CardinalToStrBuf, обходящуюся без деления вообще:
    Spoiler:

    Code: Select all

    {Converts a cardinal to string at the buffer location, returning the new
     buffer position. Note: Only supports numbers up to 2^31.}
    function CardinalToStrBuf(ACardinal: Cardinal; APBuffer: PAnsiChar): PAnsiChar;
    asm
      {On entry: eax = ACardinal, edx = ABuffer}
      push edi
      mov edi, edx                //Pointer to the first character in edi
      {Calculate leading digit: divide the number by 1e9}
      add eax, 1                  //Increment the number
      mov edx, $89705F41          //1e9 reciprocal
      mul edx                     //Multplying with reciprocal
      shr eax, 30                 //Save fraction bits
      mov ecx, edx                //First digit in bits <31:29>
      and edx, $1FFFFFFF          //Filter fraction part edx<28:0>
      shr ecx, 29                 //Get leading digit into accumulator
      lea edx, [edx + 4 * edx]    //Calculate ...
      add edx, eax                //... 5*fraction
      mov eax, ecx                //Copy leading digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #2}
      mov eax, edx                //Point format such that 1.0 = 2^28
      cmp ecx, 1                  //Any non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 28                 //Next digit
      and edx, $0fffffff          //Fraction part edx<27:0>
      or ecx, eax                 //Accumulate next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #3}
      lea eax, [edx * 4 + edx]    //5*fraction, new digit eax<31:27>
      lea edx, [edx * 4 + edx]    //5*fraction, new fraction edx<26:0>
      cmp ecx, 1                  //Any non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 27                 //Next digit
      and edx, $07ffffff          //Fraction part
      or ecx, eax                 //Accumulate next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #4}
      lea eax, [edx * 4 + edx]    //5*fraction, new digit eax<31:26>
      lea edx, [edx * 4 + edx]    //5*fraction, new fraction edx<25:0>
      cmp ecx, 1                  //Any non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 26                 //Next digit
      and edx, $03ffffff          //Fraction part
      or ecx, eax                 //Accumulate next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #5}
      lea eax, [edx * 4 + edx]    //5*fraction, new digit eax<31:25>
      lea edx, [edx * 4 + edx]    //5*fraction, new fraction edx<24:0>
      cmp ecx, 1                  //Any non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 25                 //Next digit
      and edx, $01ffffff          //Fraction part
      or ecx, eax                 //Accumulate next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #6}
      lea eax, [edx * 4 + edx]    //5*fraction, new digit eax<31:24>
      lea edx, [edx * 4 + edx]    //5*fraction, new fraction edx<23:0>
      cmp ecx, 1                  //Any non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 24                 //Next digit
      and edx, $00ffffff          //Fraction part
      or ecx, eax                 //Accumulate next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #7}
      lea eax, [edx * 4 + edx]    //5*fraction, new digit eax<31:23>
      lea edx, [edx * 4 + edx]    //5*fraction, new fraction edx<31:23>
      cmp ecx, 1                  //Any non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 23                 //Next digit
      and edx, $007fffff          //Fraction part
      or ecx, eax                 //Accumulate next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #8}
      lea eax, [edx * 4 + edx]    //5*fraction, new digit eax<31:22>
      lea edx, [edx * 4 + edx]    //5*fraction, new fraction edx<22:0>
      cmp ecx, 1                  //Any non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 22                 //Next digit
      and edx, $003fffff          //Fraction part
      or ecx, eax                 //Accumulate next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #9}
      lea eax, [edx * 4 + edx]    //5*fraction, new digit eax<31:21>
      lea edx, [edx * 4 + edx]    //5*fraction, new fraction edx<21:0>
      cmp ecx, 1                  //Any non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 21                 //Next digit
      and edx, $001fffff          //Fraction part
      or ecx, eax                 //Accumulate next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store digit out to memory
      {Calculate digit #10}
      lea eax, [edx * 4 + edx]    //5*fraction, new digit eax<31:20>
      cmp ecx, 1                  //Any-non-zero digit yet ?
      sbb edi, -1                 //Yes->increment ptr, No->keep old ptr
      shr eax, 20                 //Next digit
      or eax, '0'                 //Convert digit to ASCII
      mov [edi], al               //Store last digit and end marker out to memory
      {Return a pointer to the next character}
      lea eax, [edi + 1]
      {Restore edi}
      pop edi
    end;
    
    Тип Cardinal в Delphi -- это DWORD.
  • Mario
    Там и целочисленные тормозить будут, если сравнивать с K8+ и P6+.
    Надо смотреть точность алгоритмов, а то эта математика насчитает...
  • Товарищи, среди нас тайный агент ЯВУшников! Только он мог предложить такой алгоритм, чтобы ЯВУшники смогли показать на http://hackersdelight.org/HDcode/isqrt.c.txt и применить один из своих любимых доводов "ассемблерщики слишком заняты мелкими проблемами вместо того, чтобы использовать более сложные, но более быстрые алгоритмы".
  • Who is online

    Users browsing this forum: No registered users and 4 guests