THE PUZZLET PAGE


How_Does_It_Work


FUNCTION:  NoZeroes().  Pass an integer to this function and it will inpsect each digit in the integer. If one of them is found to be a zero it returns FALSE (0) to the calling routine. If they're all non-zero it returns TRUE (-1).  This is one of those functions that are so short you may be tempted to ask why not just put the code in the main routine and save the effort? There are two very good reasons.

Firstly, you may need to repeat this operation many times over from different parts of your program. Having a function means it only has to be typed into the code once. In addition, if you type the function in without error, it is always right. But if you have to type it into several parts of your program, a new opportunity for typos arises each time.

Secondly, it makes for neat top-down programming. The main routine can just say something like: sum = SumDigits(n). It's immediately clear to even an untutored reader what's going on, an uncluttered appearance is maintained, and the main routine is physically much shorter, making a visual overview much easier.

It's up to you what data type you make the argument, depending on the type of integer you want to process.


Type

Exponent of 2
Value

int 230 1073741824
uint 231 2147483648
int64 261 2305843009213693952
uint64 262 4611686018427387904

Declaring the function must be done like this:

declare NoZeroes(n: int) (or whatever integer type you want).

Here's the code:

sub NoZeroes(n)
' If argument n is zero or it
' contains at least one zero
' after a non-zero digit,
' returns FALSE (0), otherwise
' returns TRUE (-1).
' Note: this method is 35%
' faster than string method.

def flag: int
flag = -1
do
    if n % 10 = 0: 'is LSD a zero?
        flag = 0
    else
        n = n/10: 'chop off LSD
    endif
until not flag | n < 1: 'done
return flag


In the description of the code which follows, I have applied line numbers to make it easier to follow. Here they are:

1
2
3
4
5
6
7
8
9

flag = -1
do
    if n % 10 = 0: 'is LSD a zero?
        flag = 0
    else
        n = n/10: 'chop off LSD
    endif
until not flag | n < 1: 'done
return flag

Now for a line-by-line exegesis of the code.

1

flag = -1There's only one local variable in this function: flag, used to indicate that a zero has been found. The program commences by setting flag to TRUE (-1), making the assumption there are no zeroes in the digits of n. Unless the checks within the DO loop change flag's status, that is the value that will be returned to the calling routine. Let's look within the DO loop now.

2

do.  Opens the main do-until loop.

3

if n % 10 = 0. This is integer arithmetic. It effectively says "If the remainder after dividing n by 10 is zero ... ". Let's look at a couple of examples.  Assume n has a value of 12345. Clearly, dividing by 10 won't leave a remainder of zero. What about n = 12340? Dividing this by 10 will definitely leave zero.  Thus, if the LSD (least-significant, or right-most, digit) was zero, n % 10 will be zero. So this expression can be simplified to "If n's LSD is zero . . ." 

4

flag = 0 If the answer to the question above is yes, we've already found a zero in n, and checks on the rest of the digits are a waste of time. So the line  flag = 0 is executed to set flag to FALSE (0) to signal this fact to the rest of the code.

5

else.  Indicates that there is an alternative action if the answer to the question posed in line 3 is negative, that is, the last check did not reveal a zero.  The alternative action is detailed in line 6 below.

6

n = n/10.  Line 6 means "change the value in n to be equal to n/10." If n is 12345, the new value will be 1234.5, won't it? No! The original declaration defined n as an integer, a number with no decimal part.  So the decimal part is dropped, and we end up with 1234. This has effectively lopped off the LSD.

7

endif.  Housekeeping - closes the if-endif clause opened in line 3.

8

until not flag | n < 1The code now reaches the end of the DO loop. It needs to decide whether to execute the loop again, or just move on to the next instruction.

The line
until not flag | n < 1 is the decision-maker.  It can be paraphrased as "execute the DO loop again unless either flag is FALSE (0) or the value of n is less than 1."

The "until not flag" may appear confusing, but it's actually simple. The normal phrase is "until flag" and means "execute the DO loop until flag is set to TRUE (-1)." So "until not flag" means the opposite:
"execute the DO loop until flag is set to FALSE (0)."

Clearly, if flag is FALSE (0), a zero has been found, so there's no need to look at any more of n's digits. The function can return the FALSE (0) immediately.

And the alternative for exiting the DO loop is if n is less than 1. Remember, it's decremented by 1 each time the DO loop executes without finding a zero. So, eventually, if no zeroes are found, n will eventually reach zero.

One of those two alternatives will cause the last line of code to be executed
.

9

return flag.  Whatever value ends up stored in variable flag is now returned.  The calling routine will thus receive either a FALSE (0) or TRUE (-1), corresponding to the presence or absence of zeroes within n.

Earlier versions of this function used strings, but I have found this method, using integer arithmetic, is much faster.


MAIN MENU
HOW DOES IT WORK?

Site design/maintenance: Dave Ellis E-mail me!
Last Updated: February 5th, 2010.