Very nice utilization of proc fcmp for this problem. By simplifying the rules to fit the question more closely, i.e. we know the digits can only be 1,2,3,4,5 we can cut the runtime to nearly instant. /* instead of 217 possibilities I only have 9 valid perfect squares to choose from */ data one; array sd[5]; do i=100 to 236; v=i**2; do d=1 to dim(sd); sd =substrn(v,d,1); end; if max(of sd1-sd5)<=5 and min(of sd1-sd5)>0 then output; end; keep v; run; proc fcmp outlib=work.func.quiz; /* returns > 1000 if any condition is not met */ function usedOnceDigit(v1, v2, v3); length v $15 nDigits usedOnceDigit nUsedOnceDigits i j 8 c $1; /* I only need to perform from 1 to 5 instead of 0 to 9 */ array freq[5] (0 0 0 0 0); v = cat(v1, v2, v3); nDigits = 0; usedOnceDigit = .; nUsedOnceDigits = 0; do i = 1 to 5; c = substr("12345", i, 1); freq = 15 - length(compress(v, c)); if freq > 0 then do; if i = freq then return(1005); if freq > 5 then return(1004); if index(v, substr("12345", freq, 1)) = 0 then return(1004); nDigits + 1; if nDigits > 5 then return(1002); do j = 1 to i-1; if freq > 0 and freq = freq then return(1003); end; if freq = 1 then do; usedOnceDigit = i; nUsedOnceDigits + 1; end; end; end; if nDigits < 5 then return(1002); if nUsedOnceDigits ^= 1 then return(1006); return(usedOnceDigit); endsub; quit; %let cmplib = %sysfunc(getoption(cmplib)); options cmplib = (work.func &cmplib); proc sql; select "answer is: ", v1, v2, v3 from ( select o1.v as v1, o2.v as v2, o3.v as v3 , usedOnceDigit(o1.v, o2.v, o3.v) as usedOnce from one as o1, one as o2, one as o3 where o1.v < o2.v and o2.v < o3.v and calculated usedOnce < 1000 ) group by usedOnce having count(*) = 1; quit; options cmplib=(&cmplib); Very nice program. Here were the run stats from my machine (64-bit linux): real time 0.02 seconds cpu time 0.01 seconds
... View more