# include # include # include # include # include # include # define MACHINE APPLE_MAC # include "matmul.h" void abortm ( ); void chop(char*,int,int); void Docom(); void Explain ( ); void Flclos ( ); void Flopen ( ); void Gbye ( ); void Getcom ( ); void Getlda(char*); void Getn(char*); void Getord(char*, int*); void Getsho(char* ,int); void Help ( ); int min(int,int); void Mult ( ); int Nstep ( ); void Pdump ( ); void Printr ( ); void Putinp(); void Putout(); void Record ( ); void Result(short lchop); #if MACHINE == VAX_VMS void second(int*); #elif MACHINE == IBM_PC void second(long*); #elif MACHINE == IBM_RS6 void second(long*); #elif MACHINE == CRAY extern float SDOT(); extern SAXPY(); extern SGEMM(); void second(long*); #else void second(long*,long*); #endif void setval ( ); void Shoord ( ); void taxpy(int n,float *sa,float *sx,int incx,float *sy,int incy); void _TDOT(); float tdot(); void timestamp ( ); void TSTART ( ); void TSTOP ( ); void TMSTART ( ); void TMSTOP ( ); void Zero ( int len ); /******************************************************************************/ int main ( ) /******************************************************************************/ /* Purpose: matmul() is an interactive program demonstrating matrix multiplication. Discussion: MATMUL sets up, carries out, and times a matrix multiplication. MATMUL can use several different algorithms and matrix sizes, and can be run on many different computers. First some initialization is done, and then the program gets a command from the user, executes it, and repeats. File usage: matmul.inp, record of input, created by MATMUL. matmul.out, record of input/output, created by MATMUL. matmul.hlp, help file. (Not available) matmul.dat, data file, created by MATMUL. matmul.exp, explanation file, read by MATMUL. Licensing: This code is distributed under the MIT license. Modified: 15 May 2009 Author: John Burkardt, Paul Puglielli. */ { timestamp ( ); printf ( "\n" ); printf ( "matmul():\n" ); printf ( " C version\n" ); printf ( " An interactive demonstration of matrix multiplication.\n" ); setval ( ); Flopen(); for ( ; ; ) { Getcom ( ); Docom ( ); } return 0; } /******************************************************************************/ void abortm ( ) /******************************************************************************/ /* Purpose: abortm() is called to terminate execution. Discussion: ABORTM dumps the results to a file, says "goodbye" to the user, and closes all files. */ { Pdump(); Gbye(); Flclos(); timestamp ( ); exit ( 1 ); } /******************************************************************************/ void chop ( char *STRING, int ILO, int IHI ) /******************************************************************************/ /* CHOP "chops" out entries ILO through IHI of STRING, shifts the string down, and pads the end of the string with NULLs. */ { size_t l; int i,j; l=strlen(STRING); i=ILO; for(j=IHI+1;j22) { getchar(); line=0; } } fclose ( ifilee ); ifilee=NULL; return; } /******************************************************************************/ void Flclos() /******************************************************************************/ /* FLCLOS closes all the files */ { if (ifilei) fclose(ifilei); if (ifileo) fclose(ifileo); if (ifileh) fclose(ifileh); if (ifiled) fclose(ifiled); return; } /******************************************************************************/ void Flopen() /******************************************************************************/ /* FLOPEN opens all the files. EXCEPT for matmul.dat, which is opened in Pdump. */ { char outline[80]; ifileo=fopen(fileo,"w"); if(!ifileo) { sprintf(outline,"MATMUL could not open the output file %s",fileo); Putout(outline); Putout("This is not a serious problem, but it does mean there\n"); Putout("will not be a transcript of the input and output\n"); } ifilei=fopen(filei,"w"); if(!ifilei) { sprintf(outline,"MATMUL could not open the output file %s\n",filei); Putout(outline); Putout("This is not a serious problem, but it does mean there\n"); Putout("will not be a record of you output.\n"); } /* HELP system not available yet! ifileh=fopen(fileh,"r"); if(!ifileh) { sprintf(outline,"MATMUL could not open the help file %s\n",fileh); Putout(outline); Putout("This is not a serious problem, but it does mean that\n"); Putout("the full help system will not be available.\n"); } */ ifileh=NULL; return; } /******************************************************************************/ void Gbye() /******************************************************************************/ /* GBYE says goodbye to the user, and prints a reminder about files created by the program. */ { char outline[80]; if(ifilei) sprintf(outline,"A copy of your input is in the file %s\n",filei); else sprintf(outline,"MATMUL could not create the input file %s\n",filei); Putout(outline); if(ifiled) sprintf(outline,"A copy of your results is in the file %s\n",filed); else sprintf(outline,"MATMUL could not create the result file %s\n",filed); Putout(outline); if(ifileo) sprintf(outline,"A copy of the entire session is in the file %s\n",fileo); else sprintf(outline,"MATMUL could not create the session file %s\n",fileo); Putout(outline); printf ( "\n" ); printf ( "MATMUL:\n" ); printf ( " Normal end of execution.\n" ); return; } /******************************************************************************/ void Getcom() /******************************************************************************/ /* GETCOM reads the next command from the user. */ { short i; char cx; Putout("Command? (Type H for help):"); for(i=0;((cx=getchar()) != '\n'); i++) command[i]=toupper(cx); Putinp(); return; } /******************************************************************************/ void Getlda(char *str) /******************************************************************************/ /* GETLDA gets a new value of LDA from the user. */ { char outline[80]; int temp; CHRCTI(str,&temp); if (str == NULL) Putout("I did not understand your definition of LDA.\n"); if(temp < 0) { Putout("The assignment of LDA was not acceptable!\n"); Putout("LDA must be positive.\n"); } else if (temp > LENA) { Putout("The assignment of LDA was not acceptable!\n"); sprintf(outline,"LDA must be no greater than %d.\n",LENA); Putout(outline); } else { lda=temp; sprintf(outline,"LDA has been set to %d.\n",lda); Putout(outline); } if (lda < n) { n=lda; Putout("\nNote: Since the value of N must always be no greater\n"); Putout("than LDA, MATMUL has just decreased the value of N.\n"); sprintf(outline,"N has been set to %d\n",n); Putout(outline); } return; } /******************************************************************************/ void Getn ( char *str ) /******************************************************************************/ /* GETN reads a new value of N from the user. */ { char outline[80]; char s[80]; int temp; int i; int j; int l; int mult; if ( !str[0] ) { Putout("I could not understand your definition of N.\n"); return; } l=strlen(str); memset(s,'\0',l); /* Get first number */ for(i=0;( (i LENA) { Putout("The value of N that you chose is not acceptable!\n"); sprintf(outline,"N must be no greater than %d\n",LENA); Putout(outline); } else { n=temp; nlo=temp; nhi=temp; sprintf(outline,"N has been set to %d\n",n); Putout(outline); } /* Read second number */ /* if (str[i] == NULL) */ if ( !str[i] ) return; i++; for(j=0;((i LENA) { Putout("The value of NHI that you chose is not acceptable!\n"); sprintf(outline,"NHI must be no greater than %d\n",LENA); Putout(outline); } else { nhi=temp; sprintf(outline,"NHI has been set to %d\n",nhi); Putout(outline); ninc=1; } /* Check for multipy */ i++; if (str[i] == '*') { mult=TRUE; i++; } else mult=FALSE; /* Get third and last number */ if ( !str[i] ) return; for(j=0;((i nhi) && (ninc > 1)) ninc*=-1; sprintf(outline,"NINC has been set to %d\n",ninc); Putout(outline); } else { ninc=0; nmult=temp; sprintf(outline,"NMULT has been set to %d\n",nmult); Putout(outline); } return; } /******************************************************************************/ void Getord(char *str, int *error) /******************************************************************************/ /* GETORD reads a new value of ORDER from the user. */ { char ctemp[10],outline[80]; strncpy(ctemp,str,10); if ( (strncmp(ctemp,"ALL",3)!=0) && (strncmp(ctemp,"IJK",3)!=0) && (strncmp(ctemp,"IKJ",3)!=0) && (strncmp(ctemp,"JIK",3)!=0) && (strncmp(ctemp,"JKI",3)!=0) && (strncmp(ctemp,"KIJ",3)!=0) && (strncmp(ctemp,"KJI",3)!=0) && (strncmp(ctemp,"R8_IJK",6)!=0) && (strncmp(ctemp,"UIJK",4)!=0) && (strncmp(ctemp,"IUJK",4)!=0) && (strncmp(ctemp,"IJUK",4)!=0) && (strncmp(ctemp,"PIJKA",5)!=0) && (strncmp(ctemp,"PIJKP",5)!=0) && (strncmp(ctemp,"SDOT",4)!=0) && (strncmp(ctemp,"TAXPYC",6)!=0) && (strncmp(ctemp,"TAXPYR",6)!=0) && (strncmp(ctemp,"SAXPYC",6)!=0) && (strncmp(ctemp,"IIJK",4)!=0) && (strncmp(ctemp,"TDOT",4)!=0) && (strncmp(ctemp,"SAXPYR",6)!=0) && (strncmp(ctemp,"SGEMM",5)!=0) && (strncmp(ctemp,"SGEMMS",6)!=0) && (strncmp(ctemp,"MIJK",4)!=0) &&(strncmp(ctemp,"NIJK",4)!=0) && (strncmp(ctemp,"SIJK",4)!=0) &&(strncmp(ctemp,"MXMA",4)!=0)) { Putout("The order you chose was not a valid choice.\n"); Putout("\nYour command was not carried out.\n"); *error=1; } else { sprintf(outline,"ORDER has been set to %s\n",ctemp); Putout(outline); strcpy(order,ctemp); } return; } /******************************************************************************/ void Getsho(char *str,int lval) /******************************************************************************/ /* GETSHO gets information from the user about what is to be printed out as results after a multiplication is carried out. */ { if ((strncmp(str,"ALL",3) == 0) || (strncmp(str,"all",3) == 0)) mshow=langshow=ashow=cshow=fshow=lshow=nshow=noshow=tshow=lval; else if ((strncmp(str,"MACHINE",7) == 0) || (strncmp(str,"machine",7) == 0)) mshow=lval; else if ((strncmp(str,"LANGUAGE",8) == 0) || (strncmp(str,"language",8) == 0)) langshow=lval; else if ((strncmp(str,"A(N,N)",6) == 0) || (strncmp(str,"a(n,n)",6) == 0)) ashow=lval; else if ((strncmp(str,"ORDER",5) == 0) || (strncmp(str,"order",5) == 0)) cshow=lval; else if ((strncmp(str,"MFLOPS",6) == 0) || (strncmp(str,"mflops",6) == 0)) fshow=lval; else if ((strncmp(str,"LDA",3) == 0) || (strncmp(str,"lda",3) == 0)) lshow=lval; else if ((str[0]=='N') || (str[0]=='n')) nshow=lval; else if ((strncmp(str,"OPS",3) == 0) || (strncmp(str,"ops",3) == 0)) noshow=lval; else if ((strncmp(str,"TIME",4) == 0) || (strncmp(str,"time",4) == 0)) tshow=lval; else { Putout("That is not a legal name! \n"); Putout("Legal names are ORDER, LDA, N, TIME, OPS, LANGUAGE, MACHINE, MFLOPS and A(N,N).\n"); } return; } /******************************************************************************/ void Help() /******************************************************************************/ /* HELP prints a list of the available commands. */ { Putout("This is the list of legal commands.\n"); if(ifilee) Putout("E Explain what this program does.\n"); Putout("H Help. List the legal commands.\n"); Putout("LDA=value Assigns the leading dimension of arrays.\n"); Putout("M Multiply two matrices.\n"); Putout("N=value Assigns the size of the arrays.\n"); Putout("ORDER=name Chooses the algorithm for multiplication.\n"); Putout("P Prints out current values and results.\n"); Putout("Q Quit.\n"); Putout("NOSHOW=name Value of NAME should not be included in output.\n"); Putout(" NAME=ORDER, LDA, N, TIME, OPS or MFLOPS\n"); Putout("SHOW=name Value of NAME should be included in output.\n"); Putout(" NAME=ORDER, LDA, N, TIME, OPS or MFLOPS\n\n"); return; } /*****************************************************************************/ void r8_ijk ( ) /*****************************************************************************/ /* Purose: R8_IJK uses R8 arithmetic and IJK order. */ { double da[LENA][LENA]; double db[LENA][LENA]; double dc[LENA][LENA]; int i; int j; int k; for ( i = 0; i < n; i++ ) { for ( j = 0; j < n; j++ ) { da[i][j] = 0.0; db[i][j] = 1.0; dc[i][j] = 1.0; } } sec1 = cpu_time ( ); for ( i = 0; i < n; i++ ) { for ( j = 0; j < n; j++ ) { for ( k = 0; k < n; k++ ) { da[i][k] = da[i][k] + db[i][j] * dc[j][k]; } } } sec2 = cpu_time ( ); a[n-1][n-1] = ( float ) da[n-1][n-1]; return; } void NIJK() /****************************************************************************** NIJK multiplies A=B*C using index order IJK with integers instead of floating point numbers. ******************************************************************************/ { int i,j,k; long ia[LENA][LENA]; long ib[LENA][LENA],ic[LENA][LENA]; for(i=0;i 0)) || ((nlo > nhi) && (ninc < 0)) ) { n+=ninc; ido=1; if ( ((n < nhi) && (nhi <= nlo)) || ((n > nhi) && (nhi >= nlo)) ) { ido=0; n=nlo; } } else ido=2; return(ido); } if (nmult > 1) { if ( nlo < nhi) { n= n*nmult; ido=1; if ( ((n < nhi) && (nhi <= nlo)) || ((n > nhi) && (nhi >= nlo)) ) { ido=0; n=nlo; } } else ido = 2; return(ido); } ido=3; return(ido); } /******************************************************************************/ void Pdump() /******************************************************************************/ /* PDUMP writes the timing results to a data file. */ { int i; if(iplot >0 ) { ifiled=fopen(filed,"w"); if(ifiled) for(i=1;i<=iplot;i++) fprintf(ifiled,"%-5s %-3d %-3d %-9.6f %-11d %-9.6f %-6.3f\n", cplot[i],lplot[i],nplot[i],tplot[i],noplot[i],fplot[i],aplot[i]); } else ifiled=NULL; return; } /******************************************************************************/ void Printr() /******************************************************************************/ /* PRINTR prints out the current values of parameters that the user should be interested in, including: the algorithm, the leading dimension, the maximum allowable dimension, the actual size of arrays, the number of multiplications carried out. */ { char outline[80]; sprintf(outline,"The algorithm chosen is %s\n",order); Putout(outline); sprintf(outline,"The leading dimension of arrays, LDA, is %d\n",lda); Putout(outline); sprintf(outline,"The maximum legal choice for LDA is %d\n",LENA); Putout(outline); sprintf(outline,"The actual size of the arrays, N, is %d\n",n); Putout(outline); sprintf(outline,"A total of %d cases have been run.\n",iplot); Putout(outline); return; } void Putinp() /****************************************************************************** PUTINP prints the user's most recent input line to the command file and to the output file. ******************************************************************************/ { size_t i; i=strlen(command); if (i) { if (ifilei) fprintf(ifilei,"%s\n",command); if (ifileo) fprintf(ifileo,"%s\n",command); } else { fprintf(ifilei," \n"); fprintf(ifilei," \n"); } return; } void Putout ( char *outstr ) /****************************************************************************** PUTOUT prints a line of output to the user's screen, and to the output file. ******************************************************************************/ { size_t i; i=strlen(outstr); if (i) { printf("%s",outstr); if (ifileo) fprintf(ifileo,"%s",outstr); } else { printf("\n"); if (ifileo) fprintf(ifileo,"\n"); } return; } void Record() /****************************************************************************** RECORD stores the results for the latest multiplication into various arrays. ******************************************************************************/ { if(iplot < MAXPLT) { iplot++; aplot[iplot]=a[n-1][n-1]; strcpy(cplot[iplot],order); lplot[iplot]=lda; nplot[iplot]=n; #if MACHINE == VAX_VMS tot_seconds=sec2-sec1; tplot[iplot]=(float)tot_seconds/100.0; #elif ((MACHINE == IBM_PC) || (MACHINE == IBM_RS6)) tot_seconds=sec2-sec1; tplot[iplot]=(float)tot_seconds/CLOCKS_PER_SEC; #elif MACHINE == CRAY tot_seconds=sec2-sec1; tplot[iplot]=(float)tot_seconds*0.000000006; #else tot_seconds=sec2-sec1; tot_microseconds=micro2-micro1; tot_microseconds=tot_microseconds+(tot_seconds*1000000); tplot[iplot]=(float)((tot_microseconds/1000000.0)); #endif if(tplot[iplot] == 0.0)tplot[iplot]=1.0; noplot[iplot]=2*n*n*n; fplot[iplot]=0.000001 * (float)((float)noplot[iplot]/tplot[iplot]); } else { Putout("There is no more room to record results.\n"); Putout("This is not a serious error, but it does mean\n"); Putout("and any further results will not make it into\n"); Putout("the results file.\n"); } return; } void Result ( short lchop ) /****************************************************************************** RESULT prints out the results of all, or some, of the multiplications. ******************************************************************************/ { char out[81]; int i; if ( ilo <= ihi ) { /* Prepare the header string. Then chop out items that are not being shown. It's important to do this chopping in reverse order! */ memset(out,'\0',80); sprintf(out," %-8s %3s %3s %10s %8s %10s %8s %-12s %8s\n","ORDER","LDA","N","Time","Ops","MFLOPS","A(N,N)","MACHINE","LANGUAGE"); if (lchop) { if (!langshow) chop(out,70,78); if (!mshow) chop(out,57,69); if (!ashow) chop(out,48,56); if (!fshow) chop(out,37,47); if (!noshow) chop(out,28,36); if (!tshow) chop(out,17,27); if (!nshow) chop(out,13,16); if (!lshow) chop(out,9,12); if (!cshow) chop(out,0,8); Putout(out); } memset(out,'\0',80); /* Print out the values requested. */ for ( i = ilo; i <= min ( ihi, iplot ); i++ ) { if ( lplot[i] ) { if ( cshow ) { printf ( " %-8s", cplot[i] ); } if ( lshow ) { printf ( " %3d", lplot[i] ); } if ( nshow ) { printf ( " %3d", nplot[i] ); } if ( tshow ) { printf ( " %10.6f", tplot[i] ); } if ( noshow ) { printf ( " %8d", noplot[i] ); } if ( fshow ) { printf ( " %10.6f", fplot[i] ); } if ( ashow ) { printf ( " %8.3f", aplot[i] ); } if ( mshow ) { printf ( " %s", machine[MACHINE] ); } printf ( " C language\n" ); } /* sprintf ( out," %-8s %3d %3d %10.6f %8d %10.6f %8.3f %-23s %8s\n", cplot[i], lplot[i], nplot[i], tplot[i], noplot[i], fplot[i], aplot[i], machine[MACHINE], "C "); if (lchop) { if (!langshow) chop(out,70,78); if (!mshow) chop(out,57,69); if (!ashow) chop(out,48,56); if (!fshow) chop(out,37,47); if (!noshow) chop(out,28,36); if (!tshow) chop(out,17,27); if (!nshow) chop(out,13,16); if (!lshow) chop(out,9,12); if (!cshow) chop(out,0,8); } if (lplot[i] != 0) Putout(out); */ } } return; } float tdot ( int n, float *sx, int incx, float *sy, int incy ) /****************************************************************************** the C code for the TDOT routine ******************************************************************************/ /* PURPOSE Forms the dot product of a vector. INPUT n Number of elements to sum. sx Address of first element of x vector. incx Incrament for the x vector. sy Address of first element of y vector. incy incrament for the y vector. OUPUT sdot Dot product x and y. float returned due to `C' language features. */ { int i; float stemp=0.0e0; if( n<1 ) return( stemp ); if( incx == incy ) { if( incx == 1 ) { /* Both increments = 1 */ for( i=0; i0 ) { /* Equal, positive, non-unit increments. */ for( i=0; i0 ) { /* Equal, positive, non-unit increments. */ for(i=0; i