Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!samsung!dali.cs.montana.edu!milton!whit From: whit@milton.u.washington.edu (John Whitmore) Newsgroups: comp.lang.fortran Subject: Re: rounding a real to a whole number Summary: find good 'even' number given a range Message-ID: <10869@milton.u.washington.edu> Date: 9 Nov 90 10:34:17 GMT References: Organization: University of Washington, Seattle Lines: 123 In article u714092@eagle.larc.nasa.gov (prichard devon ) writes: > >what I want to do is to have a subroutine which, given a range of real >numbers, for example -123.445 -> 1033.02 , and choose whole numbers >outside that range. obviously the first application is axis values for >x-y plots. I had the same problem. I don't like my solution, but... I treated the axis endpoint as a range (obviously it has to include the lowest data value, but no more than 20% of the range of the plot should be empty.) Then I took the axis endpoint and separated it into mantissa_MSD, mantissa_LSD, and exponent. 'MSD' is for 'most significant digits', and 'LSD' for 'least significant digits.' With the entirety of the value of the number in 'mantissa_LSD', and 'mantissa_MSD'= 0, one tests to see if the 'mantissa_MSD' and exponent are sufficient (i.e. if that number is in the determined range). Every time the test fails, one takes one more digit from 'mantissa_LSD' and appends it to 'mantissa_MSD'. Eventually one comes up with some sort of success; the successful number will be 'mantissa_MSD' or mantissa_MSD +/-1 times 'exponent'; one discards the remaining digits. Additionally, one can build in a preference for even numbers by simply adding to a table of the variations added to 'mantissa_MSD' the values 0.2, 0.4, 0.6, 0.8. Code follows (skip if you're not interested). SUBROUTINE BESCL9(X1IN,X2IN,RESULT,NTRIAL) C C THIS SUBROUTINE FINDS THE MOST ROUNDED NUMBER IT CAN, IN C THE RANGE X TO XLIMIT, RETURNING THE ROUNDEST NUMBER IN C RESULT. THE 'ROUNDNESS' CRITERION IS: FEWEST NONZERO DIGITS, C WITH PREFERENCE FOR LAST NONZERO DIGIT '5', OR ANY EVEN DIGIT. C C X1IN, X2IN ARE REAL VARIABLES, INPUT, WHICH DELIMIT C THE RANGE IN WHICH A NUMBER IS TO BE FOUND C RESULT REAL, OUTPUT, IS THE ROUND NUMBER RESULT C NTRIAL INTEGER, OUTPUT, INDICATES THE NUMBER OF FRUITLESS ATTEMPTS C ATTEMPTS MADE TO MAKE THE NUMBER; MAY BE USEFUL IN C QUANTIFYING THE DEGREE OF ROUNDING ATTAINED C C PREFERRED DIGITS ARE TABULATED IN ARRAY "BESTUN" PARAMETER(NB=7) REAL BESTUN(NB) DATA BESTUN/ 0., 1., .5, .2, .4, .6, .8 / C DATA TEN,ONE,TENTH/10., 1., .1/ C NTRIAL=0 IF(X1IN .EQ. X2IN) THEN C C NO ROUNDING POSSIBLE OR REQUIRED RESULT=X1IN GO TO 5 ELSE IF( X1IN .LT. 0. .EQV. X2IN .GT. 0.) THEN C C ZERO IS A ROUND NUMBER RESULT=0. GO TO 5 ELSE IF(X1IN .GT. X2IN .EQV. X1IN .GT. 0.) THEN C C SEARCH 'UPWARD' FROM X1IN X=X2IN XLIMIT= X1IN ELSE C C SEARCH 'UPWARD' FROM X2IN X=X1IN XLIMIT=X2IN ENDIF C C THE TRIPLE (P1,P2,P3) HOLDS THE TRIAL X ELEMENTS AS: C P1= MANTISSA'S LEAST SIGNIFICANT DIGITS C P2= POWER OF TEN, FACTORED FROM THE MANTISSA, WITH SIGN OF X C P3= MOST SIGNIFICANT DIGITS OF MANTISSA, WHICH ARE C HOPELESS TO TRY TO DO WITHOUT C P1=ABS(X) P2=SIGN(ONE,X) P3=0. C C MULTIPLY OR DIVIDE P2 BY POWER OF TEN TO PUT C P1 INTO THE INTERVAL (.1,1.] C 1 CONTINUE IF(P1 .LT. TENTH) THEN P1=P1*TEN P2=P2*TENTH GO TO 1 ENDIF 11 CONTINUE IF(P1 .GT. ONE) THEN P1=P1*TENTH P2=P2*TEN GO TO 11 ENDIF 2 CONTINUE C C NOW TEST FOR ADEQUATE NEARNESS TO BEST NUMBERS C IF FIND LIKELY VALUE IN TABLE, WILL USE TABLE VALUE C AS A ROUNDING APPROXIMATION TO P1 XLESS= MIN(X1IN,X2IN) XGRTR= MAX(X1IN,X2IN) DO 3 N=1,NB NTRIAL = NTRIAL + 1 RESULT= (BESTUN(N)+P3) *P2 3 IF( XLESS .LE. RESULT .AND. XGRTR .GE. RESULT) GO TO 5 C C THE SEARCH WAS FRUITLESS; PUSH DIGITS TO P3 AND TRY AGAIN C A= AINT(P1*TEN) P1= P1*TEN-A P2= P2*TENTH P3= P3*TEN+A GO TO 2 C 5 RETURN END John Whitmore Whit@milton.u.washington.edu