{Begin SubSec Numbers and Arithmetic Functions} {Title Numbers and Arithmetic Functions} {Text {note add BIGNUMS ---lmm} {Tag Numbers} {Tag SmallIntegers} {index *BEGIN* numbers} {index *PRIMARY* numbers} {index *PRIMARY* boxing} {Tag Boxing} Numerical atoms, or simply numbers, do not have value cells, function definition cells, property lists, or explicit print names. There are three different types of numbers in Interlisp: small integers,{index small integers} large integers,{index large integers} and floating point numbers.{index floating point numbers} Small integers are those integers that can be directly stored within a pointer value. The range of small integers is implementation-dependent. Since a large integer or floating point number can be (in value) any full word quantity (and vice versa), it is necessary to distinguish between those full word quantities that represent large integers or floating point numbers, and other Interlisp pointers. We do this by "boxing" the number: When a large integer or floating point number is created (via an arithmetic operation or by {fn READ}), Interlisp gets a new word from "number storage" and puts the large integer or floating point number into that word. Interlisp then passes around the pointer to that word, i.e., the "boxed number",{index boxed numbers} rather than the actual quantity itself. Then when a numeric function needs the actual numeric quantity, it performs the extra level of addressing to obtain the "value" of the number. This latter process is called "unboxing".{index *PRIMARY* unboxing} Note that unboxing does not use any storage, but that each boxing operation uses one new word of number storage. Thus, if a computation creates many large integers{index large integers} or floating point numbers,{index floating point numbers} i.e., does lots of boxes, it may cause a garbage collection of large integer space, or of floating point number space. Different implementations of Interlisp may use different boxing strategies. Thus, while lots of arithmetic operations {it may} lead to garbage collections, this is not necessarily always the case. The following functions can be used to distinguish the different types of numbers: {FnDef {FnName SMALLP} {FnArgs X} {Text Returns {arg X}, if {arg X} is a small integer; {lisp NIL} otherwise. Does {it not} generate an error if {arg X} is not a number. }} {FnDef {FnName FIXP} {FnArgs X} {Text Returns {arg X}, if {arg X} is an integer (between {var MIN.FIXP} and {var MAX.FIXP}); {lisp NIL} otherwise. Note that {fn FIXP} is true for both large and small integers.{note crock!} Does {it not} generate an error if {arg X} is not a number. }} {FnDef {FnName FLOATP} {FnArgs X} {Text Returns {arg X} if {arg X} is a floating point number; {lisp NIL} otherwise. Does {it not} give an error if {arg X} is not a number. }} {FnDef {FnName NUMBERP} {FnArgs X} {Text Returns {arg X}, if {arg X} is a number of any type ({lisp FIXP} or {lisp FLOATP}); {lisp NIL} otherwise. Does {it not} generate an error if {arg X} is not a number. Note that if {lisp (NUMBERP {arg X})} is true, then either {lisp (FIXP {arg X})} or {lisp (FLOATP {arg X})} is true. {note this won't be true when BIGNUMs are added} }} Each small integer has a unique representation, so {fn EQ} may be used to check equality. Note that {fn EQ} should not be used for large integers{index large integers} or floating point numbers,{index floating point numbers} {index EQP FN}{fn EQP}, {fn IEQP}, or {index EQUAL FN}{fn EQUAL} must be used instead. {FnDef {FnName EQP} {FnArgs X Y} {Text Returns {lisp T}, if {arg X} and {arg Y} are {fn EQ}, or equal numbers; {lisp NIL} otherwise. Note that {fn EQ} may be used if {arg X} and {arg Y} are known to be {it small} integers. {fn EQP} does not convert {arg X} and {arg Y} to integers, e.g., {lisp (EQP 2000 2000.3) => NIL}, but it can be used to compare an integer and a floating point number, e.g., {lisp (EQP 2000 2000.0) => T}. {fn EQP} does {it not} generate an error if {arg X} or {arg Y} are not numbers. Note: {fn EQP} can also be used to compare stack pointers ({PageRef Tag EQPStackPointers}) and compiled code objects ({PageRef Tag EQPCompiledCode}). }} {note encourage generic arith functions ---lmm} {Begin Note} The small number range in Interlisp-D, [-65536, 65535], is much greater than in Interlisp-10, and the overall integer range is smaller (32 bits instead of 36). The {fn SETN} operation is not supported; {fn SETN} is treated as {fn SETQ}. {fn VAG} and {fn LOC} are defined and are inverses, but arithmetic operations cannot be performed on the value of {fn LOC}. {fn OPENR} and {fn CLOSER} do not exist. {fn RAND} currently generates only 16 bits of randomness. The internal format for floating-point numbers in Interlisp-D is IEEE "single" mode (32 bits). {End Note} {Begin SubSec Integer Arithmetic} {Title Integer Arithmetic} {Text {index *PRIMARY* integers} The input syntax for an integer is an optional sign ({lisp +} or {lisp -}) followed by a sequence of digits, followed by an optional {lisp Q}, and terminated by a delimiting character. {index Q (following a number)}If the {lisp Q} is present, the digits are interpreted in octal,{index octal} otherwise in decimal, e.g. {lisp 77Q} and {lisp 63} both correspond to the same integers, and in fact are indistinguishable internally since no record is kept of how integers were created. The setting of {fn RADIX} ({PageRef Fn RADIX}), determines how integers are printed: signed or unsigned, octal or decimal. Integers are created by {fn PACK} and {fn MKATOM} when given a sequence of characters observing the above syntax, e.g. {lisp (PACK '(1 2 Q)) => 10}. Integers are also created as a result of arithmetic operations. The range of integers of various types is implementation-dependent. This information is accessable to the user through the following variables: {VarDef {Name MIN.SMALLP} } {VarDef {Name MAX.SMALLP} {Text The smallest/largest possible small integer. }} {VarDef {Name MIN.FIXP} } {VarDef {Name MAX.FIXP} {Text The smallest/largest possible large integer. }} {VarDef {Name MIN.INTEGER} } {VarDef {Name MAX.INTEGER} {Text The smallest/largest possible integer representable. Currently, these variables are equal to {var MIN.FIXP} and {var MAX.FIXP}; they may be different in future implementations with other methods for representing integers. }} In Interlisp-D, the action taken on integer overflow is determined with the following function: {FnDef {Name OVERFLOW} {Args FLG} {Text Sets a flag that determines the system response to integer overflow; returns the previous setting. If {arg FLG}={lisp T}, an error occurs on integer overflow.{index OVERFLOW Error} If {arg FLG}={lisp NIL}, the largest (or smallest) integer is returned as the result of the overflowed computation. If {arg FLG}={lisp 0}, the result is returned modulo 2↑32 (the default action). {note in Interlisp-Vax, FLG=NIL same as FLG=0} }} {note for BIGNUMs, must have +infinity, -infinity ---lmm} {index *BEGIN* integer arithmetic} {index *BEGIN* arithmetic functions} All of the functions described below work on integers. Unless specified otherwise, if given a floating point number, they first convert the number to an integer by truncating the fractional bits, e.g., {lisp (IPLUS 2.3 3.8)}={lisp 5}; if given a non-numeric argument, they generate an error, {lisp NON-NUMERIC ARG}.{index NON-NUMERIC ARG Error} {note overflow in Interlisp-D??} {note "convert the number to an integer" by rounding or trucating??} {FnDef {FnName IPLUS} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the sum {arg X{sub 1}} + {arg X{sub 2}} + {ellipsis} + {arg X{sub N}}. {lisp (IPLUS)}={lisp 0}. }} {FnDef {FnName IMINUS} {FnArgs X} {Text -{arg X} }} {FnDef {FnName IDIFFERENCE} {FnArgs X Y} {Text {arg X} - {arg Y} }} {FnDef {FnName ADD1} {FnArgs X} {Text {arg X} + 1 }} {FnDef {FnName SUB1} {FnArgs X} {Text {arg X} - 1 }} {FnDef {FnName ITIMES} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the product {arg X{sub 1}} * {arg X{sub 2}} * {ellipsis} * {arg X{sub N}}. {lisp (ITIMES)}={lisp 1}. }} {FnDef {FnName IQUOTIENT} {FnArgs X Y} {Text {arg X} / {arg Y} truncated. Examples: {lispcode (IQUOTIENT 3 2) => 1} {lispcode (IQUOTIENT -3 2) => -1} }} {Begin Note} Date: 21 MAR 1982 1809-PST From: SHEIL.PA On the 10, both FQUOTIENT and IQUOTIENT (consistently)(insanely) return their first arg if their second is 0. On the D machines, IQUOTIENT returns 0 and FQUOTIENT returns randomhugenum (inconsistently)(insanely). {End Note} {note Interlisp-Vax also returns first arg for (IQUOTIENT X 0) and (IREMAINDER X 0)} {FnDef {FnName IREMAINDER} {FnArgs X Y} {Text Returns the remainder when {arg X} is divided by {arg Y}. Example: {lispcode (IREMAINDER 3 2) => 1} }} {FnDef {FnName IMOD} {FnArgs X Y} {Text Computes the integer modulus; this differs from {fn IREMAINDER} in that the result is always a non-negative integer in the range {lisp [0,{arg Y})}. {note Macroexpands into a LOGAND when y is a constant power of 2. An error if either x or y is not a number.} }} {FnDef {FnName IGREATERP} {FnArgs X Y} {Text {lisp T}, if {arg X} > {arg Y}; {lisp NIL} otherwise. }} {FnDef {FnName ILESSP} {FnArgs X Y} {Text {lisp T}, if {arg X} < {arg Y}; {lisp NIL} otherwise. }} {FnDef {FnName IGEQ} {FnArgs X Y} {Text {lisp T}, if {arg X} {GE} {arg Y}; {lisp NIL} otherwise. }} {FnDef {FnName ILEQ} {FnArgs X Y} {Text {lisp T}, if {arg X} {LE} {arg Y}; {lisp NIL} otherwise. }} {FnDef {FnName IMIN} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the minimum of {arg X{sub 1}}, {arg X{sub 2}}, {ellipsis}, {arg X{sub N}}. {lisp (IMIN)} returns the largest possible large integer, the value of {var MAX.FIXP}.{index MAX.FIXP Var} {note eventually, (IMIN) should return +infinity} }} {FnDef {FnName IMAX} {FnArgs X{SUB 1} X{SUB 2} ... X{SUB N}} {Type NOSPREAD} {Text Returns the maximum of {arg X{sub 1}}, {arg X{sub 2}}, {ellipsis}, {arg X{sub N}}. {lisp (IMAX)} returns the smallest possible large integer, the value of {var MIN.FIXP}.{index MIN.FIXP Var} {note eventually, (IMAX) should return -infinity} }} {FnDef {FnName IEQP} {FnArgs N M} {Text Returns {lisp T} if {arg N} and {arg M} are {fn EQ} or equal integers; {lisp NIL} otherwise. Note that {fn EQ} may be used if {arg N} and {arg M} are known to be {it small} integers. {fn IEQP} converts {arg N} and {arg M} to integers, e.g., {lisp (IEQP 2000 2000.3) => T}. Causes {lisp NON-NUMERIC ARG} error if either {arg N} or {arg M} are not numbers. }} {FnDef {FnName ZEROP} {FnArgs X} {Text {lisp (EQ {arg X} 0)}. Note: {fn ZEROP} should not be used for floating point numbers{index floating point numbers} because it uses {fn EQ}. Use {lisp (EQP {arg X} 0)} instead. }} {FnDef {FnName MINUSP} {FnArgs X} {Text Returns {lisp T} if {arg X} is negative; {lisp NIL} otherwise. Does not convert {arg X} to an integer, but simply checks the sign bit. }} {FnDef {FnName FIX} {FnArgs X} {Text If {arg X} is an integer, returns {arg X}. Otherwise, converts {arg X} to an integer by truncating fractional bits, e.g., {lisp (FIX 2.3) => 2}, {lisp (FIX -1.7) => -1}. Since {lisp FIX} is also a programmer's assistant command ({PageRef PAcom FIX}), typing {lisp FIX} directly to Interlisp will not cause the function {fn FIX} to be called. }} {Begin Note} Date: 8 Nov. 1981 10:17 am PST (Sunday) From: BURTON.PA Subject: FIX FIX does a truncation to get an integer from a floating point number. For most graphics applications one wants rounding rather than truncating. I would like to have the LLDISPLAY primitives round if they are given FLOATPs. How hard would it be to modify FIX to take a second argument (ROUNDFLG) which caused rounding and did it without the overhead of (FIX (FPLUS * .5))? Date: 8 Nov. 1981 1:00 pm PST (Sunday) From: vanMelle.PA Subject: Re: FIX In-reply-to: BURTON's message of 8 Nov. 1981 10:17 am PST (Sunday) Not too hard, I believe. When I first wrote the floating-point routines I asked if I should include "FIX with rounding", but there seemed no suitable place in the existing Interlisp semantics. A second arg to FIX is a possibility, but would, of course, not work in Interlisp-10. A completely separate function FIXR might thus be more suitable, which could macro to the right thing in Interlisp-10. Incidentally, FIX with rounding is not the same as (FIX (FPLUS arg .5)) if you allow negative arguments. I assume you want (FIX (FPLUS arg (if arg lt 0 then -.5 else .5)) Date: 8 NOV 1981 1354-PST From: ABELL.PA Subject: re: FIX Since we are using (I think) IEEE floating point standard, the options for rounding should probably adhere to that standard if not to hard. I seem to recall that they have 4 modes to handle all cases. May I suggest that you look at the standards document. Date: 9 NOV 1981 0028-PST From: KAPLAN.PA Subject: Rounding There is a (perhaps over-)generalized rounding operator that we developed for the IDL system that might be appropriate for inclusion in the standard system. (ROUND number tolerance) rounds number to the nearest tolerance unit. E.g., (ROUND number 1) is the standard FIXR, but (ROUND number 20) would round to the nearest 20, (ROUND number .01) would round to the nearest hundredth, etc. If tolerance is NIL, default is 1 (the nearest integer). If what we want is a fast integer round for use by internal system routines such as graphics, then a straightforward and efficienty round-to-integer (FIXR) would be enough. But if this is to be a user level routine, the extra utility of the above specification might be a desirable alternative (or separate capability if the flexibility would slow down the fast case too much). Date: 9 Nov. 1981 12:56 pm PST (Monday) From: Masinter.PA Subject: Re: FIX Common lisp in fact has a variety of rounding modes. I think that a great deal of thought went into the rounding modes and that their design is reasonable. They have used CEIL, FLOOR, TRUNC, and ROUND to specify the rounding modes. The definitions of CEIL and FLOOR are not incompatible with the macros we have in MODARITH-- the functions take a second (optional) argument which is the divisor; in the one-argument case, divisor defaults to "1". Interlisp's FIX corresponds to TRUNC, i.e., truncate toward 0. For now, we can think about including ROUND in standard Interlisp; later we might consider extending FLOOR, CEIL, etc. Date: 9 NOV 1981 1811-PST From: KAPLAN.PA Subject: Code for ROUND The IDL code for (ROUND N TOL) is (if (AND TOL TOL~=1 then (TIMES TOL (FIXR (FQUOTIENT N TOL))) else (FIXR N)) where FIXR is the standardd (FIX N +/- .5) and TIMES is not FTIMES. Is there an efficient implementation of this that avoids internal boxing? Date: 9 Nov. 1981 10:17 pm PST (Monday) From: vanMelle.PA Subject: Re: Code for ROUND Only for values of TOL that are powers of two (not very useful except for the special case TOL=1). {End Note} {FnDef {FnName GCD} {FnArgs X Y} {Text Returns the greatest common divisor of {arg X} and {arg Y}, e.g., {lisp (GCD 72 64)}={lisp 8}. }} {index *END* integer arithmetic} }{End SubSec Integer Arithmetic} {Begin SubSec Logical Arithmetic Functions} {Title Logical Arithmetic Functions} {Text {FnDef {FnName LOGAND} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the logical AND of all its arguments, as an integer. Example: {lispcode (LOGAND 7 5 6) => 4} }} {FnDef {FnName LOGOR} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the logical OR of all its arguments, as an integer. Example: {lispcode (LOGOR 1 3 9) => 11} }} {FnDef {FnName LOGXOR} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the logical exclusive OR of its arguments, as an integer. Example: {lispcode (LOGXOR 11 5) => 14} {lispcode (LOGXOR 11 5 9) <=> (LOGXOR 14 9) => 7} }} {FnDef {FnName LSH} {FnArgs X N} {Text (arithmetic) "Left Shift." Returns {arg X} shifted left {arg N} places, with the sign bit unaffected. {arg X} can be positive or negative. If {arg N} is negative, {arg X} is shifted {it right} {arg -N} places. }} {FnDef {FnName RSH} {FnArgs X N} {Text (arithmetic) "Right Shift." Returns {arg X} shifted right {arg N} places, with the sign bit unaffected, and copies of the sign bit shifted into the leftmost bit. {arg X} can be positive or negative. If {arg N} is negative, {arg X} is shifted {it left} {arg -N} places. Warning: Be careful if using {fn RSH} to simulate division; {fn RSH}ing a negative number is not generally equivalent to deviding by a power of two. }} {FnDef {FnName LLSH} {FnArgs X N} {Text "Logical Left Shift." }} {FnDef {FnName LRSH} {FnArgs X N} {Text "Logical Right Shift." }} {FnDef {FnName INTEGERLENGTH} {FnArgs N} {Text Returns the number of bits needed to represent {arg N} (coerced to a {lisp FIXP}). This is equivalent to: 1+floor[log2[abs[{arg N}]]]. {lisp (INTEGERLENGTH 0)} = 0. }} {FnDef {FnName POWEROFTWOP} {FnArgs N} {Text Returns non-{lisp NIL} if {arg N} (coerced to a {lisp FIXP}) is a power of two. }} {FnDef {FnName EVENP} {FnArgs X Y} {Type NOSPREAD} {Text If {arg Y} is not given, equivalent to {lisp (ZEROP (IMOD {arg X} 2))}; otherwise equivalent to {lisp (ZEROP (IMOD {arg X} {arg Y}))}. {note [CommonLisp specifies an error on non-numeric data, thus defaulting the second argument is different than supplying a NIL for it]} }} {FnDef {FnName ODDP} {FnArgs X Y} {Type NOSPREAD} {Text Equivalent to {lisp (NOT (EVENP {arg X} {arg Y}))}. }} The difference between a logical and arithmetic right shift lies in the treatment of the sign bit. Logical shifting treats it just like any other bit; arithmetic shifting will not change it, and will "propagate" rightward when actually shifting rightwards. Note that shifting (arithmetic) a negative number "all the way" to the right yields -1, not 0. The following "logical" arithmetic functions are derived from Common Lisp, and have both macro and function definitions (the macros are for speed in running of compiled code). The following code equivalences are primarily for definitional purposes, and should not be considered an implementation (especially since the real implementation tends to be faster and less "consy" than would be apparent from the code here). {it Note: The following logical functions are currently only implemented in Interlisp-D. } {FnDef {Name LOGNOT} {Args N} {Text {lisp (LOGXOR {arg N} -1)} }} {FnDef {Name BITTEST} {Args N MASK} {Text {lisp (NOT (ZEROP (LOGAND {arg N} {arg MASK})))} }} {FnDef {Name BITCLEAR} {Args N MASK} {Text {lisp (LOGAND {arg N} (LOGNOT {arg MASK}))} }} {FnDef {Name BITSET} {Args N MASK} {Text {lisp (LOGOR {arg N} {arg MASK})} }} {FnDef {Name MASK.1'S} {Args POSITION SIZE} {Text {lispcode (LLSH (SUB1 (EXPT 2 {arg SIZE})) {arg POSITION})} }} {FnDef {Name MASK.0'S} {Args POSITION SIZE} {Text {lisp (LOGNOT (MASK.1'S {arg POSITION} {arg SIZE}))} }} {FnDef {Name LOADBYTE} {Args N POSITION SIZE} {Text {lispcode (LOGAND (LRSH {arg N} {arg POSITION}) (MASK.1'S 0 {arg SIZE}))} }} {FnDef {Name DEPOSITBYTE} {Args N POSITION SIZE BYTE} {Text {lispcode (LOGOR (BITCLEAR {arg N} (MASK.1'S {arg POSITION} {arg SIZE})) (LLSH (LOGAND {arg BYTE} (MASK.1'S 0 {arg SIZE})) {arg POSITION}))} }} {FnDef {Name ROT} {Args X N FIELDSIZE} {Text "Rotate bits in field". This is a slight extension of the CommonLisp {lisp ROT} function. It performs a bitwise left-rotation of the integer {arg X}, by {arg N} places, within a field of {arg FIELDSIZE} bits wide. Bits being shifted out of the position selected by {lisp (EXPT 2 (SUB1 {arg FIELDSIZE}))} will flow into the "units" position. The optional argument {arg FIELDSIZE} defaults to the "cell" size (the integerlength of the current maximum {lisp FIXP}), and must either be a positive integer, or else be one of the litatoms {lisp CELL} or {lisp WORD}. In the latter two cases the appropriate numerical values are respectively substituted. A macro optimizes the case where {arg FIELDSIZE} is {lisp WORD} and {arg N} is 1. }} The notions of position and size can be combined to make up a "byte specifier", which is constructed by the macro {mac BYTE} [note reversal of arguments as compare with above functions]: {MacDef {Name BYTE} {Args SIZE POSITION} {Text Constructs and returns a "byte specifier" containing {arg SIZE} and {arg POSITION}. }} {note [currently, byte-specs are implemented as a typerecord; Common Lisp leaves unspecified whether there are any range limitations on "size" or "pos"]} {MacDef {Name BYTESIZE} {Args BYTESPEC} {Text Returns the {arg SIZE} componant of the "byte specifier" {arg BYTESPEC}. }} {MacDef {Name BYTEPOSITION} {Args BYTESPEC} {Text Returns the {arg POSITION} componant of the "byte specifier" {arg BYTESPEC}. }} {MacDef {Name LDB} {Args BYTESPEC VAL} {Text {lispcode (LOADBYTE {arg VAL} (BYTEPOSITION {arg BYTESPEC}) (BYTESIZE {arg BYTESPEC}))} }} {MacDef {Name DPB} {Args N BYTESPEC VAL} {Text {lispcode (DEPOSITBYTE {arg VAL} (BYTEPOSITION {arg BYTESPEC}) (BYTESIZE {arg BYTESPEC}) {arg N})} }} }{End SubSec Logical Arithmetic Functions} {Begin SubSec Floating Point Arithmetic} {Title Floating Point Arithmetic} {Text {index *PRIMARY* floating point numbers} A floating point number is input as a signed integer, followed by a decimal point, followed by another sequence of digits called the fraction, followed by an exponent (represented by {lisp E}{index *PRIMARY* E (in a floating point number)} followed by a signed integer) and terminated by a delimiter. Both signs are optional, and either the fraction following the decimal point, or the integer preceding the decimal point may be omitted.{index . (in a floating point number)} One or the other of the decimal point or exponent may also be omitted, but at least one of them must be present to distinguish a floating point number from an integer. For example, the following will be recognized as floating point numbers: {lispcode 5. 5.00 5.01 .3 5E2 5.1E2 5E-3 -5.2E+6} Floating point numbers are printed using the format control specified by the function {fn FLTFMT} ({PageRef Fn FLTFMT}). {fn FLTFMT} is initialized to {lisp T}, or free format. For example, the above floating point numbers would be printed free format as: {lispcode 5.0 5.0 5.01 .3 500.0 510.0 .005 -5.2E6} Floating point numbers are created by the read program when a "{lisp .}" or an {lisp E} appears in a number, e.g., {lisp 1000} is an integer, {lisp 1000.} a floating point number, as are {lisp 1E3} and {lisp 1.E3}. Note that {lisp 1000D}, {lisp 1000F}, and {lisp 1E3D} are perfectly legal literal atoms. Floating point numbers are also created by {fn PACK} and {fn MKATOM}, and as a result of arithmetic operations. {fn PRINTNUM} ({PageRef Fn PRINTNUM}) permits greater controls on the printed appearance of floating point numbers, allowing such things as left-justification, suppression of trailing decimals, etc. The floating point number range is stored in the following variables: {VarDef {Name MIN.FLOAT} {Text The smallest possible floating point number. }} {VarDef {Name MAX.FLOAT} {Text The largest possible floating point number. }} {index *BEGIN* floating point arithmetic} All of the functions described below work on floating point numbers. Unless specified otherwise, if given an integer, they first convert the number to a floating point number, e.g., {lisp (FPLUS 1 2.3) <=> (FPLUS 1.0 2.3) => 3.3}; if given a non-numeric argument, they generate an error, {lisp NON-NUMERIC ARG.}{index NON-NUMERIC ARG Error} {FnDef {FnName FPLUS} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text {arg X{sub 1}} + {arg X{sub 2}} + {ellipsis} + {arg X{sub N}} }} {FnDef {FnName FMINUS} {FnArgs X} {Text - {arg X} }} {FnDef {FnName FDIFFERENCE} {FnArgs X Y} {Text {arg X} - {arg Y} }} {FnDef {FnName FTIMES} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text {arg X{sub 1}} * {arg X{sub 2}} * {ellipsis} * {arg X{sub N}} }} {FnDef {FnName FQUOTIENT} {FnArgs X Y} {Text {arg X} / {arg Y} }} {FnDef {FnName FREMAINDER} {FnArgs X Y} {Text Returns the remainder when {arg X} is divided by {arg Y}. Equivalent to: {lispcode (FDIFFERENCE {arg X} (FTIMES {arg Y} (FIX (FQUOTIENT {arg X} {arg Y}))))} Example: {lispcode (FREMAINDER 7.5 2.3) => 0.6} }} {FnDef {FnName MINUSP} {FnArgs X} {Text {lisp T}, if {arg X} is negative; {lisp NIL} otherwise. Works for both integers and floating point numbers. }} {FnDef {FnName FGREATERP} {FnArgs X Y} {Text {lisp T}, if {arg X} > {arg Y}, {lisp NIL} otherwise. }} {FnDef {FnName FLESSP} {FnArgs X Y} {Text {lisp T}, if {arg X} < {arg Y}, {lisp NIL} otherwise. }} {FnDef {FnName FEQP} {FnArgs X Y} {Text Returns {lisp T} if {arg N} and {arg M} are equal floating point numbers; {lisp NIL} otherwise. {fn FEQP} converts {arg N} and {arg M} to floating point numbers.Causes {lisp NON-NUMERIC ARG} error if either {arg N} or {arg M} are not numbers. }} {FnDef {FnName FMIN} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the minimum of {arg X{sub 1}}, {arg X{sub 2}}, {ellipsis}, {arg X{sub N}}. {lisp (FMIN)} returns the largest possible floating point number, the value of {var MAX.FLOAT}.{index MAX.FLOAT Var} }} {FnDef {FnName FMAX} {FnArgs X{SUB 1} X{SUB 2} ... X{SUB N}} {Type NOSPREAD} {Text Returns the maximum of {arg X{sub 1}}, {arg X{sub 2}}, {ellipsis}, {arg X{sub N}}. {lisp (FMAX)} returns the smallest possible floating point number, the value of {var MIN.FLOAT}.{index MIN.FLOAT Var} }} {FnDef {FnName FLOAT} {FnArgs X} {Text Converts {arg X} to a floating point number. Example: {lispcode (FLOAT 0) => 0.0} }} {index *END* floating point arithmetic} }{End SubSec Floating Point Arithmetic} {Begin SubSec Mixed Arithmetic} {Title Mixed Arithmetic} {Text {index *BEGIN* mixed arithmetic} The functions in this section are "generic" floating point arithmetic functions. If any of the arguments are floating point numbers, they act exactly like floating point functions, and float all arguments, and return a floating point number as their value. Otherwise, they act like the integer functions. If given a non-numeric argument, they generate an error, {lisp NON-NUMERIC ARG}.{index NON-NUMERIC ARG Error} {FnDef {FnName PLUS} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text {arg X{sub 1}} + {arg X{sub 2}} + {ellipsis} + {arg X{sub N}}. }} {FnDef {FnName MINUS} {FnArgs X} {Text - {arg X} }} {FnDef {FnName DIFFERENCE} {FnArgs X Y} {Text {arg X} - {arg Y} }} {FnDef {FnName TIMES} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text {arg X{sub 1}} * {arg X{sub 2}} * {ellipsis} * {arg X{sub N}} }} {FnDef {FnName QUOTIENT} {FnArgs X Y} {Text If {arg X} and {arg Y} are both integers, returns {lisp (IQUOTIENT {arg X} {arg Y})}, otherwise {lisp (FQUOTIENT {arg X} {arg Y})}. }} {FnDef {FnName REMAINDER} {FnArgs X Y} {Text If {arg X} and {arg Y} are both integers, returns {lisp (IREMAINDER {arg X} {arg Y})}, otherwise {lisp (FREMAINDER {arg X} {arg Y})}. }} {FnDef {FnName GREATERP} {FnArgs X Y} {Text {lisp T}, if {arg X} > {arg Y}, {lisp NIL} otherwise. }} {FnDef {FnName LESSP} {FnArgs X Y} {Text {lisp T} if {arg X} < {arg Y}, {lisp NIL} otherwise. }} {FnDef {FnName GEQ} {FnArgs X Y} {Text {lisp T}, if {arg X} {GE} {arg Y}, {lisp NIL} otherwise. }} {FnDef {FnName LEQ} {FnArgs X Y} {Text {lisp T}, if {arg X} {LE} {arg Y}, {lisp NIL} otherwise. }} {FnDef {FnName MIN} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the minimum of {arg X{sub 1}}, {arg X{sub 2}}, {ellipsis}, {arg X{sub N}}. {lisp (MIN)} returns the value of {var MAX.INTEGER}. }} {FnDef {FnName MAX} {FnArgs X{SUB 1} X{SUB 2} {ellipsis} X{SUB N}} {Type NOSPREAD} {Text Returns the maximum of {arg X{sub 1}}, {arg X{sub 2}}, {ellipsis}, {arg X{sub N}}. {lisp (MAX)} returns the value of {var MIN.INTEGER}. }} {FnDef {FnName ABS} {FnArgs X} {Text {arg X} if {arg X} > 0, otherwise -{arg X}. {fn ABS} uses {fn GREATERP} and {fn MINUS}, (not {fn IGREATERP} and {fn IMINUS}). }} {index *END* mixed arithmetic} }{End SubSec Mixed Arithmetic} {Begin SubSec Special Functions} {Title Special Functions} {text {FnDef {FnName EXPT} {FnArgs M N} {Text Returns {arg M}↑{arg N}. If {arg M} is an integer and {arg N} is a positive integer, returns an integer, e.g, {lisp (EXPT 3 4) => 81}, otherwise returns a floating point number. If {arg M} is negative and {arg N} fractional, an error is generated, {lisp ILLEGAL EXPONENTIATION}.{index ILLEGAL EXPONENTIATION Error} If {arg N} is floating and either too large or too small, an error is generated, {index VALUE OUT OF RANGE EXPT Error}{lisp VALUE OUT OF RANGE EXPT}. }} {FnDef {FnName SQRT} {FnArgs N} {Text Returns the square root of {arg N} as a floating point number. {arg N} may be fixed or floating point. Generates an error if {arg N} is negative.{index SQRT OF NEGATIVE VALUE Error} }} {FnDef {FnName LOG} {FnArgs X} {Text Returns the natural logarithm of {arg X} as a floating point number. {arg X} can be integer or floating point. }} {FnDef {FnName ANTILOG} {FnArgs X} {Text Returns the floating point number whose logarithm is {arg X}. {arg X} can be integer or floating point. Example: {lispcode (ANTILOG 1) = e => 2.71828...} }} {FnDef {FnName SIN} {FnArgs X RADIANSFLG} {Text Returns the sine of {arg X} as a floating point number. {arg X} is in degrees unless {arg RADIANSFLG}={lisp T}. }} {FnDef {FnName COS} {FnArgs X RADIANSFLG} {Text Similar to {fn SIN}. }} {FnDef {FnName TAN} {FnArgs X RADIANSFLG} {Text Similar to {fn SIN}. }} {FnDef {FnName ARCSIN} {FnArgs X RADIANSFLG} {Text {arg X} is a number between -1 and 1 (or an error is generated{index ARCSIN: ARG NOT IN RANGE Error}). The value of {fn ARCSIN} is a floating point number, and is in degrees unless {arg RADIANSFLG}={lisp T}. In other words, if {lisp (ARCSIN {arg X} {arg RADIANSFLG})}={arg Z} then {lisp (SIN {arg Z} {arg RADIANSFLG})}={arg X}. The range of the value of {fn ARCSIN} is -90 to +90 for degrees, -{pi}/2 to {pi}/2 for radians. }} {FnDef {FnName ARCCOS} {FnArgs X RADIANSFLG} {Text Similar to {fn ARCSIN}. Range is 0 to 180, 0 to {pi}.{index ARCCOS: ARG NOT IN RANGE Error} }} {FnDef {FnName ARCTAN} {FnArgs X RADIANSFLG} {Text Similar to {fn ARCSIN}. Range is 0 to 180, 0 to {pi}. }} {FnDef {FnName ARCTAN2} {FnArgs Y X RADIANSFLG} {Text Computes {lisp (ARCTAN (FQUOTIENT {arg Y} {arg X}) {arg RADIANSFLG})}, and returns a corresponding value in the range -180 to 180 (or -{pi} to {pi}), i.e. the result is in the proper quadrant as determined by the signs of {arg X} and {arg Y}. }} {FnDef {FnName RAND} {FnArgs LOWER UPPER} {Text Returns a pseudo-random number between {arg LOWER} and {arg UPPER} inclusive, i.e., {fn RAND} can be used to generate a sequence of random numbers.{index random numbers} If both limits are integers, the value of {fn RAND} is an integer, otherwise it is a floating point number. The algorithm is completely deterministic, i.e., given the same initial state, {fn RAND} produces the same sequence of values. The internal state of {fn RAND} is initialized using the function {fn RANDSET} described below. }} {FnDef {FnName RANDSET} {FnArgs X} {Text Returns the internal state of {fn RAND}. If {arg X}={lisp NIL}, just returns the current state. If {arg X}={lisp T}, {fn RAND} is initialized using the clocks, and {fn RANDSET} returns the new state. Otherwise, {arg X} is interpreted as a previous internal state, i.e., a value of {fn RANDSET}, and is used to reset {fn RAND}. For example, {lispcode ← (SETQ OLDSTATE (RANDSET)) ... ← (for X from 1 to 10 do (PRIN1 (RAND 1 10))) 2847592748NIL ← (RANDSET OLDSTATE) ... ← (for X from 1 to 10 do (PRIN1 (RAND 1 10))) 2847592748NIL} }} {index *END* arithmetic functions} }{End SubSec Special Functions} {Begin Note} Date: 12 DEC 1980 0121-PST From: VANMELLE.PA Subject: number boxes Dick has made a plea that the floating functions I write allow you to reuse number boxes if you want. I could certainly have FPLUS2, FDIFFERENCE, FTIMES2, FQUOTIENT take an optional third arg which was a floating box to reuse (or have them call subfunctions with that property), much in the way other fns take scratch string ptrs or stack ptrs. I sense that you frown on this, and I would agree it is inelegant. However, there seems to be a need for such things. Suggestions? Same question for the integer fns, as long as I'm writing IQUOTIENT and IREMAINDER now. Date: 15 DEC 1980 1052-PST From: KAPLAN.PA Subject: Boxing I think all binary arithmetic operators should take 3 arguments, the 2 operands and optionally a box to smash the result into. If the result box is given, it should be smashed, even if the actually result is a smallp. With this set of functions, it will be relatively easy to put macros on IBOX and FBOX that will make the boxing behavior under those functions come very close to approximating the pdp-10's behavior. In particular, IDL should be OK. P.S. I don't think that any of the functions should take HINUM and LONUM pairs, but just the original operands. {End Note} {Begin Note} should MAKERATIONAL be documented?? no says lmm Date: 23 June 1982 12:10 am PDT (Wednesday) From: vanMelle.PA Subject: MAKERATIONAL (MAKERATIONAL x) -> (numerator . denominator) Date: 25 JUN 1982 2135-PDT From: KAPLAN.PA Subject: MAKERATIONAL bug MAKERATIONAL(.00001) yields (2748779 . 0) which is clearly wrong (and happens to be the number of micas per meter). MAKERATIONAL(.1) yields (13421773 . 134217728) which is mathematically correct, altho (1 . 10) would have been more revealing. Date: 26 June 1982 6:52 pm PDT (Saturday) From: vanMelle.PA Subject: Re: MAKERATIONAL bug Sorry about that. MAKERATIONAL(.00001) now fixed (I had missed one of the overflow cases). As for MAKERATIONAL(.1), if anyone has an algorithm for rationalizing binary floating-point numbers using denominators that are not powers of two, let me know. Date: 28 June 1982 8:33 am PDT (Monday) From: JonL.PA Subject: Re: MAKERATIONAL bug I do. That is, Guy Steele and I worked on the problem of "perfect" floating point printout, defined to be printing enough ** decimal ** digits so that the exact binary representation would be reconstructed upon read-in. Rational approximation is precisely the same process. There's also a paper by B.K.P. Horn of the M.I.T. A.I. Lab which shows some interesting algorithms for doing floating-point by rational approximations (for PDP11 etc where there is no native floating-point.) On the other hand, this is the sort of area that one could spend a week or so hacking around in. Could it wait til November for further work? {End Note} {Begin Note} Date: 9-Sep-82 9:39:44 PDT (Thursday) From: Masinter.PA Subject: Re: a stock answer to the IEEE issue Stock answer for 8-Sept-82: We support IEEE Floating point (32-bit mode) as our internal format for Lisp floating point operations. We will shortly be releasing versions of Interlisp-D which do the floating point operations in microcode (both Dolphin and Dorado.) (These versions are working internally, but are still in alpha-test.) The current release of Interlisp-D supports IEEE Floating point macrocode. IEEE format is documented in papers available from UC Berkeley. (I don't have references handy, but the Library can probably obtain the papers.) Interlisp-D code is exactly compatible with the IEEE floating point supported by Mesa. (The Lisp microcode was borrowed from Mesa.) {End Note} {index *END* numbers} }{End SubSec Numbers and Arithmetic Functions}