REF NUMBERS John Gibson Feb 1995COPYRIGHT University of Sussex 1995. All Rights Reserved.>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<PROCEDURES ON NUMBERS>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< This file describes all the Poplog number types and procedures to operate on them. For information on the textual representation of different kinds of numbers in Pop-11 see REF * ITEMISE All the Poplog arithmetic operations described in this file check the types of their arguments at run time in order to determine what to do. Fast, non-checking (hence more efficient) integer operations are described in REF * FASTPROCSCONTENTS - (Use <ENTER> g to access required sections)1 Overview1.1 Note on Terminology 1.2 Fast integer operations 1.3 Computation on Real Numbers 1.4 Complex Numbers 1.5 Conventions for Formal Parameters of Procedures2 Predicates Relating to Numbers3 Comparisons on Numbers4 Number Representation5 Arithmetic Operations6 Rational and Integer Specific Operations7 Complex Specific Operations8 Mathematical Functions9 Trigonometric Functions10 Bitwise/Logical Integer Operations11 Random Numbers12 Floating_Point Utilities13 Numeric Constants13.1 Integer 13.2 Floating-Point14 Miscellaneous-----------1 Overview-----------From Version 12 of Poplog, support is provided for all the numerical data types and associated functions specified by the Common LISP standard. This includes integers, bigintegers, decimals, ddecimals, ratios and complex numbers. This REF file describes the Pop-11 interface to these facilities, which, while differing in some minor respects from the Common LISP standard, (and of course employing different names for procedures in many cases), is essentially an upward-compatible version of it. For a description of the Clisp version see Guy L. Steele,, Chapter 12. For information on the textual representation of different kinds of numbers in Pop-11 see REF * ITEMISE All the Poplog arithmetic operations described in this REF file check the types of their arguments at run time in order to determine what to do. Fast, non-checking (hence more efficient) integer operations are described in REF * FASTPROCS 1.1 Note on Terminology ------------------------ In this document the term 'integer' means either a simple integer or a biginteger, except where explicitly qualified as one or the other; 'integral' means the same in the nominal sense, or 'integer-valued' as an adjective. Similarily, 'real' means 'non-complex', or 'non-complex number' - it does NOT carry the meaning of 'floating-point number' used by some programming languages. 1.2 Fast integer operations ---------------------------- All Poplog arithmetic operations described below check the types of their arguments at run time in order to determine what to do. This gives great flexibility in writing generic procedures, but can mean that efficiency is sacrificed. As a partial solution fast, non-checking integer operations are provided. These are described in REF * FASTPROCS Further information concerning efficiency is available in HELP * EFFICIENCY 1.3 Computation on Real Numbers -------------------------------- Overall, the number types in Poplog provide three classes of representation: ¤ rational (simple integers, bigintegers and ratios) ¤ simple floating-point (decimals) ¤ double-length floating-point (ddecimals) These classes are orthogonal in the sense that a given real number has exactly one representation in each format (the representation being exact for rational, and approximate for floating-point). In particular for rationals, this implies that integers, bigintegers and ratios are mutually disjoint in terms of the numbers they represent, and that no two ratios represent the same number unless they have the same numerator and denominator. In other words, a ratio is always reduced to its lowest common terms, by dividing numerator and denominator by their greatest common divisor; if this makes the denominator equal to 1, the result is the integer numerator (this is the rule of 'rational canonicalisation'). Any integral result from a computation will always produce a simple integer (rather than a biginteger) if it can be so represented. With very few exceptions, numerical procedures are 'generic', that is, will accept any kind of numbers as arguments. For all procedures that perform a rational-type function (i.e. excluding 'irrational' or 'transcendental' functions likeCommon LISP: The Languagesqrt,log, etc), rational argument(s) will cause the computation to be done using rational arithmetic, and the result will be rational. Otherwise, when the function is irrational, or one or more of the arguments is floating-point, all arguments are converted to double-length floating-point and the computation performed with double-float arithmetic (this is the rule of 'floating-point contagion'). The result will be a floating-point whose actual format depends on the value of the variablepopdprecision(see the description of this below). 1.4 Complex Numbers -------------------- Complex numbers always have both real and imaginary parts of the same representation class, and so may similarily be sub-divided into rational complex, simple-float-complex and double-float-complex. Aside from those irrational functions that can produce a complex result from a real argument (sqrtapplied to a negative real, for example), the only way of constructing complex numbers is with the operators+:and-:('plus i times' and 'minus i times'). These obey the same rules as for real arithmetic: with both arguments rational or rational-complex the result is a rational-complex; if either argument is floating or float-complex, the result is a float-complex whose format depends onpopdprecision. The only rider to this is the rule of 'rational-complex canonicalisation', which prevents the production of a rational-complex number with a 0 imaginary part. Instead, the result is just the real part of the number. Note that this does not apply to float-complex numbers, which can have a 0.0 imaginary part. Most numerical procedures allow complex or mixed real and complex arguments. In a similar way to the rational/float distinction for the real case, computations are done in real arithmetic producing a real result if all arguments are real, or otherwise all arguments are converted to complex and the operation performed in complex to give a complex result (the rule of 'complex contagion'). 1.5 Conventions for Formal Parameters of Procedures ---------------------------------------------------- Except in those cases where the arguments or results of a procedure are sufficiently complicated to require names that describe their function, rather than just their type, the following conventions are used: Convention Data type ---------- ---------itemanythingboola boolean,trueorfalsenum,num1,num2any number, including complexreal,real1,real2any number except complexNa simple integerint,int1,int2any integer, simple or bigfloat,float1,float2a decimal or ddecimal---------------------------------2 Predicates Relating to Numbers---------------------------------isinteger(item) ->bool[] Returnsproceduretrueifitemis a simple integer,falseotherwise.isbiginteger(item) ->bool[] Returnsproceduretrueifitemis a biginteger,falseotherwise.isintegral(item) ->bool[] Returnsproceduretrueifitemis a simple integer or a biginteger,falseotherwise.isratio(item) ->bool[] Returnsproceduretrueifitemis a ratio,falseotherwise.isrational(item)->bool[] Returnsproceduretrueifitemis a simple integer, a biginteger or a ratio, andfalseotherwise.isdecimal(item) ->bool[] Returnsproceduretrueifitemis a decimal or a ddecimal,falseotherwise.issdecimal(item) ->bool[] Returnsproceduretrueifitemis a simple decimal,falseotherwise.isddecimal(item) ->bool[] Returnsproceduretrueifitemis a ddecimal,falseotherwise.isreal(item) ->bool[] Returnsproceduretrueifitemis any number except a complex,falseotherwise.iscomplex(item) ->bool[] Returnsproceduretrueifitemis a complex number,falseotherwise.isnumber(item) ->bool[] Returnsproceduretrueifitemis any kind of number,falseotherwise.-------------------------3 Comparisons on Numbers-------------------------num1=num2->bool[]operator 7num1/=num2->bool[] On numbers, these operators compare their arguments for mathematical equality and inequality respectively. Different types of rationals (integers, bigintegers and ratios) can never represent the same number and so can never be equal; comparisons between floating-point (decimals and ddecimals) and between floating-point and rationals first convert both arguments to double float. The same rules apply to the comparison of the real and imaginary parts of a complex numbers. Note that a real number compared with a complex number will be equal only if the complex number is a float-complex with 0.0 imaginary part (since the imaginary part of a rational complex must always be non-zero). See also REF * DATA, HELP * EQUALoperator 7real1<real2->bool[]operator 6real1<=real2->bool[]operator 6real1>real2->bool[]operator 6real1>=real2->bool[] These operators compare their first argument to be respectively less than, less than or equal, greater than, and greater than or equal to their second argument, where comparisons between different number types are performed as foroperator 6=and/=. Both arguments must be real numbers.max(real1,real2)->greatest[]proceduremin(real1,real2)->least[]proceduremaxreturns the greatest of its two arguments andminthe least, where 'greatest' means closest to positive infinity, and 'least' means closest to negative infinity. Both arguments must be real numbers.num1==#num2->bool[] Returnsoperator 7trueifnum1andnum2are identical (i.e. ==), or numbers of the same representational type and numeric value. Decimals and ddecimals are NOT considered to be of the same type. Two complex numbers are==#if their real parts are ==# and their imaginary parts are==#.------------------------4 Number Representation------------------------popdprecision ->bool_or_word[]variablebool_or_word-> popdprecisionThe value of this variable controls the production of results from floating-point computations, in combination with the types of the arguments supplied to the relevant procedure. In the following, "decimal" includes decimal-complex and "ddecimal" includes ddecimal-complex (when a complex floating-point operation is involved): Value Effect ----- ------falseSimple decimal results are always produced. the word A ddecimal result is produced only if one or "ddecimal" other (or the only) argument was ddecimal. (This is the behaviour specified by Common LISP.) any other Same as the previous case, except that a ddecimal result is also produced when neither argument is a simple decimal, i.e. all argument(s) are ddecimal or rational. (Note that in NO case is there an increase in precision of floating point computations if all arguments are simple decimal to start with.) The default value ofpopdprecisionisfalse.pop_reduce_ratios ->bool[]variablebool-> pop_reduce_ratiosIt was stated above that a ratio result is always reduced to its lowest common terms (and therefore to an integral result if the denominator becomes 1). However, in situations where a rational computation is being performed that involves a number of intermediate results, the continual reduction of intermediate values can be time-consuming; this boolean variable is therefore provided to enable reduction to be turned off (by setting itfalse). Although unreduced ratios will give correct results in computation, comparisons on them may not do so (e.g. 2/2 will not come out = to 1), so this facility must be used CAREFULLY:pop_reduce_ratiosshould only be setfalseinside a procedure that has it as a dynamic local, and you should always ensure that the variable is returned totruebefore producing the final result of a computation.number_coerce(num1,to_num) ->num2[] Produces a numberprocedurenum2which is the numbernum1converted to the representation class (i.e. rational, simple decimal or double-float ddecimal) of the numberto_num. Firstly, no new number is constructed unless necessary; thus if the class ofnum1already matches that ofto_num,num1is returned unchanged. Otherwise, conversion from one class to another proceeds. Conversion from rational form to floating-point form, or from one float format to the other, takes place in the obvious way. For conversion from floating-point to rational, the float is assumed to be completely accurate, and a mathematically equal rational number is returned. Ifnum1is complex, thennum2is the complex number got by applyingnumber_coercerecursively to the real and imaginary parts ofnum1, i.e. number_coerce(realpart(num1),to_num) +: number_coerce(imagpart(num1),to_num) ->num2If the second argumentto_numis itself complex, thennum1is coerced to a complex number of the same representation class, i.e. the result is computed as realpart(to_num) ->to_num; number_coerce(realpart(num1),to_num) +: number_coerce(imagpart(num1),to_num) ->num2whereimagpartwill fill in an appropriate zero value for the imaginary part ifnum1is real.------------------------5 Arithmetic Operations------------------------num1+num2->num3[]operator 5num1-num2->num3[]operator 5num1*num2->num3[]operator 4num1/num2->num3[] These operators respectively add, subtract, multiply and divide their arguments, which may be any numbers. The type of the result depends on the rules of floating-point and complex contagion as described above. In particular, note that dividing one integer by another produces a ratio when the result is not exact.operator 4-num1->num2[] As a prefix operator,operator 1-is equivalent tonegate(num1).divid//divis->(rem,quot) []operator 4dividdivdivis->quot[]operator 2dividremdivis->rem[] The two results returned by the operatoroperator 2//are defined by intof(divid/divis) ->quotanddivid- (quot*divis) ->remwhere the arguments may be any numbers, including complex. The two results may be obtained separately withdiv(quotonly) andrem(remonly).dividmoddivis->mod[] Returnsoperator 2dividmodulodivis, where both numbers must be real. This is defined asdividremdivis->rem; if (divis> 0 andrem< 0) or (divis< 0 andrem>= 0) thenrem+divis->modelserem->modendif (i.e. the result always has the same sign as the divisor).intof(num) ->int[] Forprocedurenumreal,intoftruncates its argument to an integer, i.e. it returns the integer of the same sign asnumand with the largest magnitude such that abs(int) <= abs(num). For a complex number, the result is the integral complex number obtained by applyingintofto its parts, i.e. intof(realpart(num)) +: intof(imagpart(num))fracof(num) ->frac[] The fractional part ofprocedurenum, defined asnum- intof(num)round(num) ->int[] Forprocedurenumreal, roundsnumto an integer by taking intof(num+1/2) ifnumis positive, or intof(num-1/2) otherwise. Ifnumis complex, the result is round(realpart(num)) +: round(imagpart(num))abs(num) ->real[] Returns the absolute value ofprocedurenum, which (except for complex) will always be a number of the same type. For any complexnum, the result will be a floating-point real, computed as sqrt( realpart(num)**2 + imagpart(num)**2 )negate(num1)->num2[] Returns the negation ofprocedurenum1, which will always be a number of the same type.sign(num)->sign[] Forprocedurenumreal,signreturns -1, 0 or 1 of the same type asnum, depending on whethernumis negative, zero or positive. Ifnumis complex, the result is a floating-point complex number such that abs(sign) = 1.0, phase(sign) = phase(num)-------------------------------------------6 Rational and Integer Specific Operations-------------------------------------------checkinteger(item,low_int,hi_int) [] Checksprocedureitemto be a (simple) integer within the range specified by lower boundlow_intand upper boundhi_int(inclusive). Either or both bounds may befalseto indicate no upper or lower limit. If all conditions are satisfied the procedure returns with no action, otherwise a mishap occurs. (Note that *fi_checkis a faster version that does not check its second and third arguments are integers, and also returnsitemif it is an integer within the given range.)gcd_n(int1,int2, ...,intN,N) ->gcd[] Computes the greatest common divisor of the all theprocedureNintegersint1,int2, ...,intN, where the numberNitself (a simple integer >= 0) appears as the rightmost argument. IfN= 0, thengcd= 0; ifN= 1, thengcd=int1.lcm_n(int1,int2, ...,intN,N) ->lcm[] Computes the least common multiple of the all theprocedureNintegersint1,int2, ...,intN, where the numberNitself (a simple integer >= 0) appears as the rightmost argument. IfN= 0, thenlcm= 1; ifN= 1, thenlcm=int1.destratio(rat) -> (numerator,denominator)[]procedurenumerator(rat) ->numerator[]proceduredenominator(rat) ->denominator[] These procedures return theprocedurenumeratoranddenominatorparts of a rational number, either together (destratio), or separately (numeratoranddenominator). Whenratis integral, thennumerator=rat, anddenominator= 1.------------------------------7 Complex Specific Operations------------------------------num1+:num2->num3[]operator 5num1-:num2->num3[] These two operators are the basic way of creating complex numbers. Effectively, they both multiply their second argument by "i" (the positive square root of -1), and then either add the result to (operator 5+:) or subtract the result from (-:) the first argument.+:num1->num2[]operator 1-:num1->num2[] As prefix operators,operator 1+:and-:are equivalent tounary_+:(num1) andunary_-:(num1) respectively.unary_+:(num1) ->num2[]procedureunary_-:(num1) ->num2[] Single-argument versions ofprocedure+:and-:, which multiply their argument by i and -i respectively.conjugate(num1) ->num2[] Returns the complex conjugate of its argument. The conjugate of a real number is itself, while for a complex number it is realpart(procedurenum1) -: imagpart(num1) i.e. a complex number with the samerealpart, but negatedimagpart.destcomplex(num) -> (realpart,imagpart)[]procedurerealpart(num) ->realpart[]procedureimagpart(num) ->imagpart[] These procedures return the real and imaginary parts of a complex number, either together (proceduredestcomplex), or separately (realpartandimagpart). Whennumis real, thenrealpart=num, and a zero of the same type asnumis returned forimagpart.-------------------------8 Mathematical Functions-------------------------The procedures in this section, as well as most of those in the following section on trigonometric procedures, compute mathematical functions whose definitions on the complex plane necessitate choices of branch cuts and principal values. See the sectionBranch Cuts, Principalin Chapter 12 of Steele for details of these.Values and Boundary Conditionssqrt(num) ->sqrt[] Returns the (principal) square root ofprocedurenum. This will be a real floating-point ifnumis real and non-negative, and a float-complex otherwise.log(num) ->log[] Returns the natural (baseproceduree) logarithm ofnum, which must not be a zero of any kind. Ifnumis real and non-negative, the result is a real floating-point. Otherwise, it is the float-complex number log(abs(num)) +: phase(num)log10(num) ->log[] Returns the base 10 logarithm ofprocedurenum, which must not be a zero of any kind. Defined as log(num) / log(10)exp(num) ->exponent[] Returnsprocedureeraised to the powernum, whereeis the base of natural logarithms. The result is a floating-point if the argument is real, or a float-complex otherwise.base**power->exponent[] Returnsoperator 3baseraised to the powerpower, where either may be any numbers (except thatbasemust not be zero ifpoweris zero of any type other than integer 0). Ifpoweris an integer, the computation is performed by successively multiplying powers ofbase; thus ifbaseis rational, the result will be exact. Ifpoweris integer 0, the result is always a 1 of the same type asbase. Otherwise, ifpoweris not an integer, the result is computed as exp(power* log(base))--------------------------9 Trigonometric Functions--------------------------All the procedures in this section take an angle as argument, or return one as a result. In both cases, the units of the angle (radians or degrees) are controlled by the boolean variablepopradians(this applies equally when the angle is complex). The following diagram of the real plane is provided as a visualisation aid (angles are given in radians):Quadrant II | Quadrant Ix< 0,y>= 0|x>= 0,y>= 0 pi/2 <angle<= pi|0 <=angle<= pi/2||pi-A|A \|/---------------+--------------/|\ -(pi-A)|-A||Quadrant III | Quadrant IVx< 0,y< 0|x>= 0,y< 0 -pi <angle< -pi/2|-pi/2 <=angle< 0 (The above is particularly useful in relation toarctan2.)popradians ->bool[]variablebool-> popradiansThis boolean variable specifies whether the angle arguments for trigonometric procedures such assin,cosetc are in radians (true) or degrees (false). Similarily, it controls the units of angle results produced by procedures like arcsin, arccos, etc. Note that the default value isfalse, implying angles in degrees.phase(num) ->realangle[] Returns the complex phase angle ofprocedurenumas a floating-point quantity. This will be in the range - pi <realangle<= pi (radians) - 180 <realangle<= 180 (degrees) Ifnumis real, thenrealangle= 0.0. This procedure is defined as arctan2(destcomplex(num))cis(realangle) ->num[] Returns the float-complex number cos(procedurerealangle) +: sin(realangle) (the namecisstanding for 'cos + i sin'). Note that this is the same as exp(+:realangle) ONLY whenpopradiansis true (because the latter always interpretsrealanglein radians).sin(angle) ->num[]procedurecos(angle) ->num[]proceduretan(angle) ->num[] These procedures compute the sine, cosine and tangent ofprocedureangle. The result is a floating-point, or a float-complex ifangleis complex.arcsin(num) ->angle[]procedurearccos(num) ->angle[]procedurearctan(num) ->angle[] These procedures compute the arcsine, arccosine and arctangent ofprocedurenum. Fornumcomplex, the result is a float-complex. Fornumreal, it is a real float, except in the case ofarcsinandarccoswhen abs(num) > 1. Forarctan, it is an error ifnum= +:1 or -:1.arctan2(real_x,real_y) ->realangle[] Computes the arctangent ofprocedurereal_y/real_x, but using the signs of the two numbers to derive quadrant information. The result is a floating-point number in the range - pi <realangle<= pi (radians) - 180 <realangle<= 180 (degrees) (see diagram above). Whenreal_x= 0 andreal_y= 0 the result is defined (arbitrarily) to be 0.0.sinh(angle) ->num[]procedurecosh(angle) ->num[]proceduretanh(angle) ->num[] These procedures compute the hyperbolic sine, hyperbolic cosine and hyperbolic tangent ofprocedureangle. The result is a floating-point, or a float-complex ifangleis complex.arcsinh(num) ->angle[]procedurearccosh(num) ->angle[]procedurearctanh(num) ->angle[] These procedures compute the hyperbolic arcsine, hyperbolic arccosine and hyperbolic arctangent ofprocedurenum. Fornumcomplex, the result is a float-complex. Fornumreal, the result will be a real float, except in the following cases:arccosh:num< 1arctanh: abs(num) > 1 Forarctanh, it is an error ifnum= 1 or -1.pi ->float[] This constant is the best ddecimal approximation to "pi", = 3.14159....constant--------------------------------------10 Bitwise/Logical Integer Operations--------------------------------------These procedures enable integers to be manipulated as bit patterns representing two's-complement values, where bit positionNhas weight 2**N(i.e. bits are numbered from 0 upwards). Note that (conceptually, at any rate), the sign bit of an integer is extended indefinitely to the left. Thus everywhere above its most significant bit, a positive integer has 0 bits and a negative integer has 1 bits.int1&&int2->int3[] The result of this operation is the logical "and" of the integersoperator 4int1andint2, i.e. there is a 1 in the result for each bit position for which there is a 1 in bothint1andint2.int1&&~~int2->int3[] The result of this operation is the logical "and" ofoperator 4int1and the logical complement ofint2, i.e. there is a 1 in the result for each bit position for which there is a 1 inint1and a 0 inint2. (Same asint1&& (~~int2) -- useful for clearing bits ofint1set inint2).int1||int2->int3[] The result of this operation is the logical "inclusive or" ofoperator 4int1andint2, i.e. there is a 1 in the result for each bit position for which there is a 1 in eitherint1orint2.int1||/&int2->int3[] The result of this operation is the logical "exclusive or" ofoperator 4int1andint2, i.e. there is a 1 in the result for each bit position for which there is a 1 in eitherint1orint2but not in both.~~int1->int2[] Produces the logical complement of the integeroperator 4int1, i.e. there is a 1 in the result for each bit position for whichint1has 0. It is always true that ~~int= -(int+ 1)int1<<N->int2 [] Produces the bit pattern ofoperator 4int1shifted left by (simple integer)Npositions; a negative value forNproduces a right shift.int1>>N->int2[] Gives the bit pattern ofoperator 4int1shifted right by (simple integer)Npositions; a negative value forNimplies a left shift.int1&&/=_0int2->bool[]operator 6int1&&=_0int2->bool[] These two operators are equivalent to the boolean expressionsoperator 6int1&&int2/== 0int1&&int2== 0 but are more efficient (and avoid producing intermediate results).testbit(int,N) ->bool[]procedurebool->testbit(int,N) ->newintThis procedure and its updater enable the testing and setting or clearing of the bit at positionNin the integerint. The base procedure returns the state of bitNas a boolean value,truefor 1 andfalsefor 0. The updater (which is somewhat unusual for an updater in that it returns a result) produces a new integernewintwhich isintwith bitNset to 1 or cleared to 0 as specified by the inputboolargument (which may in fact be any item,falsemeaning 0 and anything else meaning 1).integer_leastbit(int) ->N_or_false[] Returns the bit positionprocedureNof the least-significant bit set in the integerint(equivalently,Nis the highest power of 2 by whichintdivides exactly).falseis returned forint0.integer_length(int) ->N[] Returns the length in bits ofprocedureintas a two's-complement integer. That is,Nis the smallest integer such thatint< ( 1 <<N) ifint>= 0int>= (-1 <<N) ifint< 0 Put another way: ifintis non-negative then the representation ofintas an unsigned integer requires a field of at leastNbits; alternatively, a minimum ofN+1 bits are required to representintas a signed integer, regardless of its sign.integer_bitcount(int) ->N[] Counts the number of 1 or 0 bits in the two's-complement representation ofprocedureint. Ifintis non-negative,Nis the number of 1 bits; ifintis negative, it is the number of 0 bits. (Note that, owing to the sign extension, there are an infinite number of 0 bits in a non-negative integer or 1 bits in a negative integer.) It is always the case that integer_bitcount(int) = integer_bitcount(-(int+1))integer_field(size,position) ->access_p[] This procedure is used to create accessing/updating procedures for sub-bitfields within integers, and provides a more convenient (and more efficient) way of manipulating such fields than by masking and shifting with the operatorsprocedure&&and>>, etc. Given a specification of a bitfield in terms of its width in bitssize, and lowest bit positionposition(both simple integers), it returns a procedureaccess_p. When this is applied to any integer it extracts the binary value represented by bitspositiontoposition+size-1 within the integer (shifting it right bypositionbits to align it at bit 0). That is,access_p(int) ->field_valueIf thesizeargument is > 0, the field is taken to contain unsigned (positive or zero values) only; ifsize< 0, then the field is signed, and upon extraction, the highest bit of the field is extended as the sign bit of the resulting value (cf the corresponding convention used byconskey). The updater ofaccess_p, on the other hand, takes a field value and an integer, and returns a new integer in which the contents of the field bits are replaced by the given value (but which has the same bits everywhere else). That is:field_value->access_p(int) ->newintNote that the updater makes no check on the range offield_value; bits 0 tosize-1 offield_valueare masked out, shifted up, and inserted into the field position (and it is therefore irrelevant in this context whether the field is signed or unsigned). A further feature is thataccess_pand its updater can be made to merely mask out or mask in the field bits, without shifting the value down or up. That is, upon extraction the field value is left aligned at bitpositionin the result; the input value for updating is assumed to be similarily aligned. This is achieved by supplying a second argument offalsetoaccess_por its updater, i.e.access_p(int, false) ->unshifted_field_valueunshifted_field_value->access_p(int, false) ->newintNote also that in this case, extraction of a signed field will NOT cause it to be sign-extended.------------------11 Random Numbers------------------The value of the variableranseedis used as the seed for the generation of random numbers, each random number generated using one or more successive seed values (depending on the type of the INT_OR_FLOAT argument torandom0andrandom). The algorithm used to generate each successive seed value is ranseed fi_* 524269 fi_+ 32749 -> ranseed which (since all current implementations use 30 bits for a simple integer) produces a result modulo 2**30. This algorithm has a verified cycle length of 2**30, i.e. it will produce every possible combination of 30 bits before repeating a number.random0(int_or_float) ->random[] Given a strictly-positive integer or floating-point argument, this procedure generates a random number of the same type, in the range 0 <=procedurerandom<int_or_floatwhere the distribution ofrandomwill be approximately uniform. The value of the variableranseedis used as the seed for the generation process, and is replaced with a new seed value afterwards.random(int_or_float) ->random[] Same asprocedurerandom0, except that whenever the latter would return 0 or 0.0, the original argumentint_or_floatis returned instead. It can thus be defined as random0(int_or_float) ->random; ifrandom= 0 thenint_or_floatelserandomendif; Hence the range of the result is 0 <random<=int_or_floatfor a float, or 1 <=random<=int_or_floatfor an integer.ranseed ->n_or_false[]variablen_or_false-> ranseedThis variable is used to hold the next seed for generation of random numbers byrandom0orrandom, both of which side-effect it. If set tofalse, it will be re-initialised to a random simple integer the next time either procedure is called (by usingsys_real_time). Otherwise, its value must always be a simple integer.----------------------------12 Floating_Point Utilities----------------------------The procedures in this section provide the means to manipulate floating-point numbers, and make possible the writing of machine-independent floating-point software. Note that none of these procedures are affected by the value ofpopdprecision.float_decode(float,want_int) -> (mantissa,expo,sign)[] This procedure takes a floating-point number and splits it into its component parts, i.e. mantissa, exponent and sign. The exponentprocedureexpois always an integer; the boolean argumentwant_intcontrols whether the mantissamantissaand signsignare returned as floats or integers.signrepresents the sign, and is returned either as a float or an integer. Forwant_intfalse, it is 1.0 or -1.0 of the same type as the argument, and with the same sign (note thatsignis 1.0 for 0.0). Forwant_inttrue, it is 1 or -1 (1 for 0.0). Denoting the radix of the floating-point representation byb(seepop_float_radixbelow),expois the integer power ofbby whichmantissamust be multiplied to regain the magnitude of the original number.mantissaitself is the absolute value of the number with b **expodivided out, and can be returned in one of two ways: Ifwant_intis false, thenmantissais returned as a float of the same type, in the range 1/b <=mantissa< 1 Otherwise,mantissais is returned as an integer, scaled by b ** float_precision(float) (that is, so that the least significant digit in the representation offloatis scaled to unity in the result). IfP= float_precision(float) we then have b ** (P-1) <=mantissa< b **PThus whether the mantissa is returned as a float or an integer, it will always be the case thatmantissa* (b **expo) = abs(float) (Note that this holds also whenfloat= 0.0, since in this caseexpo= 0, andmantissais 0.0 or 0 depending onwant_int.)float_scale(float1,expo) ->float2[] This provides a more efficient way of scaling a float by a power of the floating-point radix 'b' than by using ** (and avoids any intermediate overflow or underflow that could occur with the latter). It returnsprocedurefloat1* (b **expo) as a floating-point of the same type. If the final result overflows or underflows (i.e. the absolute value of the exponent is too large for the representation), thenfalseis returned. For example, this procedure can be used in conjunction withfloat_signto put back together a floating-point number decomposed withfloat_decode. That is, after float_decode(float, false) -> (mantissa,expo,sign) one can use float_sign(sign, float_scale(mantissa,expo)) to retrieve the original number.float_sign(sign_float,float1) ->float2[] Returns a floating-point numberprocedurefloat2of the same type and absolute value asfloat1, but which has the sign of the floatsign_float. The argumentfloat1may also befalse. In this case,float2is returned as a 1.0 or -1.0 of the same type and sign assign_float.float_digits(float) ->digits[] Returns, as an integer, the number of radix-'b' digits represented in the floating-point format of the argument. (I.e.proceduredigitshas only two possible values, one for decimals and one for ddecimals. In all current Poplog implementations, b = 2 and ddecimaldigitsis 53 or 56; decimaldigitsis 50 on Alpha OSF and 22 on other platforms.)float_precision(float) ->sigdigits[] Same asprocedurefloat_digits, except that the number of significant radix-'b' digits in the argument is returned. Since Poplog floating-point decimals and ddecimals are always normalised, this will in fact be identical to float_digits(float), with the single exception thatfloat_precision(0.0) = 0 for either float type.---------------------13 Numeric Constants---------------------This section describes constants that define the ranges of numbers available in various representation classes. 13.1 Integer -------------int_parameters[] This is a library; to use any of the constants it defines, you must load it explicitly with uses int_parameters; It defines the following parameter constants, all of whose values relate to the particular implementation of Poplog in use:librarypop_max_int[] The largest (i.e. most positive) integer value represented in immediate format (as an integer).constantpop_min_int[] The smallest (i.e. most negative) integer value represented in immediate format (as an integer). 13.2 Floating-Point --------------------constantfloat_parameters[] This is a library; to use any of the constants it defines, you must load it explicitly with uses float_parameters; It defines the following parameter constants, all of whose values relate to the particular implementation of Poplog in use:librarypop_most_positive_decimal[] The greatest positive value representable in simple decimal format.constantpop_least_positive_decimal[] The smallest positive (non-zero) value representable in simple decimal format.constantpop_least_negative_decimal[] The least negative value (i.e. closest to zero) representable in simple decimal format.constantpop_most_negative_decimal[] The most negative value (i.e. closest to negative infinity) representable in simple decimal format.constantpop_most_positive_ddecimal[]constantpop_least_positive_ddecimal[]constantpop_least_negative_ddecimal[]constantpop_most_negative_ddecimal[] Same as the above for double-length ddecimal format.constantpop_plus_epsilon_decimal[]constantpop_plus_epsilon_ddecimal[] These are the smallest positive numbers in each format which when added to 1.0 of the same format produce a value not equal to 1.0. I.e. for each format, the smallest positiveconstantesuch that number_coerce(1,e) +e/= 1.0 is true. (N.B. For ddecimal format, this depends onpopdprecisionnot beingfalse.)pop_minus_epsilon_decimal[]constantpop_minus_epsilon_ddecimal[] Same as before, but subtracting from 1.0 instead of adding, i.e. for each format the smallest positiveconstantesuch that number_coerce(1,e) -e/= 1.0 is true.pop_float_parameters ->fvec[] This is a full vector that holds all the floating-point constants given above, and which the latter uses to define each value as a separate constant. You are not advised to use this directly (since its format may change); always access the values viaconstantLIB*FLOAT_PARAMETERS.pop_float_radix ->int[] This integer constant is the radix of the floating-point representation (= 2 in all current Poplog implementations).constant-----------------14 Miscellaneous-----------------linearfit(list) -> (m,c)[] Takes a list of pairs of numbers representing co-ordinates of points, works out the best straight line through the points, and returns its slopeprocedurem, and its Y-interceptc. For vertical or nearly lines it will produce an error. SeeLIB*LINEARFIT.integer_key ->key[]constantbiginteger_key ->key[]constantratio_key ->key[]constantdecimal_key ->key[]constantddecimal_key ->key[]constantcomplex_key ->key[] Structure keys for simple integers, bigintegers, ratios, decimals, ddecimals and complex numbers (see REF * KEYS). +-+constant+-+C.all/ref/numbersCopyright University of Sussex 1995. All rights reserved.