| # 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 ## 19.1 Six Different Kinds of Numbers 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`
       imp =: not @ (and not)
`p` | `q` | `p imp q`
    0
    0
    1
    1
    0
    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 imp 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 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.4 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.5 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 magnitude of the larger,
       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.6 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 always regarded 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 + 0j1 * 4` | `3 j. 4`
    3j4
    3j4
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.7 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.8 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 of`x:` , 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.9 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 Infinity is equal to infinity. However, infinity minus infinity is not zero but rather a special number called "indeterminate", written as `_.` (underscore dot)
`_ = _` | `_ - _`
    1
    _.
Indeterminate is equal to indeterminate. However indeterminate minus indeterminate is not zero but indeterminate.
`_. = _.` | `_. - _.`
    1
    _.
Computations with indeterminate may produce surprising results. Thus indeterminate is not to be regarded as extending the meaning of "number" according to some extended axiomatization of arithmetic. Rather, the view is recommended that the only purpose of indeterminate is as a signal of numerical error when it occurs in the result of a computation. Infinity is equal to itself and nothing else, and the same is true of indeterminate. Thus we have a reliable (that is, determinate) test for occurrences.
`z =: 1 _ _.` | `z = 1` | `z = _` | `z = _.`
    1 _ _.
    1 0 0
    0 1 0
    0 0 1
## 19.3 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.3.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.4 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.4.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
This brings us to the end of Chapter 19.

NEXT
Table of Contents

Copyright © Roger Stokes 2002. This material may be freely reproduced, provided that this copyright notice is also reproduced.

last updated 15 Mar 2002