The MASM Forum

General => The Workshop => Topic started by: clamicun on March 18, 2017, 04:13:29 AM

Title: cubic root
Post by: clamicun on March 18, 2017, 04:13:29 AM
I am "playing around" with FPU instructions.
Trying to build a small calculator.
It exists FSQRT to get the square root of the value in ST(0).
But I am breaking my head to get a cubic root.
There is no FPU instruction.
Any ideas ?
Title: Re: cubic root
Post by: FORTRANS on March 18, 2017, 05:05:36 AM
Hi,

Quote from: clamicun on March 18, 2017, 04:13:29 AM
Any ideas ?

   Look at the exponential function and raise your value to the
one third power.

Cheers,

Steve N.
Title: Re: cubic root
Post by: clamicun on March 18, 2017, 05:45:57 AM
Thank you Steve,

if you say "function" do you refer to
Logarithmic and exponential instructions ?

F2XM1     2 to the X power Minus 1
FSCALE    SCALE ST(0) by ST(1)
FYL2X     Y*Log2X
FYL2XP1   Y*Log2(X+1)
Title: Re: cubic root
Post by: FORTRANS on March 18, 2017, 08:57:30 AM
Hi,

   Yes.  Particularly F2XM1.  FSCALE uses only integer exponents.

HTH,

Steve
Title: Re: cubic root
Post by: clamicun on March 18, 2017, 11:16:31 AM
Thanks ... will try it
Title: Re: cubic root
Post by: jj2007 on March 18, 2017, 12:02:36 PM
Example:

include \masm32\MasmBasic\MasmBasic.inc      ; download (http://masm32.com/board/index.php?topic=94.0)
  Init

  fld FP10(0.33333333333333333333333333333)
  fld FP10(8.0)      ; 2^3
  fyl2x
  f2xm1
  fld1
  fadd
  Print Str$("The result is %Jf\n", ST(0))

  fld FP10(0.33333333333333333333333333333)
  fld FP10(1.8816763723536577724902657494247)      ; 1.2345^3
  fyl2x
  f2xm1
  fld1
  fadd
  Print Str$("The result is %Jf\n", ST(0))

EndOfCode


Output:
The result is 2.000000000000000000
The result is 1.234567890123456789


There is a more detailed example Posted on 2003-08-20 12:59:18 by Raymond (http://www.asmcommunity.net/forums/topic/?id=14769), plus a fairly complex function that does not have the limitations of the log functions - see attachment (opens in WordPad in case you don't have RichMasm).
Title: Re: cubic root
Post by: Mikl__ on March 18, 2017, 08:21:25 PM
Root of the N-th power of the number
      fld Exponent
      fld st ;st=st(1)
      fabs ;st=|exp|
      fld Max
      fcompp ;leave exp in st(0)
      fstsw ax
      sahf
      jb @@RealPower ;exp > MaxInt?
      fld st ;exp=st(0)=st(1)
      frndint ;round(exp)
      fcomp ;compare exp and round(exp)
      fstsw ax
      sahf
      jne @@RealPower
      fistp IntExp
      mov eax, IntExp ;eax=Trunc(Exponent)
      mov ecx, eax
      cdq
      fld1 ;st(0)=1
      xor eax, edx
      sub eax, edx ;eax=|exp|
      jz @@Exit
      fld Base
      jmp @@Entry
@@Loop:fmul st, st ;st(0)=Base^2
@@Entry:shr eax, 1
      jnc @@Loop
      fmul st(1), st ;Result * X
      jnz @@Loop
      fstp st
      cmp ecx, 0
      jge @@Exit
      fld1
      fdivrp ;st(0)=1/Result
      jmp @@Exit
@@RealPower:fld Base
      ftst
      fstsw ax
      sahf
      jz @@Done
      fldln2
      fxch
      fyl2x
      fxch
      fmulp st(1), st
      fldl2e
      fmulp st(1), st
      fld st(0)
      frndint
      fsub st(1), st
      fxch st(1)
      f2xm1
      fld1
      faddp st(1), st
      fscale
@@Done:fstp st(1)
@@Exit:
Title: Re: cubic root
Post by: clamicun on March 19, 2017, 02:26:48 AM
JJ,
fld FP10(8.0)      ; 2^3 ok.
If I change this to e.g.
fld FP10(27.0)      ; 3^3 not ok.
fld FP10(64.0)      ; 4^3 not ok.
??
Title: Re: cubic root
Post by: raymond on March 19, 2017, 02:30:17 AM
If you have the MASM32 FDK,  you can use the FpuXexpY function of the provided Fpu.lib library, with 1/3 as the exponent. Or, if you want to code the FPU yourself, you can always look at the source code of that function and adapt it to your own specific needs.
Title: Re: cubic root
Post by: clamicun on March 19, 2017, 02:38:53 AM
Mikl__

.data ???
Title: Re: cubic root
Post by: Mikl__ on March 19, 2017, 03:19:57 AM
Guten Abend, clamicun!
Wählen Sie die Daten auf eigene Faust. Das Programm berechnet nicht nur die Wurzel des Würfels
Title: Re: cubic root
Post by: clamicun on March 19, 2017, 04:39:35 AM
Mikl__ Danke,
aber was ist der "Input" ? --- also der Wert aus dem die 3Wurzel berechnet werden soll --- Max ?

intExp ??
base  ??
Title: Re: cubic root
Post by: jj2007 on March 19, 2017, 05:22:44 AM
Quote from: clamicun on March 19, 2017, 02:26:48 AM
JJ,
fld FP10(8.0)      ; 2^3 ok.
If I change this to e.g.
fld FP10(27.0)      ; 3^3 not ok.
fld FP10(64.0)      ; 4^3 not ok.
??

Quote from: jj2007 on March 18, 2017, 12:02:36 PMThere is a more detailed example Posted on 2003-08-20 12:59:18 by Raymond (http://www.asmcommunity.net/forums/topic/?id=14769), plus a fairly complex function that does not have the limitations of the log functions

There is no easy way out :bgrin:
Title: Re: cubic root
Post by: clamicun on March 19, 2017, 06:20:38 AM
JJ,
"CubeLogA"  from Raymond works perfekt  with integers ...
wonder how floats are working.
Title: Re: cubic root
Post by: Mikl__ on March 19, 2017, 10:12:16 PM
; GUI #
include win64a.inc
include msvcrt.inc
includelib msvcrt.lib
.data
n dd 3.0,3.0,3.0,3.0;exponent
y dd 125.0,?,?,?;number
x dd ?,?,?,?;result
.code
WinMain proc
sub esp,28h
movups xmm0,y
rcpps xmm1,n ;xmm1=1/exponent
invoke powf;float powf(float x, float y);Calculates x raised to the power of y 
        movups x,xmm0;x=y^{1/n}
fld x
fistp x
mov eax,x
invoke ExitProcess,0
WinMain endp
end
Title: Re: cubic root
Post by: clamicun on March 20, 2017, 01:04:32 AM
Thanks to all.

I think for my small calculator Raymonds function is the best.
It is not the "Windows calculator" but does the job.
;====================
.data
recip3   QWORD 0.33333333333333333333333333333
value1  db 16 dup(?),0

FPU_cubic_root proc

finit
FFREE st(0)
FFREE st(1)

fld recip3
INVOKE crt_atof,offset value1          ;value1 = Input string from a dialogbox
                                                     ;st(0)=value1, st1=recip3
fabs
fyl2x                     ;->log2(Src1)*exponent
fld st(0)                 ;copy the logarithm
frndint                   ;keep only the characteristic
fsub st(1),st             ;keeps only the mantissa
fxch                      ;get the mantissa on top
f2xm1                     ;->2^(mantissa)-1
fld1
fadd                      ;add 1 back
fscale                    ;scale it with the characteristic
fstp st(1)                ;copy result over and "pop" it

ret
FPU_cubic_root endp
;====================
Title: Re: cubic root
Post by: dedndave on March 20, 2017, 01:28:14 AM
i highly recommend using 80-bit reals with the FPU
if you want a smaller result at the end, fine - the FPU will convert for you

to define data...

MyReal   REAL10   1.234567890123456789
Title: Re: cubic root
Post by: Mikl__ on March 20, 2017, 01:34:55 AM
clamicun,
schauen Sie hier http://www.asmcommunity.net/forums/topic/?id=14769
Title: Re: cubic root
Post by: raymond on March 20, 2017, 02:52:03 AM
clamicun

Quotefinit
FFREE st(0)
FFREE st(1)

fld recip3
Just a few comments to prevent you from making future mistakes.

i) The finit instruction reinitializes all the fpu registers (and also sets the precision control to its full 80 bits). The ffree instructions in your posted code are thus useless at that point.

ii) Even if you didn't use the finit instruction in your posted code, the ffree instructions would also have been useless at that point. The reason is that you cannot load a value into an fpu register if it is not free. AND the fld instruction would attempt to load a value into what would be the current st(7) register. (This is the type of pitfall that programmers fall into by trying to use the fpu without sufficient prior knowledge).

You may want to have a look at the following tutorial, at least of the first few chapters.
http://www.ray.masmcode.com/tutorial/index.html (ftp://www.ray.masmcode.com/tutorial/index.html)
Title: Re: cubic root
Post by: clamicun on March 20, 2017, 04:18:36 AM
Thank you Raymond,

"trying to use the fpu without sufficient prior knowledge"
Might depend on someones type...
I always learnt by doing and trying. 
Title: Re: cubic root
Post by: jj2007 on March 20, 2017, 05:31:20 AM
Quote from: clamicun on March 20, 2017, 04:18:36 AMI always learnt by doing and trying.

That won't work with the FPU :biggrin:

Ray's link above points to a FTP site. Here is the correct one. (http://www.ray.masmcode.com/tutorial/index.html) See in particular the "revolver" figure in chapter 1.

If you don't want to launch the debugger, the deb (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1019) macro is a good alternative; it displays ST(0)...ST(5) - 6+7 are zero because the macro itself needs the FPU:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  FpuFill ; fill the FPU with 1001 ... 1008
  deb 4, "FPU filled", ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7)  ; 6+7 not visible!
  fldpi ; try to put PI into ST(0) - will be zero, and that is an error
  deb 4, "FPU: fldpi", ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7)
  ffree st(7)
  fldpi ; put PI into ST(0) - the zero will move to ST1
  deb 4, "FPU: ffree7 + fldpi", ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7)
  Inkey "OK?"
EndOfCode


Output:
FPU filled
ST(0)           1001.000000000000000
ST(1)           1002.000000000000000
ST(2)           1003.000000000000000
ST(3)           1004.000000000000000
ST(4)           1005.000000000000000
ST(5)           1006.000000000000000
ST(6)           0.0
ST(7)           0.0

FPU: fldpi
ST(0)           0.0     <<<<<<<<<<< you would expect 3.14159 here, but ST(7) was not free...!
ST(1)           1001.000000000000000
ST(2)           1002.000000000000000
ST(3)           1003.000000000000000
ST(4)           1004.000000000000000
ST(5)           1005.000000000000000
ST(6)           0.0   <<<<<<< can't be displayed, but it is 1006.0 indeed
ST(7)           0.0   <<<<<<< can't be displayed, but it is 1007.0 indeed

FPU: ffree7 + fldpi
ST(0)           3.141592653589793238
ST(1)           0.0
ST(2)           1001.000000000000000
ST(3)           1002.000000000000000
ST(4)           1003.000000000000000
ST(5)           1004.000000000000000
ST(6)           0.0
ST(7)           0.0
Title: Re: cubic root
Post by: raymond on March 20, 2017, 05:38:10 AM
QuoteI always learnt by doing and trying.

Would that have been the way you learned trigonometry, or calculus, or simply extracting square roots, or ...  :biggrin: :biggrin: :biggrin: :dazzled:

Just kidding.
Title: Re: cubic root
Post by: dedndave on March 20, 2017, 09:36:24 PM
after giving it a little more thought....

a nice way to go might be to write a general-purpose function (i.e., PROC) that will do something like
ST(0) = ST(0)^ST(1)
let's call that one ExpReal

you can then write other "wrapper" functions to call that one
one such function might load the value 1/3 (REAL10) and the user's REAL8, then call ExpReal and return a REAL8 result
the function would then insure FPU register balance before exit

the ExpReal function can be used in many ways, on any size data
Title: Re: cubic root
Post by: Mikl__ on March 20, 2017, 10:44:39 PM
Hi, dedndave!
I do not even need to invent anything, in http://masm32.com/board/index.php?topic=6075.msg64353#msg64353 I use function float powf(float x, float y) from msvcrt.dll. There it is written for the masm64 -- probably therefore and it was not appreciated
Title: Re: cubic root
Post by: dedndave on March 20, 2017, 11:17:59 PM
i wouldn't use the MSVCRT unless i had to - lol
that's your choice

this could be turned into a macro, i suppose - or a PROC
as i recall, i based this on some code by Raymond and/or Marinus

;raising the power of x to the y is performed using logarithms:
;x^y = alog(y*log(x)), where x is any positive real
;the log and alog functions may use any base, so long as they are both the same (the FPU natively uses base 2)
;
;FYL2X (float y*log base 2 of x) performs the y*log(x) portion of the above equation
;(FYL2X is also commonly used for converting logarithms between bases)
;
;code to compute the y*log2(x) portion, if both operands are REAL numbers
;in memory and no error checking is required would be as follows.

                         ;ST(0)=zzz
    fld     exponent_y   ;load the exponent first
                         ;->ST(0)=exponent, ST(1)=zzz
    fld     number_x     ;then load the x value
                         ;->ST(0)=x value, ST(1)=exponent, ST(2)=zzz
    fyl2x                ;ST(0)=y*log2(x), ST(1)=zzz

;the alog (antilog) portion is performed using the following FPU logarithm instructions:
;FRNDINT (float round to integer)
;F2XM1 (float (2 to the x) minus 1)
;FSCALE (float scale ST(0) by ST(1))

    fld     st           ;make a second copy
                         ;ST(0)=y*log2(x), ST(1)=y*log2(x), ST(2)=zzz
    frndint              ;round it to an integer
                         ;ST(0)=int[y*log2(x)], ST(1)=y*log2(x), ST(2)=zzz
    fsub    st(1),st     ;this will leave only a fractional portion in ST(1)
                         ;ST(0)=int[y*log2(x)], ST(1)=y*log2(x)-int[y*log2(x)], ST(2)=zzz
    fxch    st(1)        ;ST(0)=y*log2(x)-int[y*log2(x)], ST(1)=int[y*log2(x)], ST(2)=zzz
    f2xm1                ;get the fractional power of 2 (minus 1)
                         ;ST(0)=2^(ST(0))-1, ST(1)=int[y*log2(x)], ST(2)=zzz
    fld1                 ;ST(0)=1, ST(1)=2^(ST(0))-1, ST(2)=int[y*log2(x)], ST(3)=zzz
    fadd                 ;add the 1 to ST(1) and POP ST(0)
                         ;ST(0)=2^(ST(0)), ST(1)=int[y*log2(x)], ST(2)=zzz
    fscale               ;add the integer in ST(1) to the exponent of ST(0)
                         ;effectively multiplying the content of ST(0) by 2^int
                         ;and yielding the final result of x^y
                         ;ST(0)=x^y, ST(1)=int[y*log2(x)], ST(2)=zzz
    fstp    st(1)        ;the content of ST(1) has become useless
                         ;overwrite the content of ST(1) with the result and POP ST(0)
                         ;ST(0)=x^y, ST(1)=zzz

    fstp    result_z     ;ST(0)->result
                         ;ST(0)=zzz
Title: Re: cubic root
Post by: HSE on March 21, 2017, 01:55:39 AM
I used the Randy Hyde's pow macro for some years (since 2000): TwoToX macro
fstcw SavedCW

fstcw MaskeCW
or byte ptr MaskeCW+1, 1100b
fldcw MaskeCW

fld st(0)
fld st(0)
Frndint

Fxch
Fsub st(0) , st(1)
F2xm1
Fld1
Fadd
Fxch
Fld1
Fscale
Fstp st(1)
fmul
Fstp st(1)   
fldcw SavedCW
endm

pow MACRO M1, M2 ; M1 ^ M2
Fld M1
Fld M2
Fxch
Fld1
Fxch
Fyl2x
Fmul
TwoToX
      ENDM
     
; Eleva a M2 la que está en st(0)
; ej: 2^10
; fld diez
; pow1 dos
pow1 MACRO M2 ; M1 ^ M2
Fld M2
Fxch
Fld1
Fxch
Fyl2x
Fmul
TwoToX
      ENDM

; ej: 2^10
; fld diez
; fld dos
; pows

pows MACRO ; st (1) ^ st(0)

Fxch ; primero cargar el numero y despues el exponente
Fld1
Fxch
Fyl2x
Fmul
TwoToX
      ENDM
     


and because work perfectly, I don't remember how it works. :biggrin:
Title: Re: cubic root
Post by: dedndave on March 22, 2017, 02:56:04 PM
Expreal MACRO

    fyl2x
    fld     st
    frndint
    fsub    st(1),st
    fxch    st(1)
    f2xm1
    fld1
    fadd
    fscale
    fstp    st(1)

        ENDM

;usage....

    fld     exponent_y
    fld     number_x
    Expreal
    fstp    result_w          ;w = x^y