Using fdlibm library in C

0

I am trying to use the fdlibm library in C to compute sin of a large number. I used the code from this link: http://www.netlib.org/fdlibm/ and downloaded the folder "s_sin.c plus dependencies". When I run the c code in that folder "s_sin.c", I get the following error:

Undefined symbols for architecture x86_64:
"___ieee754_rem_pio2", referenced from:
_sin in s_sin-a92222.o
"___kernel_cos", referenced from:
_sin in s_sin-a92222.o
"___kernel_sin", referenced from:
_sin in s_sin-a92222.o
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Any ideas how to fix this error?

Here is the code that I mentioned above:

    /* @(#)s_sin.c 1.3 95/01/18 */
/*
 * ====================================================
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 *

 * Developed at SunSoft, a Sun Microsystems, Inc. business.
 * Permission to use, copy, modify, and distribute this
 * software is freely granted, provided that this notice 
 * is preserved.
 * ====================================================
 */

/* sin(x)
 * Return sine function of x.
 *
 * kernel function:
 *  __kernel_sin        ... sine function on [-pi/4,pi/4]
 *  __kernel_cos        ... cose function on [-pi/4,pi/4]
 *  __ieee754_rem_pio2  ... argument reduction routine
 *
 * Method.
 *      Let S,C and T denote the sin, cos and tan respectively on 
 *  [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 
 *  in [-pi/4 , +pi/4], and let n = k mod 4.
 *  We have
 *
 *          n        sin(x)      cos(x)        tan(x)
 *     ----------------------------------------------------------
 *      0          S       C         T
 *      1          C      -S        -1/T
 *      2         -S      -C         T
 *      3         -C       S        -1/T
 *     ----------------------------------------------------------
 *
 * Special cases:
 *      Let trig be any of sin, cos, or tan.
 *      trig(+-INF)  is NaN, with signals;
 *      trig(NaN)    is that NaN;
 *
 * Accuracy:
 *  TRIG(x) returns trig(x) nearly rounded 
 */

#include "fdlibm.h"

#ifdef __STDC__
    double sin(double x)
#else
    double sin(x)
    double x;
#endif
{
    double y[2],z=0.0;
    int n, ix;

    /* High word of x. */
    ix = __HI(x);

    /* |x| ~< pi/4 */
    ix &= 0x7fffffff;
    if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);

    /* sin(Inf or NaN) is NaN */
    else if (ix>=0x7ff00000) return x-x;

    /* argument reduction needed */
    else {
        n = __ieee754_rem_pio2(x,y);
        switch(n&3) {
        case 0: return  __kernel_sin(y[0],y[1],1);
        case 1: return  __kernel_cos(y[0],y[1]);
        case 2: return -__kernel_sin(y[0],y[1],1);
        default:
            return -__kernel_cos(y[0],y[1]);
        }
    }
}
c
asked on Stack Overflow Jan 26, 2021 by math17 • edited Jan 26, 2021 by Rachid K.

1 Answer

0

The problem is you need to build libm.a from the fdlibm files. If you look at readme file it explains:

CONFIGURE
        To build FDLIBM, edit the supplied Makefile or create
        a local Makefile by running "sh configure"
        using the supplied configure script contributed by Nelson Beebe

(note: after downloading all the files and makefile, you can simply type make and it will build libm.a)

This will create libm.a (which you can link with instead of the normal math library). After you build the library, you need only #include "fdlibm.h" in your source file and compile similar to:

gcc -Wall -Wextra -pedantic -std=c11 -Ofast -L./ -o test_s_sin test_s_sin.c  -lm

This will compile your code (named test_s_sin.c above) to executable.

The reason you cannot simply build s_sin.c with gcc is if you look in s_sin.c, you will find it depends on a number of additional externally defined functions from fdlibm (which in turn depend on other source file in the library). For example in s_sin.c you have:

    /* High word of x. */
        ix = __HI(x);

    /* |x| ~< pi/4 */
        ix &= 0x7fffffff;
        if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);

    /* sin(Inf or NaN) is NaN */
        else if (ix>=0x7ff00000) return x-x;

    /* argument reduction needed */
        else {
            n = __ieee754_rem_pio2(x,y);
            switch(n&3) {
                case 0: return  __kernel_sin(y[0],y[1],1);
                case 1: return  __kernel_cos(y[0],y[1]);
                case 2: return -__kernel_sin(y[0],y[1],1);
                default:
                        return -__kernel_cos(y[0],y[1]);
            }

Where you have the functions or macros __HI(), __kernel_sin(), __ieee754_rem_pio2(), etc.. all required by s_sin.c. These are provided by the other sources in fdlibm, but are all meant to work together as a library rather than single source files you can cherry-pick from.

answered on Stack Overflow Jan 26, 2021 by David C. Rankin

User contributions licensed under CC BY-SA 3.0