>>  <<  Usr  Pri  JfC  LJ  Phr  Dic  Rel  Voc  !:  Help  Learning J

Chapter 19: Numbers

The topics covered in this chapter are:
  • The different kinds of numbers available in J
  • Special numbers (infinities and indeterminates)
  • Notations for writing numbers
  • How numbers are displayed and formatted
  • Number bases
  • Random numbers

19.1 Numbers of Six Different Kinds

J supports computation with numbers of these kinds:

  • booleans (or truth-values)
  • integers
  • real (or floating-point) numbers
  • complex numbers
  • extended integers (that is, arbitrarily large integers exactly represented)
  • rationals (that is, pairs of extended integers)
Each kind of number has its own internal representation in memory. For example, an array containing only the truth-values 0 and 1 is stored in a compact internal form, called "boolean", rather than in the floating-point form. Similarly an array containing only (relatively small) whole numbers is stored in a compact form called "integer".

The choice of appropriate representation is managed entirely automatically by the J system, and is not normally something the programmer must be aware of. However, there is a means of testing the representation of a number. Here is a utility function for the purpose.

   types =: 'bool';'int';'float';'complex';'ext int';'rational'
   
   type  =: > @: ({ & types) @: (1 4 8 16 64 128 & i.) @: (3 !: 0)
   

type 0=0 type 37 type 2.5 type 12345678901
bool int float float

19.1.1 Booleans

There are built-in functions for logical computation with boolean values. Giving conventional names to these functions:
   and    =: *.
   or     =: +.
   not    =: -.
   notand =: *: 
   notor  =: +:
we can show their truth-tables:
   p =: 4 1 $ 0 0 1 1
   q =: 4 1 $ 0 1 0 1
   

p q p and q p or q not p p notand q
0
0
1
1
0
1
0
1
0
0
0
1
0
1
1
1
1
1
0
0
1
1
1
0

Further logical functions can be defined in the usual way. For example, logical implication, with the scheme

         p implies q    means   not (p and not q)
is defined by not composed with the hook and not
   implies =: not @ (and not)
   

p q p implies q
0
0
1
1
0
1
0
1
1
1
0
1

Notice that in the truth-table above the rows are given in an order such that p,q = successively 00 01 10 11 in binary or 0 1 2 3. Call this the standard order.

With the rows of a truth-table in standard order, the result-column can be read as a 4-bit number, 1 1 0 1 in this example. This means that there are altogether only 16 possible logical functions of two arguments, and that any of them can be specified by giving its 4-bit result.

There is a built-in adverb b. (lowercase b dot, called "Boolean"), which can take an integer in the range 0-15, expressing a 4-bit result, and produces the corresponding logical function.

For example, we saw above that for logical implication its 4-bit specification is 1 1 0 1 or 13, giving us another way to define implication as 13 b. We see:

p q p implies q p (13 b.) q
0
0
1
1
0
1
0
1
1
1
0
1
1
1
0
1

We regard the booleans as numbers because they can be interpreted as having arithmetic values. To illustrate, implication has the same truth-table as less-than-or-equal:

p implies q p <: q
1
1
0
1
1
1
0
1

For another example of booleans as numbers, the sum of the positive numbers in a list is shown by:

z =: 3 _1 4 b =: z > 0 b * z +/ b * z
3 _1 4 1 0 1 3 0 4 7


19.1.2 Integers

On a 32-bit machine integers range between _2147483648 and 2147483647.

The result of arithmetic with integers is converted to floating-point if larger than the maximum integer.

maxint=:2147483647 type maxint z =: 1+maxint type z
2147483647 int 2.14748e9 float

19.1.3 Bitwise Logical Functions on Integers

J provides all the expected functions on integers, so not much need be said here. However, this might be a good place to mention that bitwise logical functions on integers are available through the built-in adverb b. we met above. To begin, here is a utility function to show the first and last few bits of an integer (assumed 32-bit).
   bits =: (3 : ' (8{.y), ''...'', (24 }.y) ') @: ({&'01')@:((32#2) & #:) 
   

bits 15 bits _15
00000000...00001111 11111111...11110001

Recall that logical function k is given by k b. where k is in the range 0-15. The function (k+16) b. is logically the same, but applies, not to booleans, but to integers bitwise, that is, on machine words.

For example (1 b.) is logical-and on booleans, while (17 b.) is logical-and on integers.

   bits 15 (17 b.) _15
00000000...00000001
   
The verb (32 b.) rotates the bits of y leftward by x places, or rightward for negative x. Similarly (33 b.) shifts and (34 b.) performs a "signed shift" that is, propagating the sign bit on a rightward move. For example:
   ] bits a =: 1
00000000...00000001
   
   ] bits b =: _1 (32 b.) a   NB. rotating rightwards 
10000000...00000000
   
   ] bits c =: _1 (34 b.) b   NB. shifting right, propagating sign-bit
11000000...00000000
   
   ] bits d =: 2  (33 b.) c   NB. shifting left, removing sign-bits
00000000...00000000
   
For one more example, recall the Collatz function from Chapter 10 : halve if even, otherwise triple and add one. Here is a bitwise version.
   odd    =: (17 b.) & 1
   halve  =: _1 & (33 b.)          NB. OK for an even number !
   triple =: + (1 & (33 b.))
   
   collatz =:   halve ` (1 + triple) @. odd
   
   collatz ^: (i. 10) 5
5 16 8 4 2 1 4 2 1 4

19.1.4 Floating-Point Numbers

A floating-point number is a number represented in the computer in such a way that: (1) there may be a a fractional part as well as a whole-number part. (2) a fixed amount of computer storage is occupied by the number, whatever the value of the number. and therefore (3) the precision with which the number is represented is limited to at most about 17 significant decimal digits (on a PC).

Examples of floating-point numbers are 0.25 2.5 12345678901

We will use the term "real" more or less interchangeably with "floating-point".

19.1.5 Scientific Notation

What is sometimes called "scientific notation" is a convenient way of writing very large or very small numbers. For example, 1500000 may be written as 1.5e6, meaning 1.5 * 10^6. The general scheme is that a number written in the form XeY, where Y is a (positive or negative) integer means (X * 10^Y).

3e2 1.5e6 1.5e_4
300 1500000 0.00015

Note that in 3e2 the letter e is not any kind of function; it is part of the notation for writing numbers, just as a decimal point is part of the notation.

We say that the string of characters 3 followed by e followed by 2 is a numeral which denotes the number 300. The string of characters 3 followed by 0 followed by 0 is another numeral denoting the same number. Different forms of numerals provide convenient ways to express different numbers. A number expressed by a numeral is also called a "constant" (as opposed to a variable.)

We will come back to the topic of numerals: now we return to the topic of different kinds of numbers.

19.1.6 Comparison of Floating-Point Numbers

Two numbers are regarded as equal if their difference is relatively small. For example, we see that a and b have a non-zero difference, but even so the expression a = b produces "true".

a =: 1.001 b =: a - 2^_45 a - b a = b
1.001 1.001 2.84217e_14 1

If we say that the "relative difference" of two numbers is the magnitude of the difference divided by the larger of the magnitudes:

   RD =: (| @: -) % (>. &: |)
then for a=b to be true, the relative difference (a RD b) must not exceed a small value called the "comparison tolerance" which is by default 2^_44

a RD b 2^_44 a = b
2.83933e_14 5.68434e_14 1

Thus to compare two numbers we need to compare relative difference with tolerance. The latter comparison is itself strict, that is, does not involve any tolerance.

Zero is not tolerantly equal to any non-zero number, no matter how small, because the relative difference must be 1, and thus greater than tolerance.

tiny =: 1e_300 tiny = 0 tiny RD 0
1e_300 0 1

However, 1+tiny is tolerantly equal to 1.

tiny tiny = 0 1 = tiny + 1
1e_300 0 1

The value of the comparison tolerance currently in effect is given by the built-in verb 9!:18 applied to a null argument. It is currently 2^_44.

9!:18 '' 2^_44
5.68434e_14 5.68434e_14

Applying the built-in verb 9!:19 to an argument y sets the tolerance to y subsequently. The following example shows that when the tolerance is 2^_44, then a = b but when the tolerance is set to zero it is no longer the case that a = b.

(9!:19) 2^_44 a = b (9!:19) 0 a = b
  1   0

The tolerance queried by 9!:18 and set by 9!:19 is a global parameter, influencing the outcome of computations with =. A verb to apply a specified tolerance t, regardless of the global parameter, can be written as = !. t. For example, strict (zero-tolerance) equality can be defined by:

   streq =: = !.  0
Resetting the global tolerance to the default value, we see:

(9!:19) 2^_44 a - b a = b a streq b
  2.84217e_14 1 0

Comparison with = is tolerant, and so are comparisons with <, <:, >, >:, ~: and -:. For example, the difference a-b is positive but too small to make it true that a>b

a - b a > b
2.84217e_14 0

Permissible tolerances range between 0 and 2^_35. That is, an attempt to set the tolerance larger than 2^_35 is an error:

(9!:19) 2^_35 (9!:19) 2^_34
  error

The effect of disallowing large tolerances is that no two different integers compare equal when converted to floating-point.

19.1.7 Complex Numbers

The square root of -1 is the imaginary number conventionally called "i". A complex number which is conventionally written as, for example, 3+i4 is in J written as 3j4.

In J an imaginary number is represented as a complex number with real part zero. Thus "i", the square root of -1, can be written 0j1.

i =: %: _1 i * i 0j1 * 0j1
0j1 _1 _1

A complex number can be built from two separate real numbers by arithmetic in the ordinary way, or more conveniently with the built-in function j. (lowercase j dot, called "Complex").

3 + (%: _1) * 4 3 j. 4
3j4 3j4

Some more examples of arithmetic with complex numbers:

2j3 * 5j7 10j21 % 5j7 2j3 % 2
_11j29 2.66216j0.472973 1j1.5

A complex number such as 3j4 is a single number, a scalar. To extract its real part and imaginary part separately we can use the built-in verb +.(plus dot, called "Real/Imaginary"). To extract separately the magnitude and angle (in radians) we can use the built-in verb *. (asterisk dot, called "Length/Angle").

+. 3j4 *. 3j4
3 4 5 0.927295

Given a magnitude and angle, we can build a complex number by taking sine and cosine, or more conveniently with the built-in function r. (lowercase r dot, called "Polar").

   sin =: 1 & o.
   cos =: 2 & o.
   mag =: 5
   ang =: 0.92729522  NB. radians

mag * (cos ang) + 0j1 * sin ang mag r. ang
3j4 3j4

A complex constant with magnitude X and angle (in radians) Y can be written in the form XarY, meaning X r. Y. Similarly, if the angle is given in degrees, we can write XadY.

5ar0.9272952 5ad53.1301
3j4 3j4

19.1.8 Extended Integers

A floating-point number, having a limited storage space in the computer's memory, can represent an integer exactly only up to about 17 digits. For exact computations with longer numbers, "extended integers" are available. An "extended integer" is a number which exactly represents an integer no matter how many digits are needed. An extended integer is written with the digits followed with the letter 'x'. Compare the following:

a =: *: 10000000001 b =: *: 10000000001x
1e20 100000000020000000001

Here a is an approximation while b is an exact result.

type a type b
float ext int

We can see that adding 1 to a makes no difference, while adding 1 to b does make a difference:

(a + 1) - a (b + 1) - b
0 1

19.1.9 Rational Numbers

A "rational number" is a single number which represents exactly the ratio of two integers, for example, two-thirds is the ratio of 2 to 3. Two-thirds can be written as a rational number with the notation 2r3.

The point of rationals is that they are are exact representations using extended integers. Arithmetic with rationals gives exact results.

2r3 + 1r7 2r3 * 4r7 2r3 % 5r7
17r21 8r21 14r15

Rationals can be constructed by dividing extended integers. Compare the following:

2 % 3 2x % 3x
0.666667 2r3

A rational can be constructed from a given floating-point number with the verb x:

x: 0.3 x: 1 % 3
3r10 1r3

A rational number can be converted to a floating-point approximation with the inverse ofx: , that is, verb x: ^: _1

float =: x: ^: _1 float 2r3
+--+--+--+
|x:|^:|_1|
+--+--+--+
0.666667

Given a rational number, its numerator and denominator can be recovered with the verb 2 & x:, which gives a list of length 2.

nd =: 2 & x: nd 2r3
+-+-+--+
|2|&|x:|
+-+-+--+
2 3

19.1.10 Type Conversion

We have numbers of six different types: boolean, integer, extended integer, rational, floating-point and complex.

Arithmetic can be done with a mixture of types. For example an integer plus an extended gives an extended, and a rational times a float gives a float.

1 + 10^19x 1r3 * 0.75
10000000000000000001 0.25

The general scheme is that the six types form a progression: from boolean to integer to extended to rational to floating-point to complex. We say that boolean is the simplest or "lowest" type and complex as the most general or "highest" type

Where we have two numbers of different types, the one of lower type is converted to match the type of the higher. and the result is of the "higher".

type 1r3 type 1%3 z =: 1r3, 1%3 type z
rational float 0.333333 0.333333 float

19.2 Special Numbers

19.2.1 "Infinity"

A floating-point number can (on a PC) be no larger than about 1e308, because of the way it is stored in the computer's memory. Any arithmetic which attempts to produce a larger result will in fact produce a special number called "infinity" and written _ (underscore). For example:

1e308 * 0 1 2 1e400 1 % 0
0 1e308 _ _ _

There is also "negative infinity" written as __ (underscore underscore). Infinity is a floating-point number:

   type _
float
   

19.2.2 "Indeterminate" Numbers

A floating-point number is a 64-bit value, but not all 64-bit values are valid as floating-point numbers. Any which is not valid is said to be "Not a Number", or a "NaN". Such a value might occur, for example, in data imported into a J program from an unreliable external source.

When displaying the values of numbers, the J system reports any supposed floating-point number, which is in fact "Not a Number", as the symbol _. (underbar dot, called "Indeterminate").

Floating-point arithmetic on _. arguments cannot be relied upon to produce meaningful results. Thus _. is best regarded solely as a mark of error.

The sole reliable test for _. is the verb 128 !: 5 . In the following example note the difference between results of the unreliable test X = _. and the reliable test 128 !: 5 X .

X =: 1.5 _. 2.5 X = _. 128!:5 X
1.5 _. 2.5 0 0 0 0 1 0

19.3 Number Bases

The number 5 is represented in binary as 1 0 1. There is a built- in function, monadic #: ( hash colon, called "Antibase Two" ) to compute the binary digits. Note that the result is a list.
   #: 5
1 0 1
We say that the binary digits are the base-2 representation. More generally, a base-n representation can be produced. The left argument of dyadic #: (called "Antibase") specifies the both the base and the number of digits. To get four binary digits we can write:
   2 2 2 2 #: 5
0 1 0 1
63 as two base-8 (octal) digits:
   8 8 #: 63
7 7
   
A mixed-base representation is possible. How many hours, minutes and seconds are there in 7265 seconds?
   24 60 60 #: 7265
2 1 5
The inverse functions produce numbers from lists of digits in specified bases. Monadic #. is called "Base Two". Binary 1 0 1 is 5
   #. 1 0 1
5
Dyadic #. is called "Base". Its left argument specifies a number-base for the digits of the right argument.
   2 #. 1 0 1
5
Equivalently:
   2 2 2 #. 1 0 1
5
   
There must be a base specified on the left for each digit on the right, otherwise an error is signalled
    2 2 #. 1 0 1
|length error
|   2 2    #.1 0 1
|[-535] c:\users\homer\14\js\19.ijs
   
Again, mixed bases are possible: 2 hours 1 minute 5 seconds is 7265 seconds
   24 60 60  #. 2 1 5
7265
   

19.4 Notations for Numerals

We have seen above numerals formed with the letters e, r and j, for example: 1e3, 2r3, and 3j4. Here we look at more letters for forming numerals.

A numeral written with letter p, of the form XpY means X * pi ^ Y where pi is the familiar value 3.14159265....

pi =: 1p1 twopi =: 2p1 2p_1
3.14159 6.28319 0.63662

Similarly, a numeral written with letter x, of the form XxY means X * e ^ Y where e is the familiar value 2.718281828....

e =: 1x1 2x_1 2 * e ^ _1
2.71828 0.735759 0.735759

These p and x forms of numeral provide a convenient way of writing constants accurately without writing out many digits. Finally, we can write numerals with a base other than 10. For example the binary or base-2 number with binary digits 101 has the value 5 and can be written as 2b101.

   2b101 
5
The general scheme is that NbDDD.DDD is a numeral in number-base N with digits DDD.DDD . With bases larger than 10, we will need digits larger than 9, so we take letter 'a' as a digit with value 10, 'b' with value 11, and so on up to 'z' with value 35.

For example, letter 'f' has digit-value 15, so in hexadecimal (base 16) the numeral written 16bff has the value 255. The number-base N is given in decimal.

16bff (16 * 15) + 15
255 255

One more example. 10b0.9 is evidently a base-10 number meaning "nine-tenths" and so, in base 20, 20b0.f means "fifteen twentieths"

   10b0.9 20b0.f
0.9 0.75

19.4.1 Combining the Notations

The notation-letters e, r, j ar ad p x and b may be used in combination. For example we can write 1r2p1 to mean "pi over two". Here are some further examples of possible combinations.

A numeral in the form XrY denotes the number X%Y. A numeral in the form XeYrZ denotes the number (XeY) % Z because e is considered before r.

1.2e2 (1.2e2) % 4 1.2e2r4
120 30 30

A numeral in the form XjY denotes the complex number (X j. Y) (that is, (X + (%: _1) * Y). A numeral in the form XrYjZ denotes the number (XrY) j. Z because r is considered before j

3r4 (3r4) j. 5 3r4j5
3r4 0.75j5 0.75j5

A numeral in the form XpY denotes the number X*pi^Y. A numeral in the form XjYpZ denotes (XjY) *pi^Z because j is considered before p.

3j4p5 (3j4) * pi ^ 5
918.059j1224.08 918.059j1224.08

A numeral in the form XbY denotes the number Y-in-base-X. A numeral in the form XpYbZ denotes the number Z-in-base-(XpY) because p is considered before b.

(3*pi)+5 1p1b35
14.4248 14.4248


19.5 How Numbers are Displayed

A number is displayed by J with, by default, up to 6 or 7 significant digits. This means that, commonly, small integers are shown exactly, while large numbers, or numbers with many significant digits, are shown approximately.

10 ^ 3 2.7182818285 2.718281828 * 10 ^ 7
1000 2.71828 2.71828e7

The number of significant digits used for display is determined by a global variable called the "print-precision". If we define the two functions:

   ppq =: 9 !: 10    NB. print-precision query
   pps =: 9 !: 11    NB. print-precision set
then the expression ppq '' gives the value of print-precision currently in effect, while pps n will set the print-precision to n.

ppq '' e =: 2.718281828 pps 8 e
6 2.71828   2.7182818

19.5.1 The "Format" Verb

There is a built-in verb ": (doublequote colon, called "Format"). Monadic Format converts a number into a string representing the number with the print-precision currently in effect. In the following example, note that a is a scalar, while the formatted representation of a is a list of characters.

a =: 1 % 3 ": a $ ": a
0.33333333 0.33333333 10

The argument can be a list of numbers and the result is a single string.

b =: 1 % 3 4 ": b $ b $ ": b
0.33333333 0.25 0.33333333 0.25 2 15

Dyadic Format allows more control over the representation. The left argument is complex: a value of say, 8j4 will format the numbers in a width of 8 characters and with 4 decimal places.

c =: % 1 + i. 2 2 w =: 8j4 ": c $ w
         1  0.5
0.33333333 0.25
  1.0000  0.5000
  0.3333  0.2500
2 16

If the width is specified as zero (as in say 0j3) then sufficient width is allowed. If the number of decimal places is negative (as in 10j_3) then numbers are shown in "scientific notation"

c 0j3 ": c 10j_3 ": c
         1  0.5
0.33333333 0.25
1.000 0.500
0.333 0.250
1.000e0   5.000e_1
3.333e_1  2.500e_1

Note that monadic format shows a complex number in the usual way, but dyadic format shows only the real part of a complex number.

z =: 3.14j2.72 ": z 6j2 ": z
3.14j2.72 3.14j2.72   3.14

More formatting options are provided by the built-in verbs 8!:n. Here is a small example to show a few of the many options described in the J dictionary.

Suppose our table of numbers to be formatted is N

    ] N =: 3 2 $  3.8  _2000 0  123.45 _3.14 15000
  3.8  _2000
    0 123.45
_3.14  15000
We can format each column of N separately. Suppose numbers in the first column are to be presented as blank when zero, 6 characters wide with 0 decimal places. We write a "formatting phrase" like this
   fp1 =: 'b6.0'
Here the 'b' means blank when zero.

Suppose for the second column we require a comma between each 3 digits. We require negative numbers to be shown with a following "CR" and therefore non-negative numbers should be followed by two blank characters, so that decimal points line up vertically. We require a 12-character width with 2 decimal places.

A suitable formatting phrase is like this:

   fp2 =: 'cn{CR}q{  }12.2'
Here the 'c' means commas, n{CR} means CR after a negative number and q{ } means 2 spaces after a non-negative.

Applying the formatting verb 8!:2 we see

N (fp1;fp2) (8!:2) N
  3.8  _2000
    0 123.45
_3.14  15000
     4  2,000.00CR
          123.45
    -3 15,000.00

The formatted result is a character table of dimensions 3 by 18, because N has 3 rows, and we specified widths of 6 and 12 for first and second columns.

   $ (fp1;fp2) (8!:2) N
3 18
   
   
   
   

19.6 Random Numbers

19.6.1 Roll

There are built-in functions for generating random numbers. Monadic ? is called "Roll", because ? n gives the result of rolling a die with n faces marked 0 to n-1.
   ? 6
4
That is, ? n is selected from the items of i. n randomly with equal probability.

A list of random numbers is generated by repeating the n-value. For example, four rolls of a six-sided die is given by

   ? 6 6 6 6
3 4 5 2
or more conveniently by:
   ? 4 $ 6
2 3 5 3

19.6.2 Uniform Distribution

With an argument of zero, monadic ? generates random reals uniformly distributed, greater than 0 and less than 1.
   ? 0 0 0 0
0.14112615 0.083891464 0.41388488 0.055053198
   

19.6.3 Other Distributions

The built-in verb ? generates equiprobable numbers. Various other distributions are provided by the J Application Library stats/distribs Addon

19.6.4 Deal

Dyadic ? is called "Deal". x ? y is a list of x integers randomly chosen from i. y without replacement, that is, the x integers are all different.

Suppose that cards in a deck are numbered 0 to 51, then 13 ? 52 will deal a single hand of 13 randomly selected cards, all different.

   13 ? 52
44 2 36 30 0 6 43 26 28 1 34 48 41
A shuffle of the whole deck is given by 52 ? 52. To shuffle and then deal four hands:
   4 13 $ 52 ? 52
15 18  3  8 11 25 27 51 20 31 50 48 35
45 39 21 29 10 33 32 41 36  0 34 16 22
19 14 37  2 24 42  6  7 30 46 47 28 26
38 23 40 13  4  9  5 12 49  1 44 43 17
   
This brings us to the end of Chapter 19.

NEXT
Table of Contents
Index


The examples in this chapter were executed using J version 701. This chapter last updated 02 Jul 2013
Copyright © Roger Stokes 2012. This material may be freely reproduced, provided that this copyright notice is also reproduced.


>>  <<  Usr  Pri  JfC  LJ  Phr  Dic  Rel  Voc  !:  Help  Learning J