complex.c

Go to the documentation of this file.
00001 /*                       C O M P L E X . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1985-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup complex */
00023 /*@{*/
00024 /** @file complex.c
00025  *  @par Functions:
00026  *  @li bn_cx_div               Complex Division
00027  *  @li  bn_cx_sqrt     Complex Square Root
00028  *
00029  *  
00030  * @author      Douglas A Gwyn          (Original Version)
00031  * @author      Michael John Muuss      (Macro Version)
00032  *
00033  * @par Source -
00034  *      SECAD/VLD Computing Consortium, Bldg 394
00035  *@n    The U. S. Army Ballistic Research Laboratory
00036  *@n    Aberdeen Proving Ground, Maryland  21005
00037  */
00038 /*@}*/
00039 
00040 #ifndef lint
00041 static const char RCScomplex[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/complex.c,v 14.10 2006/09/02 14:02:14 lbutler Exp $ (BRL)";
00042 #endif
00043 
00044 #include "common.h"
00045 
00046 
00047 
00048 #include <stdio.h>
00049 #include <math.h>
00050 #include "machine.h"
00051 #include "bu.h"
00052 #include "vmath.h"
00053 #include "bn.h"
00054 
00055 /* arbitrary numerical arguments, integer value: */
00056 #define SIGN( x )       ((x) == 0 ? 0 : (x) > 0 ? 1 : -1)
00057 #define ABS( a )        ((a) >= 0 ? (a) : -(a))
00058 
00059 /**
00060  *                      B N _ C X _ D I V
00061  *@brief
00062  *      Divide one complex by another
00063  *
00064  *      bn_cx_div( &a, &b )     divides  a  by  b .  Zero divisor fails.
00065  *      a and b may coincide.  Result stored in a.
00066  */
00067 void
00068 bn_cx_div(register bn_complex_t *ap, register const bn_complex_t *bp)
00069 {
00070         FAST fastf_t    r, s;
00071         FAST fastf_t    ap__re;
00072 
00073         /* Note: classical formula may cause unnecessary overflow */
00074         ap__re = ap->re;
00075         r = bp->re;
00076         s = bp->im;
00077         if ( ABS( r ) >= ABS( s ) )  {
00078                 if( NEAR_ZERO( r, SQRT_SMALL_FASTF ) )
00079                         goto err;
00080                 r = s / r;                      /* <= 1 */
00081                 s = 1.0 / (bp->re + r * s);
00082                 ap->re = (ap->re + ap->im * r) * s;
00083                 ap->im = (ap->im - ap__re * r) * s;
00084                 return;
00085         }  else  {
00086                 /* ABS( s ) > ABS( r ) */
00087                 if( NEAR_ZERO( s, SQRT_SMALL_FASTF ) )
00088                         goto err;
00089                 r = r / s;                      /* < 1 */
00090                 s = 1.0 / (s + r * bp->re);
00091                 ap->re = (ap->re * r + ap->im) * s;
00092                 ap->im = (ap->im * r - ap__re) * s;
00093                 return;
00094         }
00095 err:
00096         bu_log("bn_cx_div: division by zero: %gR+%gI / %gR+%gI\n",
00097                 ap->re, ap->im, bp->re, bp->im );
00098         ap->re = ap->im = 1.0e20;               /* "INFINITY" */
00099 }
00100 
00101 /**
00102  *                      B N _ C X _ S Q R T
00103  *@brief
00104  *  Compute square root of complex number
00105  *
00106  *      bn_cx_sqrt( &out, &c )  replaces  out  by  sqrt(c)
00107  *
00108  *      Note:   This is a double-valued function; the result of
00109  *              bn_cx_sqrt() always has nonnegative imaginary part.
00110  */
00111 void
00112 bn_cx_sqrt(bn_complex_t *op, register const bn_complex_t *ip)
00113 {
00114         FAST fastf_t    ampl, temp;
00115         /* record signs of original real & imaginary parts */
00116         register int    re_sign;
00117         register int    im_sign;
00118 
00119         /* special cases are not necessary; they are here for speed */
00120         im_sign = SIGN( ip->im );
00121         if( (re_sign = SIGN(ip->re))  == 0 )  {
00122                 if ( im_sign == 0 )
00123                         op->re = op->im = 0;
00124                 else if ( im_sign > 0 )
00125                         op->re = op->im = sqrt( ip->im * 0.5 );
00126                 else                    /* im_sign < 0 */
00127                         op->re = -(op->im = sqrt( ip->im * -0.5 ));
00128         } else if ( im_sign == 0 )  {
00129                 if ( re_sign > 0 )  {
00130                         op->re = sqrt( ip->re );
00131                         op->im = 0.0;
00132                 }  else  {              /* re_sign < 0 */
00133                         op->im = sqrt( -ip->re );
00134                         op->re = 0.0;
00135                 }
00136         }  else  {
00137                 /* no shortcuts */
00138                 ampl = bn_cx_ampl( ip );
00139                 if( (temp = (ampl - ip->re) * 0.5) < 0.0 )  {
00140                         /* This case happens rather often, when the
00141                          *  hypot() in bn_cx_ampl() returns an ampl ever so
00142                          *  slightly smaller than ip->re.  This can easily
00143                          *  happen when ip->re ~= 10**20.
00144                          *  Just ignore the imaginary part.
00145                          */
00146                         op->im = 0;
00147                 } else
00148                         op->im = sqrt( temp );
00149 
00150                 if( (temp = (ampl + ip->re) * 0.5) < 0.0 )  {
00151                         op->re = 0.0;
00152                 } else {
00153                         if( im_sign > 0 )
00154                                 op->re = sqrt(temp);
00155                         else                    /* im_sign < 0 */
00156                                 op->re = -sqrt(temp);
00157                 }
00158         }
00159 }
00160 /*@}*/
00161 /*
00162  * Local Variables:
00163  * mode: C
00164  * tab-width: 8
00165  * c-basic-offset: 4
00166  * indent-tabs-mode: t
00167  * End:
00168  * ex: shiftwidth=4 tabstop=8
00169  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6