Any code we write needs to be tested. In this circumstance, where the code is to be deployed remotely (remember the two thousand FX-7400G calculators to be shipped to the users?), the code needs to be as near bulletproof as we can make it. If a program we write for ourselves breaks, we are there to fix it. This code is to be deployed to the field, and we really do not want to deal with a problem report from Elbonia. So we need to thoroughly test this code.

We first want to test that this code works in its intended circumstances. The intended circumstances are that A and B are each zero or non-zero, and C is a function code between 0 and 15. That is 2×2×16 = 64 combinations. The desired results are given in the truth table for binary operators above.

We can write a little program to generate these intended combinations, and report on what the BOOLOP program returns. Overall, the unit test will look like:

fora := 0to1doforb := 0to1doforc := 0to15do{ report BOOLOP (a, b, c); }

In order to keep BOOLOP from destroying our control variables, though, we keep the control variables in something other than the variables A, B, and C. We pick D, E, and F.

We could report the result of BOOLOP with a dialog like:

Result of BOOLOP: A: a B: b C: c Result: result

but that is just a little cumbersome. We would like to pack all that information onto one line, or better into a table. Unfortunately, the FX-7400G does not allow cursor positioning (unlike the CFX-9850G), so it is probably a little too much to ask for a nice table. But we can report all of A, B, C, and the result on one line: we just need to split the digits of a single number up. A and B need one digit each, C needs two digits, and the result needs one digit. The calculator suppresses leading zeroes on output, though, so we either need to encode things as something other than 0 when they are 0, or put a nonsense leading digit on the output. We decide to use a 9 as a leading digit. We therefore want our one-line reports to be:

9abccr

where 9 is a leading digit to force display, a is the one-digit A value, b is the one-digit B value, cc is the two-digit C value, and r is the one-digit result value.

We can quickly code our first unit test program:

Program UTBOOLOP (105 bytes):

; Variables: ; A is first operand [input to BOOLOP] ; B is second operand [input to BOOLOP] ; C is operation [input to BOOLOP]/result [output from BOOLOP] ; D is first operand ; E is second operand ; F is operation ; Symbols: ; -> is assignment arrow ; EE is EXP key ; _ is display triangle For 0->D To 1 ; Loop through first operand, false or true For 0->E To 1 ; Loop through second operand, false or true For 0->F To 15 ; Loop through operation, 0 through 16 D->A ; Set first operand E->B ; Set second operand F->C ; Set function code Prog "BOOLOP" ; Call the function 9EE5+10000D+1000E+10F+C_ ; Display the inputs and results Next ; [End of loop through operation] Next ; [End of loop through second operand] Next ; [End of loop through first operand] "DONE" ; Report finish

Running this program yields the outputs:

900000 900011 900020 900031 900040 900051 ... 911131 911141 911151 DONE

Checking these against the truth table, we see that the BOOLOP program does indeed generate the correct results for its intended inputs.

Now, however, we should check the BOOLOP program against unintended inputs. We need a unit test that allows arbitrary inputs, which the UTBOOLOP program above does not. Also, the UTBOOLOP program above does not check that C and Ans are the same value, as guaranteed by the BOOLOP program description, or that A and B are left unchanged, also as guaranteed by the BOOLOP program description. So we want to allow arbitrary A, B, and C inputs, and report A, B, C, and Ans outputs.

This is a simple little program:

Program UTBOOLO1 (85 bytes):

; Variables: ; A is first operand [input to BOOLOP] ; B is second operand [input to BOOLOP] ; C is operation [input to BOOLOP]/result [output from BOOLOP] ; Symbols: ; -> is assignment arrow ; _ is display triangle While 1 ; Loop forever "A"?->A ; Ask for A value "B"?->B ; Ask for B value "C"?->C ; Ask for C value Prog "BOOLOP" ; Call BOOLOP "ANS:" ; Report Ans Ans_ ; result "A:" ; Report A A_ ; result "B:" ; Report B B_ ; result "C:" ; Report C C_ ; result WhileEnd ; [End of loop forever]

So now we have the capability of testing BOOLOP as a black box. We try a few intended values (0, 0, 0; 1, 1, 15; and so forth), and things seem okay.

Now, boundary errors are common, so we identify boundaries.
A and B are zero or non-zero; we try –1, 0, +1, and +2, and
things look good.
We try -9×10^{99} and +9×10^{99},
and things look good.
We try -9×10^{-99} and +9×10^{-99},
and things look good.
Zero is (correctly) treated as false, and anything else is
(correctly) treated as true.
C is different: it can be 0 through 15.
We try 16, and things look good.
We try –1, and suddenly things look bad:

A? 0 B? 0 C? -1 Ans: -1 A: 0 B: 0 C: -1

Hmm.
We had intended to always generate either 0 or 1.
Checking back against the BOOLOP logic, we see that we
carefully allow any value of A and B, but that we *assume*
C is one of a restricted set of values, 0 through 15.

Oh, dear. Now what do we do? We could just document this as a restriction: “C must be an integer between 0 and 15 inclusive, or the results are indeterminate.” But a better approach is to define some behavior instead, which will require a code change.

But what behavior should we define? We could take the integer portion of C, and take that modulo 16, to ensure we always get an integer in the range 0 to 15. We could always return a flag value if C is invalid. We could always return false (0) if C is invalid. We could halt the program, perhaps by forcing a math error, if C is invalid.

“Be liberal in what you accept; be conservative in what you generate” is a good rule of thumb. We should generate an expected value even if C is invalid. So we extend the definition of our BOOLOP program to always return 0 if C is invalid. The easiest modification of the BOOLOP program is to check C upon entry, and if it is invalid, to replace it with 0. This will ensure we always generate 0. Our BOOLOP program then becomes as follows, with the corrections marked in bold:

Revised program BOOLOP (77 bytes):

; Performs a boolean operation upon two boolean values. Any boolean ; valued function of two boolean arguments may be specified. ; ; The boolean arguments are placed into A and B. These are regarded as ; true and false as they are non-zero or zero, respetively. The code ; for the function to be performed is placed into C. The function code ; is constructed from the truth table for the desired function as ; follows: ; ; A B c ; 0 0 1 ; 0 1 2 ; 1 0 4 ; 1 1 8 ; ; The function code is the sum of the c values corresponding to true ; entries in the truth table. ; ; (Popular functions: 3 is not A, 5 is not B, 14 is A or B, 6 is ; A xor B, 8 is A and B.) ;; A valid function code is an integer between 0 and 15, inclusive. ; Invalid function codes are regarded as equivalent to function 0, ; False.; ; Variables: ; A is the first boolean value; this value is retained ; B is the second boolean value; this value is retained ; C on entry is the function code as described above; on exit is the ; specified boolean function of A and B ; Ans is on exit the specified boolean function of A and B ; ; Symbols: ; <> is the not equal relational ; => is the conditional operator ; < is the less than relational ; > is the greater than relational ; / is the division operator ; -> is the assignment arrowC<>Int C=>0->C ; If C is an invalid value, C<0=>0->C ; replace C with the FALSE C>15=>0->C ; functionA<>0=>C/4->C ; If A, then right shift function code 2 bits B<>0=>C/2->C ; If B, then right shift function code 1 bit 2Frac ((Int C)/2)->C ; Extract result into C C ; Return result in Ans as well

Running our tests again on this modified program, we find (not unexpectedly) that BOOLOP continues to generate correct results for the intended inputs, and now generates correct results for even unintended inputs.

*Now* we are done.

All programs in this section are available both here and in a text file with .CAT file contents.

[ Previous page | Top of page | Next page ]

Copyright © 2002 Brian Hetrick

Page last updated 28 April 2002.

Tutorial

Building Blocks I

Control Flow II

Basic I/O

Algorithms

A First Program

Examples

Logical Ops

Test

Answers

Modularization

Data Structures I

Recursion

Program Attributes

Building Blocks II

Algorithm Analysis

Structuring

Data Structures II

Abstract Types

Objects

Problem Analysis

Reference Card