'\"!  eqn | tbl | mmdoc
.if n .pH ref.fract @(#)fract	40.1

.ig
imagen 8/31/89
docformat -c -s4 -dqm4 -p1 fract
..
.SO mstr.hdr
.ds Lb Shapes
.\" turn off automatic hyphenation -- JHevelin (08-09-89)
.am RT
.nh
..
.EQ
delim $$
.EN
.BK "Shapes Reference Manual"
.CH "Fracts" "8"
.H 1 "Fracts"
.H 2 "Coordinate Representation Types"
.IX "coordinate" "floating-point" "" "" "" PAGE START
.IX "coordinate" "fixed-point binary" "" "" "" PAGE START
.IX "floating-point coordinate" "" "" "" PAGE START
.IX "fixed-point binary coordinate" "" "" "" PAGE START
.P
.nh
Shapes uses two types of coordinate data representation:\ \&
floating-point and fixed-point binary,
\f2fract\fP numbers.
.P
\f3Floating-Point\f1
.P
Floating point numbers should be used for values
in which magnitude and accuracy are independent.
They are fixed-precision,
real numbers in a format similar to scientific
notation with three fields:
.BL
.LI
a sign (+ or \(mi)
.LI
an exponent
.LI
a mantissa (the binary approximation of the
numeric value)
.LE
.P
\f3Fixed-Point Binary (fract)\f1
.IX "fract"
.P
Fixed point numbers, fracts, are fixed-precision,
real numbers represented as an integer with an
implied radix point.
This point divides the fract into two distinct parts:\ \&
an integer, and a fraction.
The position of the implied radix point
determines the magnitude and degree of fractional accuracy.
.P
Unlike the floating-point mantissa,
the fractional portion of the fract is not an
approximation of the entire numeric value.
Rather, the fraction represents those digits that
follow the radix point.
Dividing the fractional component by the
appropriate value and adding it to the integer
component yields an approximation of the number
the fract represents.
.H 2 "Floating-Point Versus Fixed-Point Binary"
.IX "coordinate" "floating-point vs. fixed-point"
.P
The major difference between fract and float is
the magnitude/accuracy dependence caused by its
internal representation.
The separation of the exponent and the mantissa
of the float allows magnitude and accuracy to be
completely independent,
so that very large and very small values have the
same number of significant digits.
.P
In fract representation,
the magnitude and accuracy are a function of the
implied radix point position.
In the case of the fixed-point binary
representation of a fract,
moving the binary point one position to the
right increases the integer magnitude of the
numbers it can represent by a factor of 2
.UI "and"
decreases the fractional accuracy by a
factor of 2.
Moving the binary point one position to the left
decreases the integer magnitude of the numbers
and increases the fractional accuracy.
.P
Why use a fract when a float can represent a
wider variety of magnitudes independent of accuracy?
A fract can be implemented using the same
internal format as an ordinary integer and, therefore,
can be manipulated using the high performance
integer operations of the host CPU.
.P
On the other hand,
a float can be manipulated via the host CPU and
software subroutines,
but it requires a hardware floating-point
processor to achieve the performance of a fract.
Therefore, fract representation is often chosen
over float because the performance-accuracy ratio
is significantly higher than that of the float in
a standard system configuration.
.H 2 "Converting Floating-Point to Fixed-Point"
.IX "coordinate" "converting floating-point to fixed-point"
.IX "floating-point coordinate" "converting to fixed-point"
.P
In order to convert a float to a fract,
the integer and post-decimal portion of a float
must be extracted from its mantissa and the
digits stored in the corresponding components of the fract.
Although there is no physical separation of
integer and fraction in the fract representation,
the implied radix point identifies the components.
.P
The internal representation of a fract in \f2Shapes\fP is binary.
However, for simplicities sake,
the following example of a fract represented as a
fixed-point decimal.
.H 2 "Example"
This example converts the floating-point number 1123.456789
to a fract that can store nine significant decimal digits.
The implied placement of the decimal point
determines how many of the nine representable
digits will be used for the integer and
fractional components of the fract.
.AL
.LI
Begin by placing the implied decimal point
between digits 5 and 4
(count digits right to left, starting from 0).
.P
The fract format now stores numbers as four
significant decimal digits of the integer portion
followed by five significant decimal digits of
the fraction.
.LI
Multiply 1123.456789 by the base of the radix
point raised to the power of the digit position
immediately to the left of the radix point
.LI
Truncate the result.
.LE
.P
Algebraically,
this conversion can be expressed as:
$fract~=~truncate (x * (b sup p ))$,
where
.P
\f2fract\f1
is the resulting fract representation of
\f2x\f1
.P
\f2x\f1
is the number to be converted
.P
\f2b\f1
is the radix base for representing the fract
.P
\f2p\f1
is the digit position immediately to the left of
the radix point
.\" begin new page
.P
In this example,
the base is 10,
and the decimal digit position immediately to the
left of the decimal point is 5.
Substituting this information into the formula
gives the fract fixed-point decimal
representation of the test number:
.SS
.in +0.25i
$fract = truncate (1123.456789 * (10 sup 5 ))$
.br
$fract = truncate (1123.456789 * (100000))$
.br
$fract = truncate (112345678.9)$
.br
$fract = 112345678$
.in -0.25i
.SE
Since the test number has six significant
fractional digits,
and the fract format can only represent five,
one significant digit of fractional accuracy is lost.
This loss of accuracy is known as a \f2truncation error\fP.
If the radix point had been moved one position to
the left to catch the extra fractional digit,
the left-most significant digit of the integer
position would have been lost.
This loss of significant digits is known as \f2overflow\fP.
.H 2 "Converting Fixed-Point to Floating-Point"
.IX "coordinate" "converting fixed-point to floating-point"
.IX "floating-point coordinate" "converting to fixed-point"
.P
The inverse operation of truncate is to convert
the fract result to a floating-point by appending
``.0'' to it.
This trunc_inverse operation solves the fract
conversion formula for
.UI x .
This operation results in an equation to convert
a fract back to a float.
.P
Note:\ \&
If trunc_inverse is the inverse operation of truncate,
then $trunc_inverse(truncate (x)) = x$ for all x's.
By definition,
$trunc_inverse(fract) = fract.0$.
.P
.SS
.in +0.25i
$fract = truncate (x * (10 sup p ))$
.br
$trunc_inverse (fract) = trunc_inverse(truncate(x*(10 sup p )))$
.br
$trunc_inverse (fract) = x * (10 sup p )$
.br
$trunc_inverse (fract) / (10 sup p ) = x$
.in -0.25i
.SE
Substituting the fract representation of the test
number into this inverse formula gives:
.P
.SS
.in +0.25i
$trunc_inverse (112345678) / (10 sup 5 ) = x$
.br
$112345678.0 / (100000) = x$
.br
$1123.45678 = x$
.in -0.25i
.SE
The post decimal digit ``9'' missing from
\f2x\fP was a significant digit in the original
test number that substantiates the decrease of
post-decimal accuracy caused by truncation.
.IX "coordinate" "floating-point" "" "" "" PAGE END
.IX "floating-point coordinate" "" "" "" PAGE END
.H 2 "Fixed-Point Binary Within Shapes"
.P
A fract is a fixed-point 32-bit binary value,
derived from the C
.UI int
data type,
where the implied binary point is between bits 16 and 15.
Such  implementation allows a fract to maintain
16 significant binary digits each for the integer
component and the fractional component.
.P
By changing the numeric base
.UI b
to 2 (binary) and the binary digit
position
.UI p
left of the binary point to 16,
the following equation converts the test number
from floating-point decimal to fract representation:
.P
.SS
.in +0.25i
$fract = truncate (1123.456789 * (2 sup 16 ))$
.br
$fract = truncate (1123.456789 * (65536))$
.br
$fract = truncate (73626864.12)$
.br
$fract = 73626864$
.in -0.25i
.SE
.P
The fract is expressed in decimal because its
binary representation,
00000100011000110111010011110000,
isn't very meaningful.
.P
Similarly, the following equation converts back
to floating-point:
.P
.SS
.in +0.25i
$trunc_inverse (73626864) / (2 sup 16 ) = x$
.br
$73626864.0 / (65536) = x$
.br
$1123.3456420 = x$
.in -0.25i
.SE
The precision of the converted fract value is
only accurate to four post-decimal digits.
.H 2 "Fract Operators"
.IX "fixed-point binary coordinate" "operators"
.P
Fract operators are implemented in one of three forms.
.BL
.LI
Macros are automatically expanded to in-line C
code without embedded function calls.
.LI
Functions require special processing by the SunOS
inline command.
See the
.B MANPAGES
and the \f2Shapes\fP assembly language file fr-SunX.s
(e.g., sh_fract-sun3.s) for details.
.LE
.P
The following table lists the fract operators,
their purpose, and implementation.
.\" begin new page
.TB "Fract Operators"
.TS
box, tab(@);
cf4I | cf4I | cf4I
l | l | l .
Operator@Purpose@Implementation
=
frrsh(fract,int)@fract right shift int bits@ macro, inline
frlsh(fract,int)@fract left shift int bits@ macro, inline
fracti(number)@convert integer into a fract@ macro, inline
floorfr(fract)@integer less or equal fract@ macro, inline
floorfr(fract struct)@integer less or equal fract@ macro, inline
roundfr(fract)@round fract to nearest integer@ macro, inline
ceilingfr(fract)@integer greater or equal fract@ macro, inline
floatfr(fract)@convert fract to floating-point@ macro, inline
fractf(number)@convert float to fract@ macro, inline
fradd(fract1,fract2)@add fract2 to fract1@ macro, inline
frsub(fract1,fract2)@subtract fract2 from fract1@ macro, inline
frmul(fract1,fract2)@multiply fract1 and fract2@ function, inline
frdiv(fract1,fract2)@divide fract1 by fract2@ function, inline
fraction(int1, int2)@divide int1 by int2 and return fract@function, inline
frsq(fract)@square fract@function, inline
vfradd(fract1,fract2)@add fracts with overflow@function, inline
vfrsub(fract1,fract2)@subtract fracts with overflow@function, inline
vfrmul(fract1,fract2)@multiply fracts with overflow@function, inline
vfrdiv(fract1,fract2)@divide fracts with overflow@function, inline
frsqrt(fract)@compute square root of fract@function, inline
frsincosd(fr, *fr, *fr)@given angle in degrees and@function call
@pntrs to fracts, put in pntrs the
@value of the sin and cos respectively
frsind(fract)@given angle, return sin @function call
frcosd(fract)@given angle, return cos@function call
frarccosd(fract, quad)@given fract between \(mi1 and 1,@function call
@return the angle.  Angle is affected
@by its quadrant, where 0\(en90 is 1,
@90\(en180 is 2,...Quad is defined as type int.
.TE
.TT
.IX "coordinate" "fixed-point binary" "" "" "" PAGE END
.IX "fixed-point binary coordinate" "" "" "" PAGE END
.H 2 "Fract Performance"
.P
Shapes uses fracts internally whenever the
required precision is beyond that of an integer
but less than that of a float.
An application might use fracts for the same reason.
For example, if an application must perform
sub-pixel addressing or some other task that
requires a small degree of increased precision,
fracts can be used.
.P
Using fracts within Shapes does not affect
anything except having the magnitude and
fractional accuracy be dependent on the radix point position.
Since the radix point is fixed between bits 16 and 15,
changing it is not an alternative.
In fact, the rendering pipelines are optimized
for each type of data representation;
therefore, little performance is lost when you
use fracts instead of integers.
