3-Lib banner

The Absolute Beginners Guide to OPL

Part 17 - Back to school


I introduced the concept of 'long' integers in lesson 15, as a type of integer variable that can store a larger range of numbers. It's so important to understand the differences between 'normal' and 'long' integers and the limits of each that I want to spend an entire lesson examining them in detail. We'll discuss the ideas involved first and then do some practical experiments.

A 'normal' integer is denoted by a "%" character after the variable name (which can, by the way, be up to 7 characters long on a 3a/3c or as long as you like on a S5) and is stored in 16 'bits' of computer memory. Each 'bit' is a one or zero, i.e. we're talking about binary, the raw language of any computer

If you do the maths, you'll realise that 216 is 65536, i.e. there are this many possible combinations of ones and zeros in the 16-bit word. In practice, to handle negative numbers more elegantly, the Psion lets normal integers take the values -32767 to +32767. Although this is a large number, it's not beyond the bounds of possibility that you might want to use larger ones, which of course is where 'long' integers come in.

Each long integer, denoted by the "&" after the variable name, is represented inside the Psion by 32 bits, giving 232 possible numbers, or 4294967296, which should be large enough for most people's programs! Before I talk more about these, let's see how all this works in practice.

From the system screen, make a new OPL 'Program' file, called anything you want (I'm using "Integer") and enter the code shown below:

PROC integer:
REM to examine the way integers behave!

LOCAL i%,j%

i%=1
j%=2

PRINT i%/j%
GET
ENDP

Screen shotStop and think before translating and running the program. All we've asked the program to do is to divide two numbers by each other and you'd expect 1/2 to be calculated as "0.5". Try it and see now.

You'll find the answer PRINTed out on screen is zero! The reason this happens is that whenever OPL sees you trying to use just integers in a fraction, it performs the whole calculation in a special 'integer' mode and sets the result to also be of type integer. And of course 0.5 isn't an integer, so the program's giving you the answer 'rounded down' to the nearest whole number. The reason why OPL makes this assumption and behaves like this is that doing integer arithmetic (1,2,3 etc) is many times faster than the usual 'floating point' (e.g. 2.345, 113.002 etc.) variety and for many applications where speed is essential (e.g. Psi-Mapper's display routines), many calculations can be designed to run in this quicker mode.

So, wherever you use integers or long integers and the division sign (/), always be aware of this 'integer arithmetic' effect. Sermon over. Now change the code to read:

i%=1000
j%=2000

PRINT i%*j%/2000

Screen shotNote the values of i% and j% are not too high and well within the +/-32767 limit we discussed earlier. Translate and run the program. You should get an 'overflow' error. What's happening is that although i% and j% and the expected result of the calculation are all themselves well within the normal integer limit, OPL spots that all the components are 16-bit integers and goes into its 16-bit integer arithmetic mode. And of course, within the calculation is a multiplication that involves a product of 2 million, well over the 32767 limit. So this is another thing to beware when doing this sort of calculation. As I found when programming Psi-Mapper, the best way to keep the benefits of integer arithmetic and ensure that calculations never exceed the built-in limits is to use long integers where appropriate.

To prove the point, change i% and j% to i& and j& throughout the program above and retranslate and run.

Screen shotIt of course now works fine. OPL spots that long integers are involved and does its sums using 32-bit integer calculations instead, which have a far higher built-in limit.

Finally, one other common way round the problem of being hit by integer arithmetic effects is to simple force OPL to use 'floating point' arithmetic instead. As long as speed is not critical and that you don't mind having the result in floating point form, there are easy ways of forcing OPL's hand. Change the program to read:

LOCAL i%,j%

i%=1000
j%=2000

PRINT 1.0*i%*j%/2000

Screen shotTranslate and run as usual, it should work fine. The only difference from the original code which caused the 'overflow' is the addition of the "1.0*" at the start of the calculation. Although it (obviously) doesn't affect the value of anything that follows, OPL spots the decimal point and switches the calculation into floating point (i.e. numbers, decimal points, exponentials, all that sort of thing) mode. Handy when you know how and want to stop your program from crashing!

Next week we'll return to database access and look at reading numbers back from the saved database of numbers. See you then!


Go to next lesson | Programming index