This is MathComplexArray.m in view mode; [Download] [Up]
/* MathComplexArray - Template for complex number array classes Copyright (C) 1995, Adam Fedor Should run this through a preprocessor each time defining the macro MATH_ORDER to be a number from 1 to 2. $Id: MathComplexArray.m,v 1.15 1996/07/09 13:55:16 adam Exp $ */ # line 12 "MathComplexArray.m" #ifdef NEXT_FOUNDATION #import <foundation/NSString.h> #import <foundation/NSNotification.h> #else #import <Foundation/NSString.h> #if OBJECTS_MINOR_VERSION != 1 #import <Foundation/NSNotification.h> #endif #endif #include <math.h> #include "MathArrayPrivate.h" #include "MathArray/MAValue.h" #include "MathArray/MAValueData.h" #include "MathArray/array_encoding.h" #include "MathArray/complex.h" #include "MathComplexArrayPrivate.h" /* Note: precsion is defined in terms of three words: 0xaabbcc, where cc is the storage size of the number. bb is 1 if signed and aa is an arbitrary order that increases for more "precise" numbers */ #if MATH_ORDER == 1 # define MathComplexArray MathComplexFloatArray # define MATH_TYPE complex_float # define MATH_REAL_TYPE float # define MATH_CAST_METHOD complexFloatValue static precision_t precision = 0x400110; #elif MATH_ORDER == 2 # define MathComplexArray MathComplexDoubleArray # define MATH_TYPE complex_double # define MATH_REAL_TYPE double # define MATH_CAST_METHOD complexDoubleValue static precision_t precision = 0x500120; #endif static void fourn(MATH_REAL_TYPE *data, const unsigned *nn, int ndim, int isign); typedef MATH_TYPE (*caster_f_t)(void *, unsigned long); static caster_f_t cast_function(const char *); @interface MathComplexArray : MathArray { } @end @implementation MathComplexArray : MathArray + (precision_t)precision { return precision; } + (const char *)objCType { return @encode(MATH_TYPE); } - convertFromObjCType:(const char *)old_type { ordered_index_t i, max_elements; MATH_TYPE *data; caster_f_t caster = cast_function(old_type); max_elements = array_num_elements(dimension, [size bytes]); if (array_aligned_sizeof_elements(old_type) < array_aligned_sizeof_elements([arrayData objCType])) { [arrayData setCount:array_num_elements(dimension, [size bytes])]; data = [arrayData mutableBytes]; for (i=0; i < max_elements; i++) data[max_elements-i-1] = caster(data, max_elements-i-1); } else { data = [arrayData mutableBytes]; for (i=0; i < max_elements; i++) data[i] = caster(data, i); [arrayData setCount:array_num_elements(dimension, [size bytes])]; } return self; } - maMatrixMultiply:(MathArray *)otherArray { BOOL odd; unsigned i, j, k; unsigned a_size[2]; unsigned b_size[2]; void *b_data; MAMutableValueData *cMatrix; MATH_TYPE *a_data; MATH_TYPE *c_data; MATH_TYPE (*caster)(void *, unsigned long) = cast_function([otherArray objCType]); [super maMatrixMultiply:otherArray]; a_size[0] = [self sizes][0]; if (dimension == 2) a_size[1] = [self sizes][1]; else a_size[1] = 1; b_size[0] = [otherArray sizes][0]; if ([otherArray dimension] == 2) b_size[1] = [otherArray sizes][1]; else b_size[1] = 1; cMatrix = [MAMutableValueData dataWithCount:a_size[0]*b_size[1] objCType:[self objCType]]; a_data = [arrayData mutableBytes]; b_data = [[otherArray mathData] mutableBytes]; c_data = [cMatrix mutableBytes]; odd = (a_size[1] & 0x1); for (i=0; i < a_size[0]; i++) { for (j=0; j < b_size[1]; j++) { unsigned loc = i*b_size[1]+j; c_data[loc].real = 0; c_data[loc].imag = 0; for (k=0; k < a_size[1]; k++) { // FIXME: should we just cast to double since all ops are on double anyway? #if MATH_ORDER == 1 c_data[loc] = c_d2f( c_add( c_f2d(c_data[loc]), c_mult(c_f2d(a_data[i*a_size[1]+k]), c_f2d(caster(b_data, k*b_size[1]+j))) ) ); #else c_data[loc] = c_add(c_data[loc], c_mult(a_data[i*a_size[1]+k], caster(b_data, k*b_size[1]+j) )); #endif #ifdef MATH_CHECK_FPE if (!finite(c_data[loc].real) || !finite(c_data[loc].imag)) ma_fpe_errno = FLT_OVERFLOW; #endif } } } [arrayData release]; arrayData = [cMatrix retain]; a_size[1] = b_size[1]; if (a_size[1] == 1) dimension = 1; [size release]; size = [[MAValueData dataWithValues:a_size count:dimension objCType:@encode(unsigned)] retain]; return self; } - _maOperate:(ma_operator_t)operator with:(MathArray *)value { unsigned long i, j, max_elements; unsigned long increment; void *otherData; MATH_TYPE *data; operate_f_t operate = operate_function(operator); caster_f_t caster = cast_function([value objCType]); if (operator == ma_matrix_multiply) { return [self maMatrixMultiply:value]; } if (operate == 0) { MA_RAISE_ILLEGAL; /* NOT REACHED */ } data = [arrayData mutableBytes]; increment = 1; otherData = [[value mathData] mutableBytes]; if ([value dimension] == 0) increment = 0; max_elements = array_num_elements(dimension, [size bytes]); j = 0; for (i=0; i < max_elements; i++) { // FIXME: should we just cast to double since all ops are on double anyway? #if MATH_ORDER == 1 MATH_TYPE num; complex_double num1, num2; num1 = complexf2d(data, i); num = caster(otherData, j); num2 = complexf2d(&num, 0); num1 = operate(num1, num2); data[i] = complexd2f( &num1, 0); #else data[i] = operate(data[i], caster(otherData, j)); #endif #ifdef MATH_CHECK_FPE if (!finite(data[i].real) || !finite(data[i].imag)) ma_fpe_errno = FLT_OTHER; #endif j += increment; } return self; } - _maPerform: (double_func_t)mathFunction { unsigned long i, max_elements; MATH_TYPE *data; complex_func_t cmathFunc = replace_function(mathFunction); if (cmathFunc == 0) { MA_RAISE_ILLEGAL; /* NOT REACHED */ } max_elements = array_num_elements(dimension, [size bytes]); data = [arrayData mutableBytes]; for (i=0; i < max_elements; i++) { #if MATH_ORDER == 1 complex_double num; num = cmathFunc(complexf2d(data, i)); data[i] = complexd2f(&num, 0); #else data[i] = cmathFunc(data[i]); #endif #ifdef MATH_CHECK_FPE if (!finite(data[i].real) || !finite(data[i].imag)) ma_fpe_errno = FLT_OTHER; #endif } return self; } - _maPerformFunction:(perform_func_t)perform_func userInfo:(void *)info { unsigned long i, max_elements; unsigned *index = [[[size mutableCopy] autorelease] mutableBytes]; MATH_TYPE *data; NSRange *range; range = [[MAMutableValueData dataWithCount:dimension objCType:@encode(NSRange)] mutableBytes]; for (i=0; i < dimension; i++) { range[i].location = 0; range[i].length = ((unsigned *)[size bytes])[i]; } index = start_index_from_range(dimension, range, index); max_elements = array_num_elements(dimension, [size bytes]); data = [arrayData mutableBytes]; // FIXME: need to set up autorelease pool to get rid of extra objects for (i=0; i < max_elements; i++) { id <NSNumber,ComplexNumber> number; number = (id <NSNumber,ComplexNumber>)[arrayData valueAtIndex:i]; number = perform_func(number, index, info); data[i] = [number MATH_CAST_METHOD]; #ifdef MATH_CHECK_FPE if (!finite(data[i].real) || !finite(data[i].imag)) ma_fpe_errno = FLT_OTHER; #endif increment_index_in_range(dimension, range, index, 1); } return self; } /* Calulate complex absolute value, store in the real part and then call maReal to cast ourselves to a real type */ - maAbs { unsigned long i, max_elements; MATH_TYPE *data; [MathArray _startMath]; [self _updateLazyArray]; max_elements = array_num_elements(dimension, [size bytes]); data = [arrayData mutableBytes]; for (i=0; i < max_elements; i++) { #if MATH_ORDER == 1 data[i].real = c_abs(complexf2d(data, i)); #else data[i].real = (double)c_abs(data[i]); #endif } [MathArray _finishMath]; return [self maReal]; } - maMagnitude { return [self maAbs]; } - maPhase { unsigned long i, max_elements; MATH_TYPE *data; [MathArray _startMath]; [self _updateLazyArray]; max_elements = array_num_elements(dimension, [size bytes]); data = [arrayData mutableBytes]; for (i=0; i < max_elements; i++) { data[i].real = atan2(data[i].imag, data[i].real); #ifdef MATH_CHECK_FPE if (!finite(data[i].real) || !finite(data[i].imag)) ma_fpe_errno = FLT_OTHER; #endif } [MathArray _finishMath]; return [self maReal]; } - maConjugate { unsigned long i, max_elements; MATH_TYPE *data; [MathArray _startMath]; [self _updateLazyArray]; max_elements = array_num_elements(dimension, [size bytes]); data = [arrayData mutableBytes]; for (i=0; i < max_elements; i++) { #if MATH_ORDER == 1 complex_double num; num = conj(complexf2d(data, i)); data[i] = complexd2f(&num, 0); #else data[i] = conj(data[i]); #endif } [MathArray _finishMath]; return self; } /* Performs a Fast-Fourier Transform on the receiver in the specified direction: -1 for a forward transform, +1 for an inverse transform. */ - maFFt:(int)direction { int i; const unsigned *sizes; MATH_TYPE *data; [self _updateLazyArray]; sizes = [size bytes]; /* FIXME: Currently FFTs are restricted to arrays of powers of two */ for (i=0; i < dimension; i++) if (sizes[i] != ((int)pow(2, log(sizes[i])/log(2)))) [NSException raise:MAPerformException format:@"Cannot perform FFT on non power-of-two arrays."]; data = [arrayData mutableBytes]; [MathArray _startMath]; /* FIXME: Expect complex numbers to just be two reals in a row. OK? */ fourn((MATH_REAL_TYPE *)data, sizes, dimension, direction); [MathArray _finishMath]; /* Scale forward transform by array size */ if (direction < 0) [self maDivide:[MANumber numberWithDouble:array_num_elements(dimension, sizes)]]; return self; } - maInvert { [self maNotImplemented:_cmd]; return self; } - (id <NSNumber,ComplexNumber>)_loopArrayWith: (complex_double (*)(complex_double, complex_double))loopFunc { unsigned long i, max_elements; const MATH_TYPE *data; complex_double number; [MathArray _startMath]; max_elements = array_num_elements(dimension, [size bytes]); data = [arrayData bytes]; #if MATH_ORDER == 1 number = complexf2d(data, 0); #else number = data[0]; #endif for (i=1; i < max_elements; i++) #if MATH_ORDER == 1 number = loopFunc(number, complexf2d(data, i)); #else number = loopFunc(number, data[i]); #endif [MathArray _finishMath]; return (MANumber *)[MANumber value:&number withObjCType:@encode(complex_double)]; } - (id <NSNumber,ComplexNumber>)maMinimumValue { return [self _loopArrayWith:find_cmin]; } - (id <NSNumber,ComplexNumber>)maMaximumValue { return [self _loopArrayWith:find_cmax]; } - (id <NSNumber,ComplexNumber>)maTotal { return [self _loopArrayWith:find_csum]; } - maWhere { ordered_index_t i, max_elements; unsigned j; MATH_TYPE *data; j = 0; max_elements = array_num_elements(dimension, [size bytes]); data = [arrayData mutableBytes]; for (i=0; i < max_elements; i++) if (data[i].real || data[i].imag) data[j++].real = i; [self maReal]; [arrayData setCount:j]; [size release]; dimension = 1; size = [[MAValueData dataWithValues:&j count:dimension objCType:@encode(unsigned)] retain]; return self; } @end /* All the functions which know how to cast from any known type to our type */ static inline MATH_TYPE cast_from_uchar(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((unsigned char*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_char(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((char*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_ushort(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((unsigned short*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_short(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((short*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_uint(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((unsigned int*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_int(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((int*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_ulong(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((unsigned long*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_long(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((long*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_ulonglong(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((unsigned long long*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_longlong(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((long long*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_float(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((float*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_double(void *data, unsigned long loc) { MATH_TYPE t; t.real = *((double*)data + loc); t.imag = 0; return t; } static inline MATH_TYPE cast_from_complexfloat(void *data, unsigned long loc) { MATH_TYPE t; t.real = ((complex_float*)data + loc)->real; t.imag = ((complex_float*)data + loc)->imag; return t; } static inline MATH_TYPE cast_from_complexdouble(void *data, unsigned long loc) { MATH_TYPE t; t.real = ((complex_double*)data + loc)->real; t.imag = ((complex_double*)data + loc)->imag; return t; } static caster_f_t cast_function(const char *type) { switch(*type) { case _C_CHR: return cast_from_char; break; case _C_UCHR: return cast_from_uchar; break; case _C_SHT: return cast_from_short; break; case _C_USHT: return cast_from_ushort; break; case _C_INT: return cast_from_int; break; case _C_UINT: return cast_from_uint; break; case _C_LNG: return cast_from_long; break; case _C_ULNG: return cast_from_ulong; break; case 'q': return cast_from_longlong; break; case 'Q': return cast_from_ulonglong; break; case _C_FLT: return cast_from_float; break; case _C_DBL: return cast_from_double; break; case _C_STRUCT_B: // FIXME: need better check for complex if (math_aligned_size (type) == math_aligned_size (@encode(complex_float))) return cast_from_complexfloat; else if (math_aligned_size (type) == math_aligned_size (@encode(complex_double))) return cast_from_complexdouble; break; } MA_RAISE_CAST; /* NOT REACHED */ return 0; } /*-------------------------------------------------------------------fourn fourn - N-dimensional fourier transform from Numerical Recipies data - ndim-dimensional array of complex numbers stored in row major order nn - an integer array containing the lengths of each dimension ndim - number of dimensions of the array data isign - direction of F.T (-1 for foreward transform) Extra special sneaky addition: If abs(isign) > 1, then this routine also prints out a percentage indication of how far along the routine is in processing (isign is also set back to isign/abs(isign)). */ #define SWAP(a,b) (tempr=(a),(a)=(b),(b)=tempr) static void fourn(MATH_REAL_TYPE *data, const unsigned *nn, int ndim, int isign) { int i1,i2,i3,i2rev,i3rev,ip1,ip2,ip3,ifp1,ifp2; int ibit,idim,k1,k2,n,nprev,nrem,ntot; int count, total; double tempi,tempr; double theta,wi,wpi,wpr,wr,wtemp; ntot=1; total=0; for (idim=0;idim<ndim;idim++) ntot *= nn[idim]; /* Extra special sneaky addition -- If abs(isign) is greater than one, this is a signal to print out our completion status */ if (abs(isign) > 1) { isign = (isign > 0) ? 1 : -1; total = 0; count = ntot; while ((count = count >> 1)) total++; } nprev=1; for (idim=ndim-1;idim>=0;idim--) { n=nn[idim]; nrem=ntot/(n*nprev); ip1=nprev << 1; ip2=ip1*n; ip3=ip2*nrem; i2rev=1; for (i2=1;i2<=ip2;i2+=ip1) { if (i2 < i2rev) { for (i1=i2;i1<=i2+ip1-2;i1+=2) { for (i3=i1;i3<=ip3;i3+=ip2) { i3rev=i2rev+i3-i2; SWAP(data[i3-1],data[i3rev-1]); SWAP(data[i3 ],data[i3rev ]); } } } ibit=ip2 >> 1; while (ibit >= ip1 && i2rev > ibit) { i2rev -= ibit; ibit >>= 1; } i2rev += ibit; } ifp1=ip1; while (ifp1 < ip2) { #if defined(NEXT_FOUNDATION) || OBJECTS_MINOR_VERSION != 1 if (total) [[NSNotificationCenter defaultCenter] postNotificationName: STATUS_CHECK_NOTIFICATION object: [NSNumber numberWithInt: ((float)(++count)/total)*100]]; #endif ifp2=ifp1 << 1; theta=isign*6.28318530717959/(ifp2/ip1); wtemp=sin(0.5*theta); wpr = -2.0*wtemp*wtemp; wpi=sin(theta); wr=1.0; wi=0.0; for (i3=1;i3<=ifp1;i3+=ip1) { for (i1=i3;i1<=i3+ip1-2;i1+=2) { for (i2=i1;i2<=ip3;i2+=ifp2) { k1=i2; k2=k1+ifp1; tempr=wr*data[k2-1]-wi*data[k2]; tempi=wr*data[k2]+wi*data[k2-1]; data[k2-1]=data[k1-1]-tempr; data[k2]=data[k1]-tempi; data[k1-1] += tempr; data[k1 ] += tempi; } } wr=(wtemp=wr)*wpr-wi*wpi+wr; wi=wi*wpr+wtemp*wpi+wi; } ifp1=ifp2; } nprev *= n; } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.