0

I know it is easy in java to count log by Math.log but how that works since in assembly no ready function like that ?

mariano
  • 1
  • 1
  • 2
  • 1
    There is `FYL2X` actually, but that's x87. Could you specify more clearly what sort of thing you want? – harold Oct 06 '18 at 15:57
  • Are you programming in 32 bit mode or in 64 bit mode? Would you like to have an easy solution or a fast one? – fuz Oct 06 '18 at 16:02
  • 64 , easy solution – mariano Oct 06 '18 at 16:05
  • See [Efficient implementation of log2(\_\_m256d) in AVX2](https://stackoverflow.com/q/45770089) for how to do it efficiently. An SSE2 version of that (for x86-64) should be easy. (Look at compiler output to get asm from the C intrinsics). See also [Logarithm in C++ and assembly](https://stackoverflow.com/q/45785705) for a simplistic / slow `fyl2x` version. – Peter Cordes Oct 06 '18 at 18:36
  • Possible duplicate of [Logarithm in C++ and assembly](https://stackoverflow.com/questions/45785705/logarithm-in-c-and-assembly) – fuz Oct 06 '18 at 19:10

1 Answers1

3

To compute logarithms easily, use the x87 FPU's FYL2X instruction. This instruction computes st1 * log2(st0) and then pops the register stack. Since this is a dual logarithm, you need to push a suitable conversion factor first. Luckily, suitable conversion factors are built into the FPU's ROM accessible through special instructions:

num     real8 1.234          ; the datum you want to convert
out     real8 ?              ; the memory location where you want to place the result

...

; dual logarithm (base 2)
        fld1                 ; st: 1
        fld num              ; st: 1 num
        fyl2x                ; st: log2(num)
        fstp out             ; store to out and pop

; decadic logarithm (base 10)
        fldlg2               ; st: log10(2)
        fld num              ; st: log10(2) num
        fyl2x                ; st: log10(num)
        fstp out             ; store to out and pop

; natural logarithm (base e)
        fldln2               ; st: ln(2)
        fld num              ; st: ln(2) num
        fyl2x                ; st: ln(num)
        fstp out             ; store to out and pop

Note that SSE or AVX do not have similar instructions; if you do not want to use the x87 FPU you have to manually compute the logarithm by means of a numerical approximation. This is usually faster than using fyl2x directly though.

It is possible to use this code in a program that otherwise uses SSE to do floating point math; just move your data to the x87 FPU to compute the logarithm. Since there is no way to move from an SSE register to the x87 FPU directly, you have to go through the stack:

        sub rsp, 8           ; allocate stack space

; SSE -> x87
        movsd real8 ptr [rsp], xmm0
        fld real8 ptr [rsp]

; x87 -> SSE with pop
        fstp real8 ptr [rsp] ; store and pop
        movsd xmm0, real8 ptr [rsp]

; x87 -> SSE without pop
        fst real8 ptr [rsp] ; just store
        movsd xmm0, real8 ptr [rsp]
fuz
  • 88,405
  • 25
  • 200
  • 352
  • This is nearly a duplicate of [Logarithm in C++ and assembly](https://stackoverflow.com/q/45785705), but you add the different log bases. – Peter Cordes Oct 06 '18 at 18:37
  • 1
    @PeterCordes Quite honestly, I didn't know about the duplicate. – fuz Oct 06 '18 at 19:02
  • Note that "decadic logarithm" and "natural logarithm" are using wrong constants: it should be FLDLG2 and FLDLN2 respectively. – Serpent7776 Jan 23 '23 at 11:24
  • @Serpent7776 Please go ahead and edit the answer so it holds the correct constants. I am sorry for the mistake. – fuz Jan 23 '23 at 11:38