The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: jj2007 on May 21, 2011, 09:19:45 PM

Title: GNU Scientific Library in Assembler
Post by: jj2007 on May 21, 2011, 09:19:45 PM
The GNU Scientific Library contains about 1,000 mathematical and statistical routines. Since I needed one of them, I wrote a little macro for using them in assembler. Basically (pun intended), you need
gsl  <the definition of the function copied exactly from the gsl reference manual>
...
gsl_INIT
gsl_whatever(x, y, z)
gsl_EXIT

Note that C leaves double aka Real8 output on the FPU. Use e.g. ...
gsl_sf_bessel_J0(x)
... and get the output with fstp MyReal8.
If the output is an integer, e.g. ...
gsl int gsl_multifit_test_delta (const gsl_vector * dx, const gsl_vector * x, double epsabs, double epsrel)
... then use
.data
epsabs REAL8 1.23
epsrel REAL8 4.56
.code
mov eax, gsl_multifit_test_delta (eax, ecx, epsabs, epsrel)


Here is a demo how to use the macro, taken 1:1 from the gsl example program (http://www.gnu.org/software/gsl/manual/gsl-ref.html#An-Example-Program):

Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; download (http://www.masm32.com/board/index.php?topic=12460)

; libgsl.dll download (http://gnuwin32.sourceforge.net/packages/gsl.htm) : open Binaries zip, and extract
; libgsl.dll and libgslcblas.dll to \masm32\MasmBasic\GnuScLib\DLL

; define the gsl function(s) you need using the syntax of the GNU Scientific Library Reference (http://www.gnu.org/software/gsl/manual/gsl-ref.html)
gsl   double gsl_sf_bessel_J0 (double x)
[/b]
.data
x   REAL8 5.0   ; in C, this would be double x = 5.0;

   
Init[/b]
[/color]   
gsl_INIT
[/b]
   [/color]
gsl_sf_bessel_J0(x)
[/b]
   PrintLine "GNU expected:", Tb$, "-0.1775967713143382920"
   PrintLine "On FPU:    ", Tb$, "-0.1775967713143383198"
   Inkey Str$("MB Str$()  \t%If", ST(0))
   
gsl_EXIT
[/b]   
Exit[/b]
end start

QuoteGNU expected:   -0.1775967713143382920 (from gsl example program (http://www.gnu.org/software/gsl/manual/gsl-ref.html#An-Example-Program))
On FPU:         -0.1775967713143383198
MB Str$()       -0.177596771314338320
[/tt]

Note the difference in the last digits. The GNU site claims 2920 is right, but their own routine throws 3198 on the FPU.

P.S.: Gsl is powerful stuff, but don't forget to read the GNU license - see e.g. this thread (http://www.masm32.com/board/index.php?topic=15439.0).
Title: Re: GNU Scientific Library in Assembler
Post by: hutch-- on May 22, 2011, 02:41:11 AM
JJ,

Why not write yourself a REAL10 replacement ? Be FREE of any GPL pollution.  :bg
Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 22, 2011, 06:21:54 AM
Quote from: hutch-- on May 22, 2011, 02:41:11 AM
JJ,

Why not write yourself a REAL10 replacement ? Be FREE of any GPL pollution.  :bg

Brilliant idea, Hutch. I can do the coding if you volunteer for the mathematical stuff - you surely know what "Complex Hermitian Matrices" are, right?
That'l keep us busy for the next 20 years :green2

# Mathematical Functions
# Complex Numbers
# Polynomials
# Special Functions
# Vectors and Matrices
# Permutations
# Combinations
# Multisets
# Sorting
# BLAS Support
# Linear Algebra
# Eigensystems (http://www.gnu.org/software/gsl/manual/gsl-ref.html#Eigensystems)
    * Real Symmetric Matrices
    * Complex Hermitian Matrices (http://www.gnu.org/software/gsl/manual/gsl-ref.html#Complex-Hermitian-Matrices)
15.2 Complex Hermitian Matrices

For hermitian matrices, the library uses the complex form of the symmetric bidiagonalization and QR reduction method.

— Function: gsl_eigen_herm_workspace * gsl_eigen_herm_alloc (const size_t n)

    This function allocates a workspace for computing eigenvalues of n-by-n complex hermitian matrices. The size of the workspace is O(3n).

— Function: void gsl_eigen_herm_free (gsl_eigen_herm_workspace * w)

    This function frees the memory associated with the workspace w.

— Function: int gsl_eigen_herm (gsl_matrix_complex * A, gsl_vector * eval, gsl_eigen_herm_workspace * w)

    This function computes the eigenvalues of the complex hermitian matrix A. Additional workspace of the appropriate size must be provided in w. The diagonal and lower triangular part of A are destroyed during the computation, but the strict upper triangular part is not referenced. The imaginary parts of the diagonal are assumed to be zero and are not referenced. The eigenvalues are stored in the vector eval and are unordered.

— Function: gsl_eigen_hermv_workspace * gsl_eigen_hermv_alloc (const size_t n)

    This function allocates a workspace for computing eigenvalues and eigenvectors of n-by-n complex hermitian matrices. The size of the workspace is O(5n).
....
    * Real Nonsymmetric Matrices
    * Real Generalized Symmetric-Definite Eigensystems
    * Complex Generalized Hermitian-Definite Eigensystems
    * Real Generalized Nonsymmetric Eigensystems
    * Sorting Eigenvalues and Eigenvectors
    * Eigenvalue and Eigenvector Examples
    * Eigenvalue and Eigenvector References
# Fast Fourier Transforms
# Numerical Integration
# Random Number Generation
# Quasi-Random Sequences
# Random Number Distributions
# Statistics
# Histograms
# N-tuples
# Monte Carlo Integration
# Simulated Annealing
# Ordinary Differential Equations
# Interpolation
# Numerical Differentiation
# Chebyshev Approximations
# Series Acceleration
# Wavelet Transforms
# Discrete Hankel Transforms
# One dimensional Root-Finding
# One dimensional Minimization
# Multidimensional Root-Finding
# Multidimensional Minimization
# Least-Squares Fitting
# Nonlinear Least-Squares Fitting
# Basis Splines
# Physical Constants
# IEEE floating-point arithmetic
Title: Re: GNU Scientific Library in Assembler
Post by: MichaelW on May 22, 2011, 07:53:07 AM
AFAIK all of the GNU Scientific Library functions take and return doubles, and 19 digits for a double is wishful thinking. But ignoring that reality, if I use the Cygwin j0 function, store the result as a REAL10, and display it with the Cygwin printf function, which is not the MSVCRT function and actually supports long doubles, then I get:

-0.1775967713143382920
Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 22, 2011, 08:52:28 AM
Quote from: MichaelW on May 22, 2011, 07:53:07 AM
AFAIK all of the GNU Scientific Library functions take and return doubles, and 19 digits for a double is wishful thinking. But ignoring that reality, if I use the Cygwin j0 function, store the result as a REAL10, and display it with the Cygwin printf function, which is not the MSVCRT function and actually supports long doubles, then I get:

-0.1775967713143382920


Michael,

The gsl leaves a result on the FPU, so it is by definition REAL10 (consider that the input is REAL8 but exactly 5.0, in REAL10 terms, and that the bessel routine uses REAL10 internally).

MasmBasic Str$() displays the full REAL10 precision correctly - which simply means that the result returned by the gsl bessel routine is different from what they say it should return.

But I agree fully that (quote gsl site (http://www.gnu.org/software/gsl/manual/gsl-ref.html#An-Example-Program))...
QuoteThe output is shown below, and should be correct to double-precision accuracy,2

     J0(5) = -1.775967713143382920e-01
... is incorrect. Even when I use printf:
invoke crt_printf, Chr$("J0(%g) = ", 9, " %.18e", 13, 10), x, MyRes
... the returned result is ...3200:
GNU expected:   -0.1775967713143382920
J0(5) =          -1.775967713143383200e-001
On FPU:         -0.1775967713143383198
MB Str$()       -0.177596771314338320
MB Str$()       -0.177596771314338320

Which implies that the gsl people used something else to generate the 2920 ending quoted on their site - maybe the cygwin routine you used.

In short: It is not a display problem - cygwin and libgsl.dll return different results.
Title: Re: GNU Scientific Library in Assembler
Post by: MichaelW on May 22, 2011, 09:56:08 AM
Jochen,

Returning a floating-point result in ST(0) is part of the calling convention and it does not imply that the result has the full REAL10 precision.

http://www.gnu.org/software/gsl/manual/gsl-ref.html#Long-double

"In general, the algorithms in the library are written for double precision only. The long double type is not supported for actual computation."

Considering that the library is written in ANSI C, and intended to be portable, I doubt that the computations were done without storing intermediate results and I doubt that the intermediate results were stored as long doubles.

Title: Re: GNU Scientific Library in Assembler
Post by: hutch-- on May 22, 2011, 10:21:11 AM
 :bg

JJ,

> Brilliant idea, Hutch. I can do the coding if you volunteer for the mathematical stuff - you surely know what "Complex Hermitian Matrices" are, right?

I may not be much use to you here, apart from cheating and using a computer my arithmetic skills are of the class of,

Eenie, meanie, miney and Larry and Curly's mate MOE.  :P
Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 22, 2011, 10:34:05 AM
Quote from: MichaelW on May 22, 2011, 09:56:08 AM
I doubt that the computations were done without storing intermediate results and I doubt that the intermediate results were stored as long doubles.

Michael,

At least for the Bessel routine, Olly says it's all FPU and no intermediate results stored to REAL8 vars. Now the interesting question remains which of the two results is more "exact"... :wink

Note also that the MasmBasic gsl macro is an interface to the gsl dll; using the gsl source with C might e.g. use SSE2 instead of the FPU. On the other hand, the dll comes from the fairly "official" GSL for Windows site (http://gnuwin32.sourceforge.net/packages/gsl.htm), so I guess this is the best binary they could produce...

Just for fun, here another example:

Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; download (http://www.masm32.com/board/index.php?topic=12460)

; libgsl.dll download (http://gnuwin32.sourceforge.net/packages/gsl.htm) : open Binaries zip, and extract
; libgsl.dll and libgslcblas.dll to \masm32\MasmBasic\GnuScLib\DLL

; define the gsl function(s) you want to use with the syntax of the GNU Scientific Library Reference (http://www.gnu.org/software/gsl/manual/gsl-ref.html)
gsl   double gsl_stats_mean (const double data[], size_t stride, size_t n)
gsl   double gsl_stats_variance (const double data[], size_t stride, size_t n)
gsl   double gsl_stats_sd (const double data[], size_t stride, size_t n)

.data
MyData   REAL8 5.0, 6.0, 3.2, 1.8, 9.0      ; define a double precision array

   Init
   gsl_INIT
   gsl_stats_
mean (offset MyData, 1, 5)      ; stride 1, 5 elements
   PrintLine Str$("Mean    \t%7f", ST(0))      ; print ST directly from the FPU with 7 digits precision
   gsl_stats_
variance (offset MyData, 1, 5)
   PrintLine Str$("Variance\t%7f", ST(0))
   gsl_stats_
sd (offset MyData, 1, 5)
   PrintLine Str$("Standard Dev\t%7f", ST(0))
   gsl_EXIT
   Inkey "ok"
   Exit
end start

Mean            5.000000
Variance        7.620000
Standard Dev    2.760435
Title: Re: GNU Scientific Library in Assembler
Post by: MichaelW on May 22, 2011, 10:41:10 AM
As to which one is more exact I don't know, but they both appear to produce REAL8 results (but not the same results).

;====================================================================
    .486                                ; create 32 bit code
    .model flat, stdcall                ; 32 bit memory model
    option casemap :none                ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\Comctl32.inc
    include \masm32\include\comdlg32.inc
    include \masm32\include\shell32.inc
    include \masm32\include\oleaut32.inc
    include \masm32\include\msvcrt.inc

    include \masm32\macros\macros.asm

    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\Comctl32.lib
    includelib \masm32\lib\comdlg32.lib
    includelib \masm32\lib\shell32.lib
    includelib \masm32\lib\oleaut32.lib

    includelib cygwin1.lib
    includelib libgsl.lib

    includelib \masm32\lib\msvcrt.lib
;====================================================================

cygwin_dll_init PROTO C
dll_dllcrt0 PROTO C
printf PROTO C :VARARG

j0               PROTO C :REAL8
gsl_sf_bessel_J0 PROTO C :REAL8

;====================================================================
    .data
        r85 REAL8 5.0
        r8  REAL8 ?
        r10 REAL10 ?
    .code
;====================================================================
start:
;====================================================================
    invoke cygwin_dll_init
    invoke dll_dllcrt0

    invoke j0, r85
    fstp r10
    invoke printf, cfm$("cygwin j0 to r10       : %.19Lf\n\n"), r10

    invoke j0, r85
    fstp r8
    invoke printf, cfm$("cygwin j0 to r8        : %.19f\n\n"), r8

    invoke gsl_sf_bessel_J0, r85
    fstp r10
    invoke printf, cfm$("gsl_sf_bessel_J0 to r10: %.19Lf\n\n"), r10

    invoke gsl_sf_bessel_J0, r85
    fstp r8
    invoke printf, cfm$("gsl_sf_bessel_J0 to r8 : %.19f\n\n"), r8

    inkey "Press any key to exit..."
    exit
;====================================================================
end start


cygwin j0 to r10       : -0.1775967713143382920

cygwin j0 to r8        : -0.1775967713143382920

gsl_sf_bessel_J0 to r10: -0.1775967713143382642

gsl_sf_bessel_J0 to r8 : -0.1775967713143382642


FWIW, the module definition file that I created for libgsl.dll, that I then used to create an import library, included 3695 function names.
Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 22, 2011, 10:46:17 AM
Michael,

How did you get libgsl.lib? Can you post the executable, so that we can have a look at differences in Olly?
Title: Re: GNU Scientific Library in Assembler
Post by: MichaelW on May 22, 2011, 11:08:34 AM
All of the necessary components except the DLLs are in the attachment. It turned out that for this I didn't need the libgslcblas components, although as you know I did need the DLL.

And I checked the header files to verify that both functions take a REAL8 argument.
Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 22, 2011, 12:28:50 PM
Thanks a lot, Michael. I had to do a complete CygWin install to get it to work, but it is pretty obvious: There are two different versions around that return slightly different figures... using the same dll and the same inputs!
::)

Here is what Olly sees:
a) my version, result on FPU: -0.1775967713143383198
gsl_sf_bessel_J0_e   55                        push ebp
100B5611             89E5                      mov ebp, esp
100B5613             56                        push esi
100B5614             53                        push ebx
100B5615             83C4 80                   add esp, -80
100B5618             8B75 10                   mov esi, [ebp+10]
100B561B             DD45 08                   fld qword ptr [ebp+8]
100B561E             D905 207C1310             fld dword ptr [10137C20]         ; float 2.980232e-08 (const 1/2**25)
100B5624             D9C9                      fxch st(1)
100B5626             D9E1                      fabs
100B5628             D9C9                      fxch st(1)
100B562A             DDE9                      fucomp st(1)
100B562C             DFE0                      fstsw ax
100B562E             9E                        sahf
100B562F            76 12                     jbe short 100B5643
100B5631             D8C8                      fmul st, st
100B5633             D9E8                      fld1
100B5635             DD1E                      fstp qword ptr [esi]
100B5637             DD5E 08                   fstp qword ptr [esi+8]
100B563A             83EC 80                   sub esp, -80
100B563D             31C0                      xor eax, eax
100B563F             5B                        pop ebx
100B5640             5E                        pop esi
100B5641             5D                        pop ebp
100B5642             C3                        retn

b) the CygWin version, result on FPU: -0.1775967713143382642
j0                   55                        push ebp
610FE651             89E5                      mov ebp, esp
610FE653             83EC 48                   sub esp, 48
610FE656             DD45 08                   fld qword ptr [ebp+8]
610FE659             DD55 C0                   fst qword ptr [ebp-40]
610FE65C             DD1C24                    fstp qword ptr [esp]
610FE65F             E8 DC810000               call 61106840 <<<<<<<<<<<<<<<<<<<<<<<
610FE664             833D E0201661 FF          cmp dword ptr [611620E0], -1
610FE66B             DD5D C8                   fstp qword ptr [ebp-38]
610FE66E            74 0F                     je short 610FE67F
610FE670             DD45 C0                   fld qword ptr [ebp-40]
610FE673             DD1C24                    fstp qword ptr [esp]
610FE676             E8 45F3FFFF               call __fpclassifyd
610FE67B             85C0                      test eax, eax
610FE67D            75 05                     jne short 610FE684
610FE67F             DD45 C8                   fld qword ptr [ebp-38]
610FE682             C9                        leave
610FE683             C3                        retn


61106840             55                        push ebp
61106841             89E5                      mov ebp, esp
61106843             53                        push ebx
61106844             83EC 64                   sub esp, 64
61106847             DD45 08                   fld qword ptr [ebp+8]
6110684A             DD55 C8                   fst qword ptr [ebp-38]
6110684D             8B5D CC                   mov ebx, [ebp-34]
61106850             81E3 FFFFFF7F             and ebx, 7FFFFFFF
61106856             81FB FFFFEF7F             cmp ebx, 7FEFFFFF
6110685C            7E 12                     jle short 61106870
6110685E             D9C0                      fld st
61106860             DEC9                      fmulp st(1), st
61106862             D83D 70E51C61             fdivr dword ptr [611CE570]       ; float 1.000000
61106868             83C4 64                   add esp, 64
6110686B             5B                        pop ebx
6110686C             5D                        pop ebp
6110686D             C3                        retn
Title: Re: GNU Scientific Library in Assembler
Post by: vanjast on May 23, 2011, 09:37:26 AM
Don't forget to init the FPU to Real10 and rounding to the nearest...
Maybe there's an FPU intialisation problem with that......eughh!! library.. whatyou callit!!
:bg
Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 23, 2011, 11:53:09 AM
Quote from: vanjast on May 23, 2011, 09:37:26 AM
Don't forget to init the FPU to Real10 and rounding to the nearest...
Maybe there's an FPU intialisation problem with that......eughh!! library.. whatyou callit!!
:bg

Correct, thanks.
Quote   finit
   gsl_sf_bessel_J0(x)

GNU expected:   -0.1775967713143382920
MB Str$()       -0.1775967713143382920

Mystery solved. Needless to say that the string fpu does not appear in the 422 pages of the gsl reference manual (http://www.gnu.org/software/gsl/manual/gsl-ref.html) :'(
Title: Re: GNU Scientific Library in Assembler
Post by: dedndave on May 23, 2011, 12:03:44 PM
that suggests that there is a library init routine someplace
perhaps there are other items that require initialization, as well
Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 23, 2011, 01:48:20 PM
Quote from: dedndave on May 23, 2011, 12:03:44 PM
that suggests that there is a library init routine someplace
perhaps there are other items that require initialization, as well

Couldn't find any, Dave. But anyway, the next edition of MB will take care of that.
Title: Re: GNU Scientific Library in Assembler
Post by: donkey on May 23, 2011, 02:17:49 PM
Quote from: jj2007 on May 23, 2011, 01:48:20 PM
Quote from: dedndave on May 23, 2011, 12:03:44 PM
that suggests that there is a library init routine someplace
perhaps there are other items that require initialization, as well

Couldn't find any, Dave. But anyway, the next edition of MB will take care of that.

Maybe gsl_ieee_env_setup

http://www.gnu.org/software/gsl/manual/html_node/Setting-up-your-IEEE-environment.html
Title: Re: GNU Scientific Library in Assembler
Post by: MichaelW on May 23, 2011, 05:30:24 PM
Looking in the GSL module definition file for exported functions that contain "init", I don't see any that look like some sort of global initialization, but I do see what look like initialization for specific groups of functions, for example gsl_interp_init and gsl_monte_vegas_init. And in my quick look at the source, virtually all of the floating-point variables/parameters/returns are doubles and the configuration is done via defines. The Cygwin library also apparently does not, at least by default, control the FPU precision, and I'm guessing that for both libraries it's a portability thing.

;====================================================================
    .486                                ; create 32 bit code
    .model flat, stdcall                ; 32 bit memory model
    option casemap :none                ; case sensitive

    include \masm32\include\windows.inc
    include \masm32\include\masm32.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\Comctl32.inc
    include \masm32\include\comdlg32.inc
    include \masm32\include\shell32.inc
    include \masm32\include\oleaut32.inc
    include \masm32\include\msvcrt.inc

    include \masm32\macros\macros.asm

    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\gdi32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\Comctl32.lib
    includelib \masm32\lib\comdlg32.lib
    includelib \masm32\lib\shell32.lib
    includelib \masm32\lib\oleaut32.lib

    includelib cygwin1.lib
    includelib libgsl.lib

    includelib \masm32\lib\msvcrt.lib
;====================================================================

cygwin_dll_init PROTO C
dll_dllcrt0 PROTO C
printf PROTO C :VARARG

j0               PROTO C :REAL8
gsl_sf_bessel_J0 PROTO C :REAL8

;====================================================================
    .data
        r85 REAL8 5.0
        r8  REAL8 ?
        r10 REAL10 ?
    .code
;====================================================================

FPC_24BITS equ 0000000000b
FPC_53BITS equ 1000000000b
FPC_64BITS equ 1100000000b

ShowPC proc
    invoke printf, cfm$("PC = ")
    push eax
    fstcw [esp]
    pop eax
    and eax, FPC_64BITS
    .IF eax == FPC_24BITS
        invoke printf, cfm$("24 bits\n\n")
    .ELSEIF eax == FPC_53BITS
        invoke printf, cfm$("53 bits\n\n")
    .ELSE
        invoke printf, cfm$("64 bits\n\n")
    .ENDIF
    ret
ShowPC endp

;====================================================================
start:
;====================================================================
    invoke cygwin_dll_init
    invoke dll_dllcrt0

    invoke ShowPC

    invoke j0, r85
    fstp r10
    invoke printf, cfm$("cygwin j0 to r10       : %.19Lf\n\n"), r10

    invoke j0, r85
    fstp r8
    invoke printf, cfm$("cygwin j0 to r8        : %.19f\n\n"), r8

    invoke gsl_sf_bessel_J0, r85
    fstp r10
    invoke printf, cfm$("gsl_sf_bessel_J0 to r10: %.19Lf\n\n"), r10

    invoke gsl_sf_bessel_J0, r85
    fstp r8
    invoke printf, cfm$("gsl_sf_bessel_J0 to r8 : %.19f\n\n"), r8

    finit

    invoke ShowPC

    invoke j0, r85
    fstp r10
    invoke printf, cfm$("cygwin j0 to r10       : %.19Lf\n\n"), r10

    invoke j0, r85
    fstp r8
    invoke printf, cfm$("cygwin j0 to r8        : %.19f\n\n"), r8

    invoke gsl_sf_bessel_J0, r85
    fstp r10
    invoke printf, cfm$("gsl_sf_bessel_J0 to r10: %.19Lf\n\n"), r10

    invoke gsl_sf_bessel_J0, r85
    fstp r8
    invoke printf, cfm$("gsl_sf_bessel_J0 to r8 : %.19f\n\n"), r8

    inkey "Press any key to exit..."
    exit
;====================================================================
end start


PC = 53 bits

cygwin j0 to r10       : -0.1775967713143382920

cygwin j0 to r8        : -0.1775967713143382920

gsl_sf_bessel_J0 to r10: -0.1775967713143382642

gsl_sf_bessel_J0 to r8 : -0.1775967713143382642

PC = 64 bits

cygwin j0 to r10       : -0.1775967713143382642

cygwin j0 to r8        : -0.1775967713143382642

gsl_sf_bessel_J0 to r10: -0.1775967713143382920

gsl_sf_bessel_J0 to r8 : -0.1775967713143382920


I have no idea how to explain the opposite effect that the FPU PC has on the two libraries.

Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 23, 2011, 06:26:52 PM
Michael,

Edgar found the FPU init function: gsl_ieee_env_setup (http://www.gnu.org/software/gsl/manual/html_node/Setting-up-your-IEEE-environment.html):
"When [no]* options are specified using this method, the resulting mode is based on a default setting of the highest available precision (double precision or extended precision, depending on the platform) in round-to-nearest mode, with all exceptions enabled apart from the inexact exception. The inexact  exception is generated whenever rounding occurs"

When my proggie called the Bessel routine, the FPU happened to be set to 64 bits (i.e. full precision) but rounding down instead of nearest. Which triggered the wrong results.

I have fixed that in the meantime, the MasmBasic package of today 23 May (http://www.masm32.com/board/index.php?topic=12460) calls finit after the initialisation routine. The gsl macro has also become more powerful and accurate, but exotic cases may still choke - I haven't seen one, but with over 1,000 functions there surely will be some problematic cases.

*: Original says "When options are specified" but they obviously mean NO options.
Title: Re: GNU Scientific Library in Assembler
Post by: MichaelW on May 23, 2011, 07:28:47 PM
New results, this time controlling the RC (which apparently defaults to Nearest):

PC = 53 bits

RC = Nearest

cygwin j0 to r10       : -0.1775967713143382920

cygwin j0 to r8        : -0.1775967713143382920

gsl_sf_bessel_J0 to r10: -0.1775967713143382642

gsl_sf_bessel_J0 to r8 : -0.1775967713143382642

PC = 64 bits

cygwin j0 to r10       : -0.1775967713143382642

cygwin j0 to r8        : -0.1775967713143382642

gsl_sf_bessel_J0 to r10: -0.1775967713143382920

gsl_sf_bessel_J0 to r8 : -0.1775967713143382920

RC = Down

cygwin j0 to r10       : -0.1775967713143383198

cygwin j0 to r8        : -0.1775967713143383198

gsl_sf_bessel_J0 to r10: -0.1775967713143383198

gsl_sf_bessel_J0 to r8 : -0.1775967713143383198
Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on May 23, 2011, 08:06:55 PM
Really strange, that "exchange of results" for rising precision. By the way, the correct value seems to be

-0.177596771314338304347397013075 - according to Wolfram Mathematica (http://functions.wolfram.com/webMathematica/FunctionEvaluation.jsp?name=BesselJ)

There is another issue to observe: Those gsl functions that return a double leave it on the FPU, in ST(0). So you need to cleanup yourself, either by a fstp MyReal8MemVar*), or with fstp st. Otherwise strange things happen - the Bessel algo uses all 8 FPU regs!

Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; Download (http://www.masm32.com/board/index.php?topic=12460)
WantGoodResult = 1   ; test it with ... = 0
.data
MyReal8 REAL8 5.0

   Init
   gsl   double gsl_sf_bessel_J0 (double)
   gsl_INIT
   gsl_sf_bessel_J0(MyReal8)      ; method A: use the macro
   Print Str$("BesselJ(0)=%Jf\n", ST(0))      ; display what is still on the FPU
   if WantGoodResult
      fstp st      ; the Bessel routine uses all eight FPU regs, so you better clear the result
   endif
   invoke hgsl_sf_bessel_J0, MyReal8      ; method B: invoke hXXX
   Print Str$("BesselJ(0)=%Jf\n", ST(0))
   gsl_EXIT
   Exit
end start

Output:
BesselJ(0)=-0.1775967713143382920
BesselJ(0)=-0.1775967713143382920


*) Another option is this macro (works for Real8 and Real4 destinations):
include \masm32\MasmBasic\MasmBasic.inc

PopReal MACRO dest, arg
  arg
  fstp dest
ENDM

.data
MyData REAL8 5.0, 6.0, 3.2, 1.8, 9.0 ; define a double precision array
MyReal8 REAL8 ?

Init
gsl double gsl_stats_mean (const double data[], size_t stride, size_t n)
gsl_INIT
PopReal MyReal8, gsl_stats_mean(offset MyData, 1, 5)
PrintLine Str$("Mean = %7f", MyReal8)
gsl_EXIT
Exit
end start

Title: Re: GNU Scientific Library in Assembler
Post by: jj2007 on February 11, 2012, 09:55:53 PM
Just in case you are using the gsl_INIT macro inside a procedure:
There was a bug in line 6234 of \Masm32\MasmBasic\MasmBasic.inc - a plain ret instead of the correct retn. Strange things could happen if you used it inside a proc, such as (through the eyes of Olly (http://www.ollydbg.de/version2.html)):

  pop ebx
  pop edi
  pop esi
  mov esp, ebp
  pop ebp
  retn 8

The plain ret is not as plain as it looks - it is a actually a macro taking care of adjusting the stack and the regs that were declared in xx proc use esi edi ebx :bg

Version 10 Feb 2012 is ok (http://www.masm32.com/board/index.php?topic=12460).