/* -*-C-*- $Id: array.c,v 9.46 1999/01/02 06:11:34 cph Exp $ Copyright (c) 1987-1999 Massachusetts Institute of Technology This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "scheme.h" #include "prims.h" #include "array.h" #include #include /* contains some math constants */ /* ARRAY (as a scheme object) is a usual array (in C) containing REAL numbers (float/double) and tagged as a non-marked vector. Basic contents: constructors, selectors, arithmetic operations, conversion routines between C_Array, and Scheme_Vector see array.h for macros, NM_VECTOR, and extern */ /* mathematical constants */ #ifdef PI #undef PI #endif #define PI 3.141592653589793238462643 #define PI_OVER_2 1.570796326794896619231322 #define TWOPI 6.283185307179586476925287 #define SQRT_2 1.4142135623730950488 #define ONE_OVER_SQRT_2 .7071067811865475244 /* Abramowitz and Stegun p.3 */ REAL flonum_to_real (argument, arg_number) fast SCHEME_OBJECT argument; int arg_number; { switch (OBJECT_TYPE (argument)) { case TC_FIXNUM: return ((REAL) (FIXNUM_TO_DOUBLE (argument))); case TC_BIG_FIXNUM: if (! (BIGNUM_TO_DOUBLE_P (argument))) error_bad_range_arg (arg_number); return ((REAL) (bignum_to_double (argument))); case TC_BIG_FLONUM: return ((REAL) (FLONUM_TO_DOUBLE (argument))); default: error_wrong_type_arg (arg_number); /* NOTREACHED */ } } SCHEME_OBJECT allocate_array (length) long length; { #if (REAL_IS_DEFINED_DOUBLE == 0) fast SCHEME_OBJECT result = (allocate_non_marked_vector (TC_NON_MARKED_VECTOR, ((length * REAL_SIZE) + 1), true)); FAST_MEMORY_SET (result, 1, length); return (result); #else /* (REAL_IS_DEFINED_DOUBLE != 0) */ long n_words = (length * DOUBLE_SIZE); ALIGN_FLOAT (Free); Primitive_GC_If_Needed (n_words + 1); { SCHEME_OBJECT result = (MAKE_POINTER_OBJECT (TC_BIG_FLONUM, (Free))); (*Free++) = (MAKE_OBJECT (TC_MANIFEST_NM_VECTOR, n_words)); Free += n_words; return (result); } #endif /* (REAL_IS_DEFINED_DOUBLE != 0) */ } DEFINE_PRIMITIVE ("VECTOR->ARRAY", Prim_vector_to_array, 1, 1, 0) { PRIMITIVE_HEADER (1); CHECK_ARG (1, VECTOR_P); { SCHEME_OBJECT vector = (ARG_REF (1)); long length = (VECTOR_LENGTH (vector)); SCHEME_OBJECT result = (allocate_array (length)); fast SCHEME_OBJECT * scan_source = (& (VECTOR_REF (vector, 0))); fast SCHEME_OBJECT * end_source = (scan_source + length); fast REAL * scan_target = (ARRAY_CONTENTS (result)); while (scan_source < end_source) (*scan_target++) = (flonum_to_real ((*scan_source++), 1)); PRIMITIVE_RETURN (result); } } DEFINE_PRIMITIVE ("ARRAY->VECTOR", Prim_array_to_vector, 1, 1, 0) { PRIMITIVE_HEADER (1); CHECK_ARG (1, ARRAY_P); { SCHEME_OBJECT array = (ARG_REF (1)); long length = (ARRAY_LENGTH (array)); fast REAL * scan_source = (ARRAY_CONTENTS (array)); fast REAL * end_source = (scan_source + length); SCHEME_OBJECT result = (allocate_marked_vector (TC_VECTOR, length, true)); fast SCHEME_OBJECT * scan_result = (MEMORY_LOC (result, 1)); while (scan_source < end_source) (*scan_result++) = (double_to_flonum ((double) (*scan_source++))); PRIMITIVE_RETURN (result); } } DEFINE_PRIMITIVE ("ARRAY-ALLOCATE", Prim_array_allocate, 1,1, 0) { fast REAL * scan; long length; SCHEME_OBJECT result; PRIMITIVE_HEADER (1); length = (arg_nonnegative_integer (1)); result = (allocate_array (length)); for (scan = (ARRAY_CONTENTS (result)); --length >= 0; ) *scan++ = ((REAL) 0.0); PRIMITIVE_RETURN (result); } DEFINE_PRIMITIVE ("ARRAY-CONS-REALS", Prim_array_cons_reals, 3, 3, 0) { PRIMITIVE_HEADER (3); { fast double from = (arg_real_number (1)); fast double dt = (arg_real_number (2)); long length = (arg_nonnegative_integer (3)); SCHEME_OBJECT result = (allocate_array (length)); fast REAL * scan_result = (ARRAY_CONTENTS (result)); fast int i; for (i = 0; (i < length); i += 1) { (*scan_result++) = ((REAL) from); from += dt; } PRIMITIVE_RETURN (result); } } DEFINE_PRIMITIVE ("ARRAY-LENGTH", Prim_array_length, 1, 1, 0) { PRIMITIVE_HEADER (1); CHECK_ARG (1, ARRAY_P); PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (ARRAY_LENGTH (ARG_REF (1)))); } DEFINE_PRIMITIVE ("ARRAY-REF", Prim_array_ref, 2, 2, 0) { SCHEME_OBJECT array; PRIMITIVE_HEADER (2); CHECK_ARG (1, ARRAY_P); array = (ARG_REF (1)); PRIMITIVE_RETURN (double_to_flonum ((double) ((ARRAY_CONTENTS (array)) [arg_index_integer (2, (ARRAY_LENGTH (array)))]))); } DEFINE_PRIMITIVE ("ARRAY-SET!", Prim_array_set, 3, 3, 0) { SCHEME_OBJECT array; REAL * array_ptr; double old_value, new_value; PRIMITIVE_HEADER (3); CHECK_ARG (1, ARRAY_P); array = (ARG_REF (1)); array_ptr = (& ((ARRAY_CONTENTS (array)) [arg_index_integer (2, (ARRAY_LENGTH (array)))])); old_value = (*array_ptr); new_value = (arg_real_number (3)); #if (REAL_IS_DEFINED_DOUBLE == 0) if ((new_value >= 0.0) ? (new_value < ((double) FLT_MIN)) : (new_value > (0.0 - ((double) FLT_MIN)))) new_value = ((REAL) 0.0); #endif (*array_ptr) = ((REAL) new_value); PRIMITIVE_RETURN (double_to_flonum (old_value)); } /*____________________ file readers ___________ ascii and 2bint formats ______________________________________________*/ /* Reading data from files To read REAL numbers, use "lf" for double, "%f" for float */ #if (REAL_IS_DEFINED_DOUBLE == 1) #define REALREAD "%lf" #define REALREAD2 "%lf %lf" #else #define REALREAD "%f" #define REALREAD2 "%f %f" #endif static void C_Array_Read_Ascii_File (a, N, fp) /* 16 ascii decimal digits */ REAL * a; long N; FILE * fp; { fast long i; for (i = 0; (i < N); i += 1) { if ((fscanf (fp, REALREAD, (&(a[i])))) != 1) { printf("Not enough values read ---\n last value a[%d] = % .16e \n", (i-1), a[i-1]); error_external_return (); } } return; } /* 2BINT FORMAT = integer stored in 2 consecutive bytes. On many machines, "putw" and "getw" use 4 byte integers (C int) so use "putc" "getc" as shown below. */ static void C_Array_Read_2bint_File (a, N, fp) REAL * a; long N; FILE * fp; { fast long i; fast int msd; for (i = 0; (i < N); i += 1) { if (feof (fp)) error_external_return (); msd = (getc (fp)); (a [i]) = ((REAL) ((msd << 8) | (getc (fp)))); } return; } DEFINE_PRIMITIVE ("ARRAY-READ-FROM-FILE", Prim_array_read_from_file, 3,3, 0) { PRIMITIVE_HEADER (3); CHECK_ARG (1, STRING_P); /* 1 = filename */ /* 2 = length of data */ CHECK_ARG (3, FIXNUM_P); /* 3 = format of data 0=ascii 1=2bint */ { fast long length = (arg_nonnegative_integer (2)); fast SCHEME_OBJECT result = (allocate_array (length)); int format; fast FILE * fp; if ( (fp = fopen((STRING_ARG (1)), "r")) == NULL) error_bad_range_arg (1); format = arg_nonnegative_integer(3); if (format==0) C_Array_Read_Ascii_File ((ARRAY_CONTENTS (result)), length, fp); else if (format==1) C_Array_Read_2bint_File ((ARRAY_CONTENTS (result)), length, fp); else error_bad_range_arg(3); /* illegal format code */ if ((fclose (fp)) != 0) error_external_return (); PRIMITIVE_RETURN (result); } } static void C_Array_Write_Ascii_File (a, N, fp) /* 16 ascii decimal digits */ REAL * a; long N; FILE * fp; { fast long i; for (i = 0; (i < N); i += 1) { if (feof (fp)) error_external_return (); fprintf (fp, "% .16e \n", a[i]); } return; } DEFINE_PRIMITIVE ("ARRAY-WRITE-ASCII-FILE", Prim_array_write_ascii_file, 2, 2, 0) { PRIMITIVE_HEADER (2); CHECK_ARG (1, ARRAY_P); CHECK_ARG (2, STRING_P); { fast SCHEME_OBJECT array = (ARG_REF (1)); fast FILE * fp = (fopen((STRING_ARG (2)), "w")); if (fp == ((FILE *) 0)) error_bad_range_arg (2); C_Array_Write_Ascii_File ((ARRAY_CONTENTS (array)), (ARRAY_LENGTH (array)), fp); if ((fclose (fp)) != 0) error_external_return (); } PRIMITIVE_RETURN (UNSPECIFIC); } DEFINE_PRIMITIVE ("SUBARRAY-COPY!", Prim_subarray_copy, 5, 5, 0) { PRIMITIVE_HEADER (5); CHECK_ARG (1, ARRAY_P); /* source array */ CHECK_ARG (2, ARRAY_P); /* destination array */ { REAL * source = (ARRAY_CONTENTS (ARG_REF (1))); REAL * target = (ARRAY_CONTENTS (ARG_REF (2))); long start_source = (arg_nonnegative_integer (3)); long start_target = (arg_nonnegative_integer (4)); long n_elements = (arg_nonnegative_integer (5)); if ((start_source + n_elements) > (ARRAY_LENGTH (ARG_REF (1)))) error_bad_range_arg (3); if ((start_target + n_elements) > (ARRAY_LENGTH (ARG_REF (2)))) error_bad_range_arg (4); { fast REAL * scan_source = (source + start_source); fast REAL * end_source = (scan_source + n_elements); fast REAL * scan_target = (target + start_target); while (scan_source < end_source) (*scan_target++) = (*scan_source++); } } PRIMITIVE_RETURN (UNSPECIFIC); } DEFINE_PRIMITIVE ("ARRAY-REVERSE!", Prim_array_reverse, 1, 1, 0) { PRIMITIVE_HEADER (1); CHECK_ARG (1, ARRAY_P); { SCHEME_OBJECT array = (ARG_REF (1)); long length = (ARRAY_LENGTH (array)); long half_length = (length / 2); fast REAL * array_ptr = (ARRAY_CONTENTS (array)); fast long i; fast long j; for (i = 0, j = (length - 1); (i < half_length); i += 1, j -= 1) { fast REAL Temp = (array_ptr [j]); (array_ptr [j]) = (array_ptr [i]); (array_ptr [i]) = Temp; } } PRIMITIVE_RETURN (UNSPECIFIC); } DEFINE_PRIMITIVE ("ARRAY-TIME-REVERSE!", Prim_array_time_reverse, 1, 1, 0) { void C_Array_Time_Reverse (); PRIMITIVE_HEADER (1); CHECK_ARG (1, ARRAY_P); C_Array_Time_Reverse ((ARRAY_CONTENTS (ARG_REF (1))), (ARRAY_LENGTH (ARG_REF (1)))); PRIMITIVE_RETURN (UNSPECIFIC); } /* time-reverse x[0] remains fixed. (time=0) x[i] swapped with x[n-i]. (mirror image around x[0]) */ void C_Array_Time_Reverse (x,n) REAL *x; long n; { long i, ni, n2; REAL xt; if ((n % 2) == 0) /* even length */ { n2 = (n/2); for (i=1; i (ARRAY_LENGTH(ARG_REF(1)))) error_bad_range_arg(3); offset = (arg_real (4)); scale = (arg_real (5)); if ((offset == 0.0) && (scale == 1.0)) ; /* be smart */ else if (scale == 0.0) for (i=at; i (ARRAY_LENGTH(ARG_REF(1)))) error_bad_range_arg(4); x = (arg_real_number (5)); y = (arg_real_number (6)); a = ARRAY_CONTENTS(ARG_REF(1)); b = ARRAY_CONTENTS(ARG_REF(2)); if ((ARRAY_LENGTH(ARG_REF(1))) != (ARRAY_LENGTH(ARG_REF(2)))) error_bad_range_arg(2); if (x==0.0) /* imaginary only */ if (y==0.0) for (i=at; i (ARRAY_LENGTH(ARG_REF(1)))) error_bad_range_arg(5); if (tc==1) { x = 1.0; /* real part of accumulator */ y = 0.0; /* imag part of accumulator */ for (i=at;i= 0.0) /* It may be faster to look at the sign of mantissa, and dispatch */ modf( ((double) ((*a)+0.5)), &integral_part); else modf( ((double) ((*a)-0.5)), &integral_part); (*b) = ( (REAL) integral_part); } void REALsquare (a,b) REAL *a,*b; { (*b) = ( (REAL) ((*a) * (*a)) ); } void REALsqrt (a,b) REAL *a,*b; { if ((*a) < 0.0) error_bad_range_arg(1); /* sqrt(negative) */ (*b) = ( (REAL) sqrt( (double) (*a)) ); } void REALsin (a,b) REAL *a,*b; { (*b) = ( (REAL) sin( (double) (*a)) ); } void REALcos (a,b) REAL *a,*b; { (*b) = ( (REAL) cos( (double) (*a)) ); } void REALtan (a,b) REAL *a,*b; { (*b) = ( (REAL) tan( (double) (*a)) ); } void REALasin (a,b) REAL *a,*b; { (*b) = ( (REAL) asin( (double) (*a)) ); } void REALacos (a,b) REAL *a,*b; { (*b) = ( (REAL) acos( (double) (*a)) ); } void REALatan (a,b) REAL *a,*b; { (*b) = ( (REAL) atan( (double) (*a)) ); } void REALgamma (a,b) REAL *a,*b; { fast double y; if ((y = gamma(((double) (*a)))) > LN_MAXDOUBLE) error_bad_range_arg(1); /* gamma( non-positive integer ) */ (*b) = ((REAL) (signgam * exp(y))); /* see HPUX Section 3 */ } void REALerf (a,b) REAL *a,*b; { (*b) = ( (REAL) erf((double) (*a)) ); } void REALerfc (a,b) REAL *a,*b; { (*b) = ( (REAL) erfc((double) (*a)) ); } void REALbessel1 (order,a,b) /* Bessel of first kind */ long order; REAL *a,*b; { if (order == 0) (*b) = ( (REAL) j0((double) (*a)) ); if (order == 1) (*b) = ( (REAL) j1((double) (*a)) ); else (*b) = ( (REAL) jn(((int) order), ((double) (*a))) ); } void REALbessel2 (order,a,b) /* Bessel of second kind */ long order; REAL *a,*b; { if ((*a) <= 0.0) error_bad_range_arg(1); /* Blows Up */ if (order == 0) (*b) = ( (REAL) y0((double) (*a)) ); if (order == 1) (*b) = ( (REAL) y1((double) (*a)) ); else (*b) = ( (REAL) yn(((int) order), ((double) (*a))) ); } /* Table to store the available unary-functions. Also some binary functions at the end -- not available right now. The (1 and 2)s denote the numofargs (1 for unary 2 for binary) */ struct array_func_table { long numofargs; void (*func)(); } Array_Function_Table [] = { 1, REALabs, /*0*/ 1, REALexp, /*1*/ 1, REALlog, /*2*/ 1, REALtruncate, /*3*/ 1, REALround, /*4*/ 1, REALsquare, /*5*/ 1, REALsqrt, /*6*/ 1, REALsin, /*7*/ 1, REALcos, /*8*/ 1, REALtan, /*9*/ 1, REALasin, /*10*/ 1, REALacos, /*11*/ 1, REALatan, /*12*/ 1, REALgamma, /*13*/ 1, REALerf, /*14*/ 1, REALerfc, /*15*/ 2, REALbessel1, /*16*/ 2, REALbessel2 /*17*/ }; #define MAX_ARRAY_FUNCTC 17 /* array-unary-function! could be called array-operation-1! following the naming convention for other similar procedures but it is specialized to mappings only, so we have special name. */ DEFINE_PRIMITIVE ("ARRAY-UNARY-FUNCTION!", Prim_array_unary_function, 2,2, 0) { long n, i; REAL *a,*b; long tc; void (*f)(); PRIMITIVE_HEADER (2); CHECK_ARG (1, ARRAY_P); /* a = input (and output) array */ CHECK_ARG (2, FIXNUM_P); /* tc = type code */ tc = arg_nonnegative_integer(2); if (tc > MAX_ARRAY_FUNCTC) error_bad_range_arg(2); f = ((Array_Function_Table[tc]).func); if (1 != (Array_Function_Table[tc]).numofargs) error_wrong_type_arg(2); /* check it is a unary function */ a = ARRAY_CONTENTS(ARG_REF(1)); b = a; n = ARRAY_LENGTH(ARG_REF(1)); for (i=0; i (ARRAY_LENGTH(ARG_REF(1)))) error_bad_range_arg(4); if (tc == 0) { result = 0.0; for (i=at;i= (fabs ((double) ((a [i]) - value)))) PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (i)); } PRIMITIVE_RETURN (SHARP_F); } DEFINE_PRIMITIVE ("SUBARRAY-MIN-MAX-INDEX", Prim_subarray_min_max_index, 3, 3, 0) { PRIMITIVE_HEADER (3); CHECK_ARG (1, ARRAY_P); { REAL * a = (ARRAY_CONTENTS (ARG_REF (1))); long at = (arg_nonnegative_integer (2)); /* starting index */ long m = (arg_nonnegative_integer (3)); /* number of points to process */ long mplus = (at + m); long nmin; long nmax; if (mplus > (ARRAY_LENGTH (ARG_REF (1)))) error_bad_range_arg (3); C_Array_Find_Min_Max ((& (a [at])), m, (&nmin), (&nmax)); nmin = nmin + at; /* offset appropriately */ nmax = nmax + at; PRIMITIVE_RETURN (cons ((LONG_TO_FIXNUM (nmin)), (cons ((LONG_TO_FIXNUM (nmax)), EMPTY_LIST)))); } } void C_Array_Find_Min_Max (x, n, nmin, nmax) fast REAL * x; fast long n; long * nmin; long * nmax; { REAL *xold = x; register REAL xmin, xmax; register long nnmin, nnmax; register long count; nnmin = nnmax = 0; xmin = xmax = *x++; n--; count = 1; if(n>0) { do { if(*x < xmin) { nnmin = count++ ; xmin = *x++ ; } else if(*x > xmax) { nnmax = count++ ; xmax = *x++ ; } else { count++ ; x++ ; } } while( --n > 0 ) ; } *nmin = nnmin ; *nmax = nnmax ; } /* array-average can be done with (array-reduce +) and division by array-length. But there is also this C primitive. Keep it around, may be useful someday. */ /* Computes the average in pieces, so as to reduce roundoff smearing in cumulative sum. example= first huge positive numbers, then small nums, then huge negative numbers. */ static void C_Array_Find_Average (Array, Length, pAverage) long Length; REAL * Array; REAL * pAverage; { long i; long array_index; REAL average_n, sum; average_n = 0.0; array_index = 0; while (array_index < Length) { sum = 0.0; for (i=0;((array_index xmax) error_bad_range_arg (3); for (i = 0; (i < Length); i += 1) { if ((*From_Here) < xmin) (*To_Here++) = xmin; else if ((*From_Here) > xmax) (*To_Here++) = xmax; else (*To_Here++) = (*From_Here); From_Here += 1; } } PRIMITIVE_RETURN (UNSPECIFIC); } /* complex-array-operation-1! groups together procedures that use 1 complex-array and store the result in place */ DEFINE_PRIMITIVE ("COMPLEX-ARRAY-OPERATION-1!", Prim_complex_array_operation_1, 3,3, 0) { long n, i, opcode; REAL *a, *b; void complex_array_to_polar(), complex_array_exp(), complex_array_sqrt(); void complex_array_sin(), complex_array_cos(); void complex_array_asin(), complex_array_acos(), complex_array_atan(); PRIMITIVE_HEADER (3); CHECK_ARG (1, FIXNUM_P); /* operation opcode */ CHECK_ARG (2, ARRAY_P); /* input array -- n real part */ CHECK_ARG (3, ARRAY_P); /* input array -- n imag part */ n = ARRAY_LENGTH(ARG_REF(2)); if (n != ARRAY_LENGTH(ARG_REF(3))) error_bad_range_arg(3); a = ARRAY_CONTENTS(ARG_REF(2)); /* real part */ b = ARRAY_CONTENTS(ARG_REF(3)); /* imag part */ opcode = arg_nonnegative_integer(1); if (opcode==1) complex_array_to_polar(a,b,n); else if (opcode==2) complex_array_exp(a,b,n); else if (opcode==3) complex_array_sqrt(a,b,n); else if (opcode==4) complex_array_sin(a,b,n); else if (opcode==5) complex_array_cos(a,b,n); /* for tan(z) use sin(z)/cos(z) */ else if (opcode==6) complex_array_asin(a,b,n); else if (opcode==7) complex_array_acos(a,b,n); else if (opcode==8) complex_array_atan(a,b,n); else error_bad_range_arg(1); /* illegal opcode */ PRIMITIVE_RETURN (UNSPECIFIC); } void complex_array_to_polar (a,b,n) REAL *a,*b; long n; { long i; double x,y, temp; for (i=0; i=0.0) b[i] = sqrt((r-x)/2.0); /* choose principal root */ else /* see Abramowitz (p.17 3.7.27) */ b[i] = -sqrt((r-x)/2.0); } } void complex_array_sin (a,b,n) REAL *a,*b; long n; { long i; double x, ey,fy; REAL temp; for (i=0; i=0.0) imag = sqrt((r-x)/2.0); /* choose principal root */ else /* see Abramowitz (p.17 3.7.27) */ imag = -sqrt((r-x)/2.0); real = real - oldy; /* i*z + sqrt(...) */ imag = imag + oldx; b[i] = (REAL) (- log (sqrt (real*real + imag*imag))); /* -i*log(...) */ a[i] = (REAL) atan2( imag, real); /* chosen angle is okay Also 0/0 doesnot occur */ } } void complex_array_acos (a,b,n) REAL *a,*b; long n; { long i; complex_array_asin (a,b,n); for (i=0; i0.0)) return(.08 + .46 * (1 - t_bar)); else return (0); } double unit_square_wave (t) double t; { double twopi = 6.28318530717958; double fmod(), fabs(); double pi = twopi/2.; double t_bar = ((REAL) fabs(fmod( ((double) t), twopi))); if (t_bar < pi) return(1); else return(-1); } double unit_triangle_wave (t) double t; { double twopi = 6.28318530717958; double pi = twopi/2.; double pi_half = pi/2.; double three_pi_half = pi+pi_half; double t_bar = ((double) fabs(fmod( ((double) t), twopi))); if (t_bar0.0)) return(.5 * (1 - t_bar)); else return (0.0); } double integer_power (a, n) double a; long n; { double b; double integer_power(); if (n<0) exit(-1); else if (n==0) return(1.0); else if (n==1) return(a); else if ((n%2) == 0) { b = integer_power(a, n/2); return(b*b); } else return(a * integer_power(a, (n-1))); } /* array-operation-1! groups together procedures that use 1 array and store the result in place (e.g. random) */ DEFINE_PRIMITIVE ("ARRAY-OPERATION-1!", Prim_array_operation_1, 2,2, 0) { long n, opcode; REAL *a; void array_random(); PRIMITIVE_HEADER (2); CHECK_ARG (1, FIXNUM_P); /* operation opcode */ CHECK_ARG (2, ARRAY_P); /* input array -- n */ n = ARRAY_LENGTH(ARG_REF(2)); a = ARRAY_CONTENTS(ARG_REF(2)); opcode = arg_nonnegative_integer(1); if (opcode==1) array_random(a,n); else if (opcode==2) error_bad_range_arg(1); /* illegal opcode */ else error_bad_range_arg(1); /* illegal opcode */ PRIMITIVE_RETURN (UNSPECIFIC); } void array_random (a,n) REAL *a; long n; { long i; /* HPUX 3: Rand uses a multiplicative congruential random-number generator with period 2^32 that returns successive pseudo-random numbers in the range from 0 to 2^15-1 */ for (i=0;i fabs(*(a+m+(k-1)*n-1))) m = i; *(pvt+k-1) = m; if (m != k) *(pvt+n-1) = - *(pvt+n-1); p = *(a+m+(k-1)*n-1); *(a+m+(k-1)*n-1) = *(a+k+(k-1)*n-1); *(a+k+(k-1)*n-1) = p; if (p != 0.0) { for (i=k+1; i<=n; i++) *(a+i+(k-1)*n-1) = - *(a+i+(k-1)*n-1) / p; for (j=k+1; j<=n; j++) { t = *(a+m+(j-1)*n-1); *(a+m+(j-1)*n-1) = *(a+k+(j-1)*n-1); *(a+k+(j-1)*n-1) = t; if (t != 0.0) for (i=k+1; i<=n; i++) *(a+i+(j-1)*n-1) = *(a+i+(j-1)*n-1) + *(a+i+(k-1)*n-1) * t; } } } for (k=1; k