INTEGER*4 FUNCTION GENHSH(KEY,KLNGTH,IMOD) C** C** C** MODULE NAME: GENHSH C** C** AUTHOR: D. EDWARDS C** C** DATE: AUGUST 1978 C** C** C** MODULE FUNCTION: GENERALIZED HASHING FUNCTION RETURNS LOGICAL C** BLOCK ADDRESS IN HASH TABLE FROM PASSED C** ASCII KEY C** C** CALLING SEQUENCE: BA=GENHSH(ARG1,ARG2,ARG3) C** C** ARG1 = VARIABLE LENGTH ASCII KEY (BYTE ARRAY) C** C** ARG2 = LENGTH OF KEY C** C** ARG3 = NUMBER OF BLOCKS IN HASH TABLE C** C** C****************************************************************************** C** THE INCOMING ASCII KEY IS PROCESSED IN THE FOLLOWING WAYS C** C****************************************************************************** C** C** SECTION ONE TRANSFORMS ANY VALID ASCII CHARACTER INTO A NUMERIC C** EQUIVALENT. KEY CHARACTERS ALREADY CONTAINING NUMERIC ASCII CHARACTERS C** REMAIN THE SAME. ALL OTHER CHARACTERS (A-Z,SYMBOLS #@ ETC) ARE TRANSFORMED C** INTO A TWO BYTE NUMERIC EQUIVALENT."A" TRANSFORMS INTO "10", "B" INTO "11" C** ETC. "A"-"Z" MAP INTO 10-35. THE REMAINING VALID CHARACTERS BETWEEN OCTAL C** 040 AND 140 ASCII CHARACTERS (SUCH AS !/< ETC) MAP INTO 36-64. ANY C** OTHER CHARACTERS ENCOUNTERED THAT ARE NOT BETWEEN 040 AND 140 (OCTAL) C** MAP INTO "65". THIS INSURES THAT ALL NON-NUMERIC CHARACTERS WILL BE C** TRANSFORMED INTO NUMERICS. THE TRANSFORMED KEY MAY BE LONGER THAN C** THE ORIGINAL KEY BECAUSE EACH NON-NUMERIC KEY IS EXPLODED INTO A C** TWO BYTE NUMERIC KEY. C** EG: "5"------>"5" C** "G"------>"16" C** " "------>"36" C** "123ABC !"------>"1231011123637" C** TYPICAL STOCK CODE KEY "123A5678" WOULD RESULT IN A 'EXPLODED' KEY OF C** "123105678" C** C****************************************************************************** C** C** SECTION TWO COMPUTES THE NUMBER OF 9 BYTE 'WORDS' THE 'EXPLODED' KEY C** CONTAINS. THE REASON FOR THIS BECOMES APPARENT LATER! C** C****************************************************************************** C** C** SECTION THREE DIVIDES THE EXPLODED KEY INTO 9 BYTE WORDS C** IE: A 10 BYTE EXPLODED KEY CONTAINS 2 'WORDS',ONE WORD CONTAINS C** 1 BYTE ,THE SECOND WORD 9. FROM EACH WORD (CONTAINING UP TO 9 ASCII C** NUMERIC BYTES) AN DOUBLE PRECISION INTEGER EQUIVALENT IS COMPUTED. C** THE REASON FOR DIVIDING THE KEY INTO 9 BYTE 'WORDS' IS THAT EACH C** I*4 EQUIVALENT CAN CONTAIN NO MORE THAN 9 COMPLETE DIGITS C** C****************************************************************************** C** C** SECTION 4 PERFORMS THE RANDOMIZING ON THE I*4 NUMBER C** THE METHOD USED HERE IS THE /9/8/7/6/9/8/7/6 REMAINDER METHOD WHERE C** THE NUMBER IS DIVIDED BY 9 ,THE REMAINDER PLACED IN THE MOST SIGN- C** NIFICANT DIGIT AND THE LEAST THROWN AWAY. THE PROCESS IS REPEATED C** ON THE RESULTANT NUMBER USING 8,THEN 7,THEN 6,THEN 9,ETC UNTIL THE C** THE NUMBER OF DIVISIONS EQUALS THE NUMBER OF DIGITS IN THE WORD (NORMAL- C** LY 9). IF THE I*4 WORD HAS ONLY 5 DIGITS THEN IT WILL BE DIVIDED BY C** 9, THEN 8,THEN 7,THEN 6,THEN 9, ;THE REMAINDER OF EACH DIVISION BECOMING C** THE MOST SIGNIFICANT DIGIT OF THE NUMBER AND THE REST OF THE NUMBER C** SHIFTED DOWN BY ONE DIGIT. THE LEAST SIGNIFICANT IS THROWN AWAY. C** C****************************************************************************** C** C** SECTION 5 GENERATES THE RANDOM NUMBER(BLOCK ADDRESS) BY: C** GENHSH=MODULUS((MODULUS(I*4WORD#1,IMOD)+MODULUS(I*4WORD#2,IMOD)+..)+1 C** C INCLUDE 'COMMON.FTN/NOLIST' INCLUDE 'COMEQUIV.FTN/NOLIST' BYTE KEY(1) !CONTAINS PASSED IN ASCII KEY (VARIABLE LENGTH) INTEGER KLNGTH !KEY LENGTH INTEGER*4 IMOD !FILE SIZE IN SECTORS BYTE EXPLO(70) !EXPLODED (ALL NUMERIC) KEY INTEGER ELNGTH !LENGTH OF EXPLODED KEY INTEGER*4 KK INTEGER*4 WORDS !# OF 9 BYTE WORDS INTEGER*4 KL !# OF DIGITS IN EACH 'WORD',ALWAYS 9 EXCEPT 1ST C !DIGIT WHICH CAN BE BETWEEN 1 AND 9 INTEGER*4 CKD !REMAINDER OF 9/8/7/6 IS PLACED IN HIGHEST C !SIGNIFICANT DIGIT INTEGER*4 DPREC(8) !CONTAINS I*4 EQUIVALENT OF 'EXPLO' INTEGER*4 LNG(8) !=KL FOR EACH 'WORD' INTEGER*4 TMOD !CONTAINS SUM OF MODULUSES FOR EACH 'WORD' EQUIVALENCE (DPREC ,DBHFIL(60)) EQUIVALENCE (CKD ,DBHFIL(76)) EQUIVALENCE (EXPLO ,DBHFIL(78)) EQUIVALENCE (ELNGTH,DBHFIL(113)) C C********** SECTION ONE ***************************************************** C ELNGTH=0 DO 190 I=1,KLNGTH ! DO TRANSFORMATION PROCESS FOR EACH BYTE OF THE C ! KEY 20 DO 50 K=1,65 ! COMPARE KEY TO ASCII CHARACTERS "040->"140 IF (KEY(I).EQ."037+K) GO TO 100 ! EXIT LOOP WHEN MATCH MADE 50 CONTINUE IF (KEY(I).EQ.0)GO TO 140 CALL CHRCVT(KEY(I)) GO TO 20 100 IF (K.GT.16) GO TO 110 K=K+35 ! ASCII "040 ( )-"057 (/); TRANSFORM K=>36-51 GO TO 180 C 110 IF (K.GT.26) GO TO 120 ELNGTH=ELNGTH+1 ! NUMERIC KEY BYTE; NO TRANSFORMATION REQUIRED EXPLO(ELNGTH)=KEY(I) ! PUT KEY BYTE DIRECTLY INTO EXPLODED KEY GO TO 190 120 IF (K.GT.33) GO TO 130 K=K+25 ! ASCII "072 (:)-"100 (@); TRANSFORM K=>52-58 GO TO 180 C 130 IF (K.GT.59) GO TO 140 K=K-24 ! ALPHABETIC KEY BYTE ; TRANSFORM K=>10-35 GO TO 180 140 K=K-1 ! ASCII "134 ([) OR GREATER; TRANSFORM K=>59-65 C 180 ELNGTH=ELNGTH+1 EXPLO(ELNGTH)=(K/10)+"060 ! PLACE HIGHER ORDER DIGIT OF "K" IN ! 'EXPLO' (IN OCTAL) ELNGTH=ELNGTH+1 EXPLO(ELNGTH)=(K-(K/10)*10)+"060 ! PLACE LOWER ORDER DIGIT OF 'K' ! IN 'EXPLO' (IN OCTAL) C 190 CONTINUE C C********** SECTION TWO ***************************************************** C C FIND OUT HOW MANY 9 BYTE WORDS ARE REQUIRED TO COMPLETELY CONTAIN C THE EXPLODED KEY 'EXPLO' C DO 210 WORDS=1,8 DPREC(WORDS)=0 IF (ELNGTH.LE.WORDS*9) GO TO 300 210 CONTINUE C C********** SECTION THREE *************************************************** C 300 DO 360 I=WORDS,1,-1 KL=9 FKL=ELNGTH-(WORDS-1)*9 ! = THE NUMBER OF DIGITS IN THE FIRST WORD C ! 'WORD(1)'. (1-9) IF (I.EQ.1) KL=FKL DO 350 KK=KL,1,-1 ! KEEP TRACK OF WHICH BYTE IN WHICH C ! 'WORD' IN 'EXPLO' IS BEING CONSIDERED IF (I.EQ.1) N=KK IF (I.EQ.2) N=KK+FKL IF (I.GT.2) N=KK+FKL+(I-2)*9 DO 310 L=1,10 IF (EXPLO(N).EQ.L+"057) GO TO 330 ! EXIT LOOP WHEN C ! ASCII NUMBER IN 'EXPLO' IS DETERMINED 310 CONTINUE 330 CONTINUE C DPREC(I)=(L-1)*10**(KL-KK)+DPREC(I) ! TRANSFORMS ASCII C ! 'WORDS' INTO I*4 NUMBERS 350 CONTINUE LNG(I)=KL ! STORE HOW MANY DIGITS ARE IN EACH 'WORD' 360 CONTINUE C C********** SECTION FOUR **************************************************** C C DIVIDE I*4 'WORDS' BY 'DIV', PUT REMAINDER IN HIGHEST DIGIT LOCATION C , AFTER SHIFTING DIGITS DOWN BY ONE (LOWEST IS THROWN AWAY). CHANGE C 'DIV'AND REPEAT DIVIDING UNTIL THERE HAVE BEEN AS MANY DIVISIONS AS C THERE ARE DIGITS. 'DIV" SEQUENCES THROUGH 9-8-7-6-9-8 ETC C DO 440 I=1,WORDS DIV=9 DO 410 J=1,LNG(I) ! REPEAT DIVIDING PROCESS FOR ALL I*4 'WORDS' CKD=DPREC(I)-(DPREC(I)/DIV)*DIV ! COMPUTE REMAINDER DPREC(I)=DPREC(I)/10+CKD*10**(LNG(I)-1) ! SHIFT DOWN ONE DIGIT AND C ! PUT REMAINDER IN HIGHEST DIGIT DIV=DIV-1 IF (DIV.LT.6) DIV=9 ! DIV CHANGES BETWEEN 9-8-7-6-9 ETC 410 CONTINUE 440 CONTINUE C C********** SECTION FIVE **************************************************** C TMOD = 0 C DO 500 I=1,WORDS ! COMPUTE MODULUS FOR EACH 'WORD' TMOD=TMOD+DPREC(I)-(DPREC(I)/IMOD)*IMOD ! AND SUM THEM ALL UP 500 CONTINUE C GENHSH=TMOD-(TMOD/IMOD)*IMOD+1 ! COMPUTE MODULUS OF THE SUM OF ALL C ! THE MODULUSES C RETURN END