PROGRAM !About the Clarion language: !http://softvelocity.com !The language converts numbers to string and back !Arrays are 1 based, I'm using Array[n+1] to compensate for this !Strings are implicit arrays of string(1) MAP LoopString PROCEDURE(long pFirst,long pLast,long pZeros, *long[] pDigits) LoopModulus PROCEDURE(long pFirst,long pLast,long pZeros, *long[] pDigits) LoopPowersOfTen PROCEDURE(long pFirst,long pLast,long pZeros, *long[] pDigits) BenchMark PROCEDURE(LoopString pDigitCount,*string pStringResult) END LoopStringResult STRING(600) LoopModulusResult STRING(600) LoopPowersOfTenResult STRING(600) Window WINDOW('Count digits benchmark'),AT(,,473,112),FONT('Tahoma',8,,FONT:regular),GRAY BUTTON('Loop Strings'),AT(4,6,41,26),USE(?loopstrings),LEFT,ICON(ICON:None) BUTTON('Loop Modulus'),AT(4,42,41,26),USE(?loopmodulus),LEFT,ICON(ICON:None) BUTTON('Loop Powers of Ten'),AT(4,78,41,26),USE(?looppowersoften),LEFT,ICON(ICON:None) TEXT,AT(48,4,420,30),USE(LoopStringResult),SKIP,BOXED,FLAT,FONT('Lucida Console',7,,,CHARSET:ANSI), | READONLY TEXT,AT(48,40,420,30),USE(LoopModulusResult),SKIP,BOXED,FLAT,FONT('Lucida Console',7,,,CHARSET:ANSI), | READONLY TEXT,AT(48,76,420,30),USE(LoopPowersOfTenResult),SKIP,BOXED,FLAT,FONT('Lucida Console',7,,,CHARSET:ANSI), | READONLY END CODE OPEN(Window) ACCEPT CASE ACCEPTED() OF ?loopstrings Benchmark(LoopString,LoopStringResult) OF ?loopmodulus Benchmark(LoopModulus,LoopModulusResult) OF ?looppowersoften Benchmark(LoopPowersOfTen,LoopPowersOfTenResult) END END LoopString PROCEDURE(long pFirst,long pLast,long pZeros, *long[] pDigits) I LONG D LONG String &STRING CODE String &= NEW(STRING(LEN(pLast))) CLEAR(pDigits[]) LOOP I = pFirst TO pLast IF pZeros String = RIGHT(ALL('0',SIZE(String))&I,SIZE(String)) !Add leading zeros ELSE String = I END LOOP D = 1 TO SIZE(String) IF String[D] = ' ' THEN BREAK. pDigits[ String[D]+1 ] += 1 END END DISPOSE(String) LoopModulus PROCEDURE(long pFirst,long pLast,long pZeros, *long[] pDigits) I LONG Number LONG Size LONG UsedDigits LONG CODE Size = LEN(pLast) CLEAR(pDigits[]) LOOP I = pFirst TO pLast UsedDigits = 0 Number = I LOOP Size TIMES pDigits [ (Number % 10) + 1 ] += 1 UsedDigits += 1 Number /= 10 IF Number = 0 THEN BREAK. END IF pZeros AND UsedDigits < Size !If number is shorter than last, include enough leading zeros pDigits[0+1] += Size - UsedDigits END END LoopPowersOfTen PROCEDURE(long pFirst,long pLast,long pZeros, *long[] pDigits) MAP EndingZeros PROCEDURE(long pNumber),LONG DigitsPower PROCEDURE(long pPower,long pPrefix, *long[] pDigits1) DigitsOneNumber PROCEDURE(long pNumber,*long[] pDigitsN,long pMultiplier) END I LONG First LONG Last LONG Prefix &STRING Power LONG Nines LONG CODE Prefix &= NEW(STRING(LEN(pLast))) IF pZeros First ='1'&RIGHT(ALL('0',LEN(pLast))&pFirst,LEN(pLast)) !If 1 to 999, compute 1001 to 1999 to Last = '1'&pLast !include leading zeros ELSE First = pFirst Last = pLast END CLEAR(pDigits[]) LOOP I = First TO Last DigitsOneNumber(I,pDigits,1) !Count digits using % 10 Power = EndingZeros(I) !Does it end in 000? IF Power Nines = ALL('9',Power) !Nines = 999 IF I+Nines <= Last !Does a full set fit? Prefix = LEFT(I,LEN(I)-Power) !Extract digits before 000 DigitsPower(Power,Prefix,pDigits) !Add a set of 1 to 999 I += Nines !Jump 999 cycles ahead END END END IF pZeros pDigits[1+1] -= pLast - pFirst + 1 !1001 to 1999 was computed, substract 999 Ones END DISPOSE(Prefix) EndingZeros PROCEDURE(long pNumber)!,LONG String &STRING Zeros LONG J LONG CODE !Loop number from right to left, counting consecutive zeros Zeros = 0 String &= NEW(STRING(LEN(pNumber))) String = pNumber LOOP J = SIZE(String) TO 1 BY - 1 IF String[J] <> '0' THEN BREAK. Zeros += 1 END DISPOSE(String) RETURN Zeros DigitsPower PROCEDURE(long pPower,long pPrefix, *long[] pDigitsP) J LONG CODE !If ending in 000, compute 1 - 999, adding 3 * 10^(3-1) = 300 to all digits LOOP J = 0 TO 9 pDigitsP[J+1] += pPower * (10 ^ (pPower-1)) END pDigitsP[0+1] -= pPower !Substract 1 from Zeros DigitsOneNumber(pPrefix,pDigitsP,ALL('9',pPower)) !and add the count for the digits before 000 multplied by 999 DigitsOneNumber PROCEDURE(long pNumber,*long[] pDigitsN,long pCount) CODE !Count digits in the number using % 10 LOOP LEN(pNumber) TIMES pDigitsN[ (pNumber % 10) + 1 ] += pCount pNumber /= 10 IF pNumber = 0 THEN BREAK. END Benchmark PROCEDURE(LoopString pDigitCount,*string pStringResult) I LONG StartTime LONG EndTime LONG Digits1 LONG,DIM(10) Digits1Zero LONG,DIM(10) TestFirst EQUATE(35283) TestLast EQUATE(935521) Digits2 LONG,DIM(10) Digits2Zero LONG,DIM(10) CODE !Run and display results pStringResult = 'Testing...' DISPLAY StartTime = CLOCK() LOOP 10 TIMES pDigitCount(1,1000000,0,Digits1) pDigitCount(1,1000000,1,Digits1Zero) pDigitCount(TestFirst,TestLast,0,Digits2) pDigitCount(TestFirst,TestLast,1,Digits2Zero) END EndTime = CLOCK() pStringResult = (EndTime - StartTime)/100&' seconds<13,10>' pStringResult = CLIP(pStringResult)&' 1 to 1000000 > ' LOOP I = 0 TO 9 pStringResult = CLIP(pStringResult)&' '&I&':'&RIGHT(Digits1[I+1],7) END pStringResult = CLIP(pStringResult)&'<13,10>' pStringResult = CLIP(pStringResult)&'0000001 to 1000000 > ' LOOP I = 0 TO 9 pStringResult = CLIP(pStringResult)&' '&I&':'&RIGHT(Digits1Zero[I+1],7) END pStringResult = CLIP(pStringResult)&'<13,10>' pStringResult = CLIP(pStringResult)&RIGHT(TestFirst,7)&' to '&RIGHT(TestLast,7)&' > ' LOOP I = 0 TO 9 pStringResult = CLIP(pStringResult)&' '&I&':'&RIGHT(Digits2[I+1],7) END pStringResult = CLIP(pStringResult)&'<13,10>' pStringResult = CLIP(pStringResult)&RIGHT('0000000'&TestFirst,7)&' to '&RIGHT('0000000'&TestLast,7)&' > ' LOOP I = 0 TO 9 pStringResult = CLIP(pStringResult)&' '&I&':'&RIGHT(Digits2Zero[I+1],7) END pStringResult = CLIP(pStringResult)&'<13,10>' DISPLAY