132b578d3Smrg/*
232b578d3Smrg * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
332b578d3Smrg *
432b578d3Smrg * Permission to use, copy, modify, distribute, and sell this software and its
532b578d3Smrg * documentation for any purpose is hereby granted without fee, provided that
632b578d3Smrg * the above copyright notice appear in all copies and that both that copyright
732b578d3Smrg * notice and this permission notice appear in supporting documentation, and
832b578d3Smrg * that the name of Marc Aurele La France not be used in advertising or
932b578d3Smrg * publicity pertaining to distribution of the software without specific,
1032b578d3Smrg * written prior permission.  Marc Aurele La France makes no representations
1132b578d3Smrg * about the suitability of this software for any purpose.  It is provided
1232b578d3Smrg * "as-is" without express or implied warranty.
1332b578d3Smrg *
1432b578d3Smrg * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1532b578d3Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
1632b578d3Smrg * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1732b578d3Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1832b578d3Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1932b578d3Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2032b578d3Smrg * PERFORMANCE OF THIS SOFTWARE.
2132b578d3Smrg */
2232b578d3Smrg
2332b578d3Smrg#ifdef HAVE_CONFIG_H
2432b578d3Smrg#include "config.h"
2532b578d3Smrg#endif
2632b578d3Smrg
2732b578d3Smrg#include "atiutil.h"
2832b578d3Smrg
2932b578d3Smrg/*
3032b578d3Smrg * ATIReduceRatio --
3132b578d3Smrg *
3232b578d3Smrg * Reduce a fraction by factoring out the largest common divider of the
3332b578d3Smrg * fraction's numerator and denominator.
3432b578d3Smrg */
3532b578d3Smrgvoid
3632b578d3SmrgATIReduceRatio
3732b578d3Smrg(
3832b578d3Smrg    int *Numerator,
3932b578d3Smrg    int *Denominator
4032b578d3Smrg)
4132b578d3Smrg{
4232b578d3Smrg    int Multiplier, Divider, Remainder;
4332b578d3Smrg
4432b578d3Smrg    Multiplier = *Numerator;
4532b578d3Smrg    Divider = *Denominator;
4632b578d3Smrg
4732b578d3Smrg    while ((Remainder = Multiplier % Divider))
4832b578d3Smrg    {
4932b578d3Smrg        Multiplier = Divider;
5032b578d3Smrg        Divider = Remainder;
5132b578d3Smrg    }
5232b578d3Smrg
5332b578d3Smrg    *Numerator /= Divider;
5432b578d3Smrg    *Denominator /= Divider;
5532b578d3Smrg}
5632b578d3Smrg
5732b578d3Smrg/*
5832b578d3Smrg * ATIDivide --
5932b578d3Smrg *
6032b578d3Smrg * Using integer arithmetic and avoiding overflows, this function finds the
6132b578d3Smrg * rounded integer that best approximates
6232b578d3Smrg *
6332b578d3Smrg *         Numerator      Shift
6432b578d3Smrg *        ----------- * 2
6532b578d3Smrg *        Denominator
6632b578d3Smrg *
6732b578d3Smrg * using the specified rounding (floor (<0), nearest (=0) or ceiling (>0)).
6832b578d3Smrg */
6932b578d3Smrgint
7032b578d3SmrgATIDivide
7132b578d3Smrg(
7232b578d3Smrg    int       Numerator,
7332b578d3Smrg    int       Denominator,
7432b578d3Smrg    int       Shift,
7532b578d3Smrg    const int RoundingKind
7632b578d3Smrg)
7732b578d3Smrg{
7832b578d3Smrg    int Rounding = 0;                           /* Default to floor */
7932b578d3Smrg
8032b578d3Smrg#define MaxInt ((int)((unsigned int)(-1) >> 2))
8132b578d3Smrg
8232b578d3Smrg    ATIReduceRatio(&Numerator, &Denominator);
8332b578d3Smrg
8432b578d3Smrg    /* Deal with left shifts but try to keep the denominator even */
8532b578d3Smrg    if (Denominator & 1)
8632b578d3Smrg    {
8732b578d3Smrg        if (Denominator <= MaxInt)
8832b578d3Smrg        {
8932b578d3Smrg            Denominator <<= 1;
9032b578d3Smrg            Shift++;
9132b578d3Smrg        }
9232b578d3Smrg    }
9332b578d3Smrg    else while ((Shift > 0) && !(Denominator & 3))
9432b578d3Smrg    {
9532b578d3Smrg        Denominator >>= 1;
9632b578d3Smrg        Shift--;
9732b578d3Smrg    }
9832b578d3Smrg
9932b578d3Smrg    /* Deal with right shifts */
10032b578d3Smrg    while (Shift < 0)
10132b578d3Smrg    {
10232b578d3Smrg        if ((Numerator & 1) && (Denominator <= MaxInt))
10332b578d3Smrg            Denominator <<= 1;
10432b578d3Smrg        else
10532b578d3Smrg            Numerator >>= 1;
10632b578d3Smrg
10732b578d3Smrg        Shift++;
10832b578d3Smrg    }
10932b578d3Smrg
11032b578d3Smrg    if (!RoundingKind)                          /* Nearest */
11132b578d3Smrg        Rounding = Denominator >> 1;
11232b578d3Smrg    else if (RoundingKind > 0)                  /* Ceiling */
11332b578d3Smrg        Rounding = Denominator - 1;
11432b578d3Smrg
11532b578d3Smrg    return ((Numerator / Denominator) << Shift) +
11632b578d3Smrg            ((((Numerator % Denominator) << Shift) + Rounding) / Denominator);
11732b578d3Smrg}
118