|
|
<HTML> <HEAD> <!-- Created by texi2html 1.56k from cln.texi on 14 January 2000 -->
<TITLE>CLN, a Class Library for Numbers - 3. Ordinary number types</TITLE> </HEAD> <BODY> Go to the <A HREF="cln_1.html">first</A>, <A HREF="cln_2.html">previous</A>, <A HREF="cln_4.html">next</A>, <A HREF="cln_13.html">last</A> section, <A HREF="cln_toc.html">table of contents</A>. <P><HR><P>
<H1><A NAME="SEC10" HREF="cln_toc.html#TOC10">3. Ordinary number types</A></H1>
<P> CLN implements the following class hierarchy:
<PRE> Number cl_number <cl_number.h> | | Real or complex number cl_N <cl_complex.h> | | Real number cl_R <cl_real.h> | +-------------------+-------------------+ | | Rational number Floating-point number cl_RA cl_F <cl_rational.h> <cl_float.h> | | | +-------------+-------------+-------------+ Integer | | | | cl_I Short-Float Single-Float Double-Float Long-Float <cl_integer.h> cl_SF cl_FF cl_DF cl_LF <cl_sfloat.h> <cl_ffloat.h> <cl_dfloat.h> <cl_lfloat.h> </PRE>
<P> The base class <CODE>cl_number</CODE> is an abstract base class. It is not useful to declare a variable of this type except if you want to completely disable compile-time type checking and use run-time type checking instead.
<P> The class <CODE>cl_N</CODE> comprises real and complex numbers. There is no special class for complex numbers since complex numbers with imaginary part <CODE>0</CODE> are automatically converted to real numbers.
<P> The class <CODE>cl_R</CODE> comprises real numbers of different kinds. It is an abstract class.
<P> The class <CODE>cl_RA</CODE> comprises exact real numbers: rational numbers, including integers. There is no special class for non-integral rational numbers since rational numbers with denominator <CODE>1</CODE> are automatically converted to integers.
<P> The class <CODE>cl_F</CODE> implements floating-point approximations to real numbers. It is an abstract class.
<H2><A NAME="SEC11" HREF="cln_toc.html#TOC11">3.1 Exact numbers</A></H2>
<P> Some numbers are represented as exact numbers: there is no loss of information when such a number is converted from its mathematical value to its internal representation. On exact numbers, the elementary operations (<CODE>+</CODE>, <CODE>-</CODE>, <CODE>*</CODE>, <CODE>/</CODE>, comparisons, ...) compute the completely correct result.
<P> In CLN, the exact numbers are:
<UL> <LI>
rational numbers (including integers), <LI>
complex numbers whose real and imaginary parts are both rational numbers. </UL>
<P> Rational numbers are always normalized to the form <CODE><VAR>numerator</VAR>/<VAR>denominator</VAR></CODE> where the numerator and denominator are coprime integers and the denominator is positive. If the resulting denominator is <CODE>1</CODE>, the rational number is converted to an integer.
<P> Small integers (typically in the range <CODE>-2^30</CODE>...<CODE>2^30-1</CODE>, for 32-bit machines) are especially efficient, because they consume no heap allocation. Otherwise the distinction between these immediate integers (called "fixnums") and heap allocated integers (called "bignums") is completely transparent.
<H2><A NAME="SEC12" HREF="cln_toc.html#TOC12">3.2 Floating-point numbers</A></H2>
<P> Not all real numbers can be represented exactly. (There is an easy mathematical proof for this: Only a countable set of numbers can be stored exactly in a computer, even if one assumes that it has unlimited storage. But there are uncountably many real numbers.) So some approximation is needed. CLN implements ordinary floating-point numbers, with mantissa and exponent.
<P> The elementary operations (<CODE>+</CODE>, <CODE>-</CODE>, <CODE>*</CODE>, <CODE>/</CODE>, ...) only return approximate results. For example, the value of the expression <CODE>(cl_F) 0.3 + (cl_F) 0.4</CODE> prints as <SAMP>`0.70000005'</SAMP>, not as <SAMP>`0.7'</SAMP>. Rounding errors like this one are inevitable when computing with floating-point numbers.
<P> Nevertheless, CLN rounds the floating-point results of the operations <CODE>+</CODE>, <CODE>-</CODE>, <CODE>*</CODE>, <CODE>/</CODE>, <CODE>sqrt</CODE> according to the "round-to-even" rule: It first computes the exact mathematical result and then returns the floating-point number which is nearest to this. If two floating-point numbers are equally distant from the ideal result, the one with a <CODE>0</CODE> in its least significant mantissa bit is chosen.
<P> Similarly, testing floating point numbers for equality <SAMP>`x == y'</SAMP> is gambling with random errors. Better check for <SAMP>`abs(x - y) < epsilon'</SAMP> for some well-chosen <CODE>epsilon</CODE>.
<P> Floating point numbers come in four flavors:
<UL> <LI>
Short floats, type <CODE>cl_SF</CODE>. They have 1 sign bit, 8 exponent bits (including the exponent's sign), and 17 mantissa bits (including the "hidden" bit). They don't consume heap allocation.
<LI>
Single floats, type <CODE>cl_FF</CODE>. They have 1 sign bit, 8 exponent bits (including the exponent's sign), and 24 mantissa bits (including the "hidden" bit). In CLN, they are represented as IEEE single-precision floating point numbers. This corresponds closely to the C/C++ type <SAMP>`float'</SAMP>.
<LI>
Double floats, type <CODE>cl_DF</CODE>. They have 1 sign bit, 11 exponent bits (including the exponent's sign), and 53 mantissa bits (including the "hidden" bit). In CLN, they are represented as IEEE double-precision floating point numbers. This corresponds closely to the C/C++ type <SAMP>`double'</SAMP>.
<LI>
Long floats, type <CODE>cl_LF</CODE>. They have 1 sign bit, 32 exponent bits (including the exponent's sign), and n mantissa bits (including the "hidden" bit), where n >= 64. The precision of a long float is unlimited, but once created, a long float has a fixed precision. (No "lazy recomputation".) </UL>
<P> Of course, computations with long floats are more expensive than those with smaller floating-point formats.
<P> CLN does not implement features like NaNs, denormalized numbers and gradual underflow. If the exponent range of some floating-point type is too limited for your application, choose another floating-point type with larger exponent range.
<P> As a user of CLN, you can forget about the differences between the four floating-point types and just declare all your floating-point variables as being of type <CODE>cl_F</CODE>. This has the advantage that when you change the precision of some computation (say, from <CODE>cl_DF</CODE> to <CODE>cl_LF</CODE>), you don't have to change the code, only the precision of the initial values. Also, many transcendental functions have been declared as returning a <CODE>cl_F</CODE> when the argument is a <CODE>cl_F</CODE>, but such declarations are missing for the types <CODE>cl_SF</CODE>, <CODE>cl_FF</CODE>, <CODE>cl_DF</CODE>, <CODE>cl_LF</CODE>. (Such declarations would be wrong if the floating point contagion rule happened to change in the future.)
<H2><A NAME="SEC13" HREF="cln_toc.html#TOC13">3.3 Complex numbers</A></H2>
<P> Complex numbers, as implemented by the class <CODE>cl_N</CODE>, have a real part and an imaginary part, both real numbers. A complex number whose imaginary part is the exact number <CODE>0</CODE> is automatically converted to a real number.
<P> Complex numbers can arise from real numbers alone, for example through application of <CODE>sqrt</CODE> or transcendental functions.
<H2><A NAME="SEC14" HREF="cln_toc.html#TOC14">3.4 Conversions</A></H2>
<P> Conversions from any class to any its superclasses ("base classes" in C++ terminology) is done automatically.
<P> Conversions from the C built-in types <SAMP>`long'</SAMP> and <SAMP>`unsigned long'</SAMP> are provided for the classes <CODE>cl_I</CODE>, <CODE>cl_RA</CODE>, <CODE>cl_R</CODE>, <CODE>cl_N</CODE> and <CODE>cl_number</CODE>.
<P> Conversions from the C built-in types <SAMP>`int'</SAMP> and <SAMP>`unsigned int'</SAMP> are provided for the classes <CODE>cl_I</CODE>, <CODE>cl_RA</CODE>, <CODE>cl_R</CODE>, <CODE>cl_N</CODE> and <CODE>cl_number</CODE>. However, these conversions emphasize efficiency. Their range is therefore limited:
<UL> <LI>
The conversion from <SAMP>`int'</SAMP> works only if the argument is < 2^29 and > -2^29. <LI>
The conversion from <SAMP>`unsigned int'</SAMP> works only if the argument is < 2^29. </UL>
<P> In a declaration like <SAMP>`cl_I x = 10;'</SAMP> the C++ compiler is able to do the conversion of <CODE>10</CODE> from <SAMP>`int'</SAMP> to <SAMP>`cl_I'</SAMP> at compile time already. On the other hand, code like <SAMP>`cl_I x = 1000000000;'</SAMP> is in error. So, if you want to be sure that an <SAMP>`int'</SAMP> whose magnitude is not guaranteed to be < 2^29 is correctly converted to a <SAMP>`cl_I'</SAMP>, first convert it to a <SAMP>`long'</SAMP>. Similarly, if a large <SAMP>`unsigned int'</SAMP> is to be converted to a <SAMP>`cl_I'</SAMP>, first convert it to an <SAMP>`unsigned long'</SAMP>.
<P> Conversions from the C built-in type <SAMP>`float'</SAMP> are provided for the classes <CODE>cl_FF</CODE>, <CODE>cl_F</CODE>, <CODE>cl_R</CODE>, <CODE>cl_N</CODE> and <CODE>cl_number</CODE>.
<P> Conversions from the C built-in type <SAMP>`double'</SAMP> are provided for the classes <CODE>cl_DF</CODE>, <CODE>cl_F</CODE>, <CODE>cl_R</CODE>, <CODE>cl_N</CODE> and <CODE>cl_number</CODE>.
<P> Conversions from <SAMP>`const char *'</SAMP> are provided for the classes <CODE>cl_I</CODE>, <CODE>cl_RA</CODE>, <CODE>cl_SF</CODE>, <CODE>cl_FF</CODE>, <CODE>cl_DF</CODE>, <CODE>cl_LF</CODE>, <CODE>cl_F</CODE>, <CODE>cl_R</CODE>, <CODE>cl_N</CODE>. The easiest way to specify a value which is outside of the range of the C++ built-in types is therefore to specify it as a string, like this:
<PRE> cl_I order_of_rubiks_cube_group = "43252003274489856000"; </PRE>
<P> Note that this conversion is done at runtime, not at compile-time.
<P> Conversions from <CODE>cl_I</CODE> to the C built-in types <SAMP>`int'</SAMP>, <SAMP>`unsigned int'</SAMP>, <SAMP>`long'</SAMP>, <SAMP>`unsigned long'</SAMP> are provided through the functions
<DL COMPACT>
<DT><CODE>int cl_I_to_int (const cl_I& x)</CODE> <DD> <DT><CODE>unsigned int cl_I_to_uint (const cl_I& x)</CODE> <DD> <DT><CODE>long cl_I_to_long (const cl_I& x)</CODE> <DD> <DT><CODE>unsigned long cl_I_to_ulong (const cl_I& x)</CODE> <DD> Returns <CODE>x</CODE> as element of the C type <VAR>ctype</VAR>. If <CODE>x</CODE> is not representable in the range of <VAR>ctype</VAR>, a runtime error occurs. </DL>
<P> Conversions from the classes <CODE>cl_I</CODE>, <CODE>cl_RA</CODE>, <CODE>cl_SF</CODE>, <CODE>cl_FF</CODE>, <CODE>cl_DF</CODE>, <CODE>cl_LF</CODE>, <CODE>cl_F</CODE> and <CODE>cl_R</CODE> to the C built-in types <SAMP>`float'</SAMP> and <SAMP>`double'</SAMP> are provided through the functions
<DL COMPACT>
<DT><CODE>float cl_float_approx (const <VAR>type</VAR>& x)</CODE> <DD> <DT><CODE>double cl_double_approx (const <VAR>type</VAR>& x)</CODE> <DD> Returns an approximation of <CODE>x</CODE> of C type <VAR>ctype</VAR>. If <CODE>abs(x)</CODE> is too close to 0 (underflow), 0 is returned. If <CODE>abs(x)</CODE> is too large (overflow), an IEEE infinity is returned. </DL>
<P> Conversions from any class to any of its subclasses ("derived classes" in C++ terminology) are not provided. Instead, you can assert and check that a value belongs to a certain subclass, and return it as element of that class, using the <SAMP>`As'</SAMP> and <SAMP>`The'</SAMP> macros. <CODE>As(<VAR>type</VAR>)(<VAR>value</VAR>)</CODE> checks that <VAR>value</VAR> belongs to <VAR>type</VAR> and returns it as such. <CODE>The(<VAR>type</VAR>)(<VAR>value</VAR>)</CODE> assumes that <VAR>value</VAR> belongs to <VAR>type</VAR> and returns it as such. It is your responsibility to ensure that this assumption is valid. Example:
<PRE> cl_I x = ...; if (!(x >= 0)) abort(); cl_I ten_x = The(cl_I)(expt(10,x)); // If x >= 0, 10^x is an integer. // In general, it would be a rational number. </PRE>
<P><HR><P> Go to the <A HREF="cln_1.html">first</A>, <A HREF="cln_2.html">previous</A>, <A HREF="cln_4.html">next</A>, <A HREF="cln_13.html">last</A> section, <A HREF="cln_toc.html">table of contents</A>. </BODY> </HTML>
|