atiutil.c revision 32b578d3
1/* 2 * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of Marc Aurele La France not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. Marc Aurele La France makes no representations 11 * about the suitability of this software for any purpose. It is provided 12 * "as-is" without express or implied warranty. 13 * 14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include "atiutil.h" 28 29/* 30 * ATIReduceRatio -- 31 * 32 * Reduce a fraction by factoring out the largest common divider of the 33 * fraction's numerator and denominator. 34 */ 35void 36ATIReduceRatio 37( 38 int *Numerator, 39 int *Denominator 40) 41{ 42 int Multiplier, Divider, Remainder; 43 44 Multiplier = *Numerator; 45 Divider = *Denominator; 46 47 while ((Remainder = Multiplier % Divider)) 48 { 49 Multiplier = Divider; 50 Divider = Remainder; 51 } 52 53 *Numerator /= Divider; 54 *Denominator /= Divider; 55} 56 57/* 58 * ATIDivide -- 59 * 60 * Using integer arithmetic and avoiding overflows, this function finds the 61 * rounded integer that best approximates 62 * 63 * Numerator Shift 64 * ----------- * 2 65 * Denominator 66 * 67 * using the specified rounding (floor (<0), nearest (=0) or ceiling (>0)). 68 */ 69int 70ATIDivide 71( 72 int Numerator, 73 int Denominator, 74 int Shift, 75 const int RoundingKind 76) 77{ 78 int Rounding = 0; /* Default to floor */ 79 80#define MaxInt ((int)((unsigned int)(-1) >> 2)) 81 82 ATIReduceRatio(&Numerator, &Denominator); 83 84 /* Deal with left shifts but try to keep the denominator even */ 85 if (Denominator & 1) 86 { 87 if (Denominator <= MaxInt) 88 { 89 Denominator <<= 1; 90 Shift++; 91 } 92 } 93 else while ((Shift > 0) && !(Denominator & 3)) 94 { 95 Denominator >>= 1; 96 Shift--; 97 } 98 99 /* Deal with right shifts */ 100 while (Shift < 0) 101 { 102 if ((Numerator & 1) && (Denominator <= MaxInt)) 103 Denominator <<= 1; 104 else 105 Numerator >>= 1; 106 107 Shift++; 108 } 109 110 if (!RoundingKind) /* Nearest */ 111 Rounding = Denominator >> 1; 112 else if (RoundingKind > 0) /* Ceiling */ 113 Rounding = Denominator - 1; 114 115 return ((Numerator / Denominator) << Shift) + 116 ((((Numerator % Denominator) << Shift) + Rounding) / Denominator); 117} 118