floating_fudge.h

00001 /*
00002  * SpanDSP - a series of DSP components for telephony
00003  *
00004  * floating_fudge.h - A bunch of shims, to use double maths
00005  *                    functions on platforms which lack the
00006  *                    float versions with an 'f' at the end,
00007  *                    and to deal with the vaguaries of lrint().
00008  *
00009  * Written by Steve Underwood <steveu@coppice.org>
00010  *
00011  * Copyright (C) 2008 Steve Underwood
00012  *
00013  * All rights reserved.
00014  *
00015  * This program is free software; you can redistribute it and/or modify
00016  * it under the terms of the GNU Lesser General Public License version 2.1,
00017  * as published by the Free Software Foundation.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU Lesser General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public
00025  * License along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00027  *
00028  * $Id: floating_fudge.h,v 1.5 2008/08/03 03:44:00 steveu Exp $
00029  */
00030 
00031 #if !defined(_FLOATING_FUDGE_H_)
00032 #define _FLOATING_FUDGE_H_
00033 
00034 #if defined(__cplusplus)
00035 extern "C"
00036 {
00037 #endif
00038 
00039 #if !defined(HAVE_SINF)
00040 static __inline__ float sinf(float x)
00041 {
00042         return (float) sin((double) x);
00043 }
00044 #endif
00045 
00046 #if !defined(HAVE_COSF)
00047 static __inline__ float cosf(float x)
00048 {
00049         return (float) cos((double) x);
00050 }
00051 #endif
00052 
00053 #if !defined(HAVE_TANF)
00054 static __inline__ float tanf(float x)
00055 {
00056         return (float) tan((double) x);
00057 }
00058 #endif
00059 
00060 #if !defined(HAVE_ASINF)
00061 static __inline__ float asinf(float x)
00062 {
00063         return (float) asin((double) x);
00064 }
00065 #endif
00066 
00067 #if !defined(HAVE_ACOSF)
00068 static __inline__ float acosf(float x)
00069 {
00070         return (float) acos((double) x);
00071 }
00072 #endif
00073 
00074 #if !defined(HAVE_ATANF)
00075 static __inline__ float atanf(float x)
00076 {
00077         return (float) atan((double) x);
00078 }
00079 
00080 #endif
00081 
00082 #if !defined(HAVE_ATAN2F)
00083 static __inline__ float atan2f(float y, float x)
00084 {
00085         return (float) atan2((double) y, (double) x);
00086 }
00087 
00088 #endif
00089 
00090 #if !defined(HAVE_CEILF)
00091 static __inline__ float ceilf(float x)
00092 {
00093         return (float) ceil((double) x);
00094 }
00095 #endif
00096 
00097 #if !defined(HAVE_FLOORF)
00098 static __inline__ float floorf(float x)
00099 {
00100         return (float) floor((double) x);
00101 }
00102 
00103 #endif
00104 
00105 #if !defined(HAVE_POWF)
00106 static __inline__ float powf(float x, float y)
00107 {
00108     return (float) pow((double) x, (double) y);
00109 }
00110 #endif
00111 
00112 #if !defined(HAVE_EXPF)
00113 static __inline__ float expf(float x)
00114 {
00115     return (float) expf((double) x);
00116 }
00117 #endif
00118 
00119 #if !defined(HAVE_LOGF)
00120 static __inline__ float logf(float x)
00121 {
00122         return (float) logf((double) x);
00123 }
00124 #endif
00125 
00126 #if !defined(HAVE_LOG10F)
00127 static __inline__ float log10f(float x)
00128 {
00129     return (float) log10((double) x);
00130 }
00131 #endif
00132 
00133 /* The following code, to handle issues with lrint() and lrintf() on various
00134  * platforms, is adapted from similar code in libsndfile, which is:
00135  *
00136  * Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
00137  *
00138  * This program is free software; you can redistribute it and/or modify
00139  * it under the terms of the GNU Lesser General Public License as published by
00140  * the Free Software Foundation; either version 2.1 of the License, or
00141  * (at your option) any later version.
00142  *
00143  * This program is distributed in the hope that it will be useful,
00144  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00145  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00146  * GNU Lesser General Public License for more details.
00147  */
00148 
00149 /*
00150  *    On Intel Pentium processors (especially PIII and probably P4), converting
00151  *    from float to int is very slow. To meet the C specs, the code produced by
00152  *    most C compilers targeting Pentium needs to change the FPU rounding mode
00153  *    before the float to int conversion is performed.
00154  *
00155  *    Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
00156  *    is this flushing of the pipeline which is so slow.
00157  *
00158  *    Fortunately the ISO C99 specification defines the functions lrint, lrintf,
00159  *    llrint and llrintf which fix this problem as a side effect.
00160  *
00161  *    On Unix-like systems, the configure process should have detected the
00162  *    presence of these functions. If they weren't found we have to replace them
00163  *    here with a standard C cast.
00164  */
00165 
00166 /*
00167  *    The C99 prototypes for these functions are as follows:
00168  *
00169  *        int rintf(float x);
00170  *        int rint(double x);
00171  *        long int lrintf(float x);
00172  *        long int lrint(double x);
00173  *        long long int llrintf(float x);
00174  *        long long int llrint(double x);
00175  *
00176  *    The presence of the required functions are detected during the configure
00177  *    process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
00178  *    the config file.
00179  */
00180 
00181 #if defined(__CYGWIN__)
00182     /*
00183      *    CYGWIN has lrint and lrintf functions, but they are slow and buggy:
00184      *        http://sourceware.org/ml/cygwin/2005-06/msg00153.html
00185      *        http://sourceware.org/ml/cygwin/2005-09/msg00047.html
00186      *    The latest version of cygwin seems to have made no effort to fix this.
00187      *    These replacement functions (pulled from the Public Domain MinGW
00188      *    math.h header) replace the native versions.
00189      */
00190     static __inline__ long int lrint(double x)
00191     {
00192         long int retval;
00193 
00194         __asm__ __volatile__
00195         (
00196             "fistpl %0"
00197             : "=m" (retval)
00198             : "t" (x)
00199             : "st"
00200         );
00201 
00202         return retval;
00203     }
00204 
00205     static __inline__ long int lrintf(float x)
00206     {
00207         long int retval;
00208 
00209         __asm__ __volatile__
00210         (
00211             "fistpl %0"
00212             : "=m" (retval)
00213             : "t" (x)
00214             : "st"
00215         );
00216         return retval;
00217     }
00218 
00219     static __inline__ long int lfastrint(double x)
00220     {
00221         long int retval;
00222 
00223         __asm__ __volatile__
00224         (
00225             "fistpl %0"
00226             : "=m" (retval)
00227             : "t" (x)
00228             : "st"
00229         );
00230 
00231         return retval;
00232     }
00233 
00234     static __inline__ long int lfastrintf(float x)
00235     {
00236         long int retval;
00237 
00238         __asm__ __volatile__
00239         (
00240             "fistpl %0"
00241             : "=m" (retval)
00242             : "t" (x)
00243             : "st"
00244         );
00245         return retval;
00246     }
00247 #elif defined(HAVE_LRINT)  &&  defined(HAVE_LRINTF)
00248 
00249 #if defined(__i386__)
00250     /* These routines are guaranteed fast on an i386 machine. Using the built in
00251        lrint() and lrintf() should be similar, but they may not always be enabled.
00252        Sometimes, especially with "-O0", you might get slow calls to routines. */
00253     static __inline__ long int lfastrint(double x)
00254     {
00255         long int retval;
00256 
00257         __asm__ __volatile__
00258         (
00259             "fistpl %0"
00260             : "=m" (retval)
00261             : "t" (x)
00262             : "st"
00263         );
00264 
00265         return retval;
00266     }
00267 
00268     static __inline__ long int lfastrintf(float x)
00269     {
00270         long int retval;
00271 
00272         __asm__ __volatile__
00273         (
00274             "fistpl %0"
00275             : "=m" (retval)
00276             : "t" (x)
00277             : "st"
00278         );
00279         return retval;
00280     }
00281 #elif defined(__x86_64__)
00282     /* On an x86_64 machine, the fastest thing seems to be a pure assignment from a
00283        double or float to an int. It looks like the design on the x86_64 took account
00284        of the default behaviour specified for C. */
00285     static __inline__ long int lfastrint(double x)
00286     {
00287         return (long int) (x);
00288     }
00289 
00290     static __inline__ long int lfastrintf(float x)
00291     {
00292         return (long int) (x);
00293     }
00294 #elif defined(__ppc__)  ||   defined(__powerpc__)
00295     static __inline__ long int lfastrint(register double x)
00296     {
00297         int res[2];
00298 
00299         __asm__ __volatile__
00300         (
00301             "fctiw %1, %1\n\t"
00302             "stfd %1, %0"
00303             : "=m" (res)    /* Output */
00304             : "f" (x)       /* Input */
00305             : "memory"
00306         );
00307 
00308         return res[1];
00309     }
00310 
00311     static __inline__ long int lfastrintf(register float x)
00312     {
00313         int res[2];
00314 
00315         __asm__ __volatile__
00316         (
00317             "fctiw %1, %1\n\t"
00318             "stfd %1, %0"
00319             : "=m" (res)    /* Output */
00320             : "f" (x)       /* Input */
00321             : "memory"
00322         );
00323 
00324         return res[1];
00325     }
00326 #endif
00327 
00328 #elif defined(WIN32)  ||  defined(_WIN32)
00329     /*
00330      *    Win32 doesn't seem to have the lrint() and lrintf() functions.
00331      *    Therefore implement inline versions of these functions here.
00332      */
00333     __inline long int lrint(double x)
00334     {
00335         long int i;
00336 
00337         _asm
00338         {
00339             fld x
00340             fistp i
00341         };
00342         return i;
00343     }
00344 
00345     __inline long int lrintf(float x)
00346     {
00347         long int i;
00348 
00349         _asm
00350         {
00351             fld x
00352             fistp i
00353         };
00354         return i;
00355     }
00356 
00357     __inline long int lfastrint(double x)
00358     {
00359         long int i;
00360 
00361         _asm
00362         {
00363             fld x
00364             fistp i
00365         };
00366         return i;
00367     }
00368 
00369     __inline long int lfastrintf(float x)
00370     {
00371         long int i;
00372 
00373         _asm
00374         {
00375             fld x
00376             fistp i
00377         };
00378         return i;
00379     }
00380 #elif defined(WIN64)  ||  defined(_WIN64)
00381     /*
00382      *    Win64 machines will do best with a simple assignment.
00383      */
00384     __inline long int lfastrint(double x)
00385     {
00386         return (long int) (x);
00387     }
00388 
00389     __inline long int lfastrintf(float x)
00390     {
00391         return (long int) (x);
00392     }
00393 #elif defined(__MWERKS__)  &&  defined(macintosh)
00394     /* This MacOS 9 solution was provided by Stephane Letz */
00395 
00396     long int __inline__ lfastrint(register double x)
00397     {
00398         long int res[2];
00399 
00400         asm
00401         {
00402             fctiw x, x
00403             stfd x, res
00404         }
00405         return res[1];
00406     }
00407 
00408     long int __inline__ lfastrintf(register float x)
00409     {
00410         long int res[2];
00411 
00412         asm
00413         {
00414             fctiw x, x
00415             stfd x, res
00416         }
00417         return res[1];
00418     }
00419 
00420 #elif defined(__MACH__)  &&  defined(__APPLE__)  &&  (defined(__ppc__)  ||  defined(__powerpc__))
00421     /* For Apple Mac OS/X - do recent versions still need this? */
00422 
00423     static __inline__ long int lfastrint(register double x)
00424     {
00425         int res[2];
00426 
00427         __asm__ __volatile__
00428         (
00429             "fctiw %1, %1\n\t"
00430             "stfd %1, %0"
00431             : "=m" (res)    /* Output */
00432             : "f" (x)       /* Input */
00433             : "memory"
00434         );
00435 
00436         return res[1];
00437     }
00438 
00439     static __inline__ long int lfastrintf(register float x)
00440     {
00441         int res[2];
00442 
00443         __asm__ __volatile__
00444         (
00445             "fctiw %1, %1\n\t"
00446             "stfd %1, %0"
00447             : "=m" (res)    /* Output */
00448             : "f" (x)       /* Input */
00449             : "memory"
00450         );
00451 
00452         return res[1];
00453     }
00454 #else
00455     /* There is nothing else to do, but use a simple casting operation, instead of a real
00456        rint() type function. Since we are only trying to use rint() to speed up conversions,
00457        the accuracy issues related to changing the rounding scheme are of little concern
00458        to us. */
00459 
00460     #if !defined(__sgi)
00461         #warning "No usable lrint() and lrintf() functions available."
00462         #warning "Replacing these functions with a simple C cast."
00463     #endif
00464 
00465     static __inline__ long int lfastrint(double x)
00466     {
00467         return (long int) (x);
00468     }
00469 
00470     static __inline__ long int lfastrintf(float x)
00471     {
00472         return (long int) (x);
00473     }
00474 
00475 #endif
00476 
00477 #if defined(__cplusplus)
00478 }
00479 #endif
00480 
00481 #endif
00482 
00483 /*- End of file ------------------------------------------------------------*/

Generated on Tue Oct 7 20:25:46 2008 for spandsp by  doxygen 1.5.6