Home | History | Annotate | Line # | Download | only in mp
      1 /*
      2  * Copyright (c) 2002 by The XFree86 Project, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20  * SOFTWARE.
     21  *
     22  * Except as contained in this notice, the name of the XFree86 Project shall
     23  * not be used in advertising or otherwise to promote the sale, use or other
     24  * dealings in this Software without prior written authorization from the
     25  * XFree86 Project.
     26  *
     27  * Author: Paulo Csar Pereira de Andrade
     28  */
     29 
     30 /* $XFree86$ */
     31 
     32 #include "mp.h"
     33 
     34 /*
     35  * TODO:
     36  *  Implement a fast gcd and divexact for integers, so that this code
     37  * could be changed to do intermediary calculations faster using smaller
     38  * numbers.
     39  */
     40 
     41 /*
     42  * Prototypes
     43  */
     44 	/* do the hard work of mpr_add and mpr_sub */
     45 static void mpr_addsub(mpr *rop, mpr *op1, mpr *op2, int sub);
     46 
     47 	/* do the hard work of mpr_cmp and mpr_cmpabs */
     48 static int mpr_docmp(mpr *op1, mpr *op2, int sign);
     49 
     50 /*
     51  * Implementation
     52  */
     53 void
     54 mpr_init(mpr *op)
     55 {
     56     op->num.digs = mp_malloc(sizeof(BNS));
     57     op->num.sign = 0;
     58     op->num.size = op->num.alloc = 1;
     59     op->num.digs[0] = 0;
     60 
     61     op->den.digs = mp_malloc(sizeof(BNS));
     62     op->den.sign = 0;
     63     op->den.size = op->den.alloc = 1;
     64     op->den.digs[0] = 1;
     65 }
     66 
     67 void
     68 mpr_clear(mpr *op)
     69 {
     70     op->num.sign = 0;
     71     op->num.size = op->num.alloc = 0;
     72     mp_free(op->num.digs);
     73 
     74     op->den.sign = 0;
     75     op->den.size = op->den.alloc = 0;
     76     mp_free(op->den.digs);
     77 }
     78 
     79 void
     80 mpr_set(mpr *rop, mpr *op)
     81 {
     82     if (rop != op) {
     83 	mpi_set(mpr_num(rop), mpr_num(op));
     84 	mpi_set(mpr_den(rop), mpr_den(op));
     85     }
     86 }
     87 
     88 void
     89 mpr_seti(mpr *rop, long num, long den)
     90 {
     91     mpi_seti(mpr_num(rop), num);
     92     mpi_seti(mpr_den(rop), den);
     93 }
     94 
     95 void
     96 mpr_setd(mpr *rop, double d)
     97 {
     98     double val, num;
     99     int e, sign;
    100 
    101     /* initialize */
    102     if (d < 0) {
    103 	sign = 1;
    104 	val = -d;
    105     }
    106     else {
    107 	sign = 0;
    108 	val = d;
    109     }
    110 
    111     val = frexp(val, &e);
    112     while (modf(val, &num) != 0.0 && val <= DBL_MAX / 2.0) {
    113 	--e;
    114 	val *= 2.0;
    115     }
    116     if (e >= 0) {
    117 	mpi_setd(mpr_num(rop), d);
    118 	mpi_seti(mpr_den(rop), 1);
    119     }
    120     else {
    121 	mpi_setd(mpr_num(rop), sign ? -num : num);
    122 	mpi_setd(mpr_den(rop), ldexp(1.0, -e));
    123     }
    124 }
    125 
    126 void
    127 mpr_setstr(mpr *rop, char *str, int base)
    128 {
    129     char *slash = strchr(str, '/');
    130 
    131     mpi_setstr(mpr_num(rop), str, base);
    132     if (slash != NULL)
    133 	mpi_setstr(mpr_den(rop), slash + 1, base);
    134     else
    135 	mpi_seti(mpr_den(rop), 1);
    136 }
    137 
    138 void
    139 mpr_canonicalize(mpr *op)
    140 {
    141     mpi gcd;
    142 
    143     memset(&gcd, '\0', sizeof(mpi));
    144 
    145     mpi_gcd(&gcd, mpr_num(op), mpr_den(op));
    146     if (mpi_cmpabsi(&gcd, 1)) {
    147 	mpi_div(mpr_num(op), mpr_num(op), &gcd);
    148 	mpi_div(mpr_den(op), mpr_den(op), &gcd);
    149     }
    150 
    151     if (op->den.sign) {
    152 	op->num.sign = !op->num.sign;
    153 	op->den.sign = 0;
    154     }
    155 
    156     mpi_clear(&gcd);
    157 }
    158 
    159 void
    160 mpr_add(mpr *rop, mpr *op1, mpr *op2)
    161 {
    162     mpr_addsub(rop, op1, op2, 0);
    163 }
    164 
    165 void
    166 mpr_addi(mpr *rop, mpr *op1, long op2)
    167 {
    168     mpi prod;
    169 
    170     memset(&prod, '\0', sizeof(mpi));
    171 
    172     mpi_muli(&prod, mpr_den(op1), op2);
    173     mpi_add(mpr_num(rop), mpr_num(op1), &prod);
    174     mpi_clear(&prod);
    175 }
    176 
    177 void
    178 mpr_sub(mpr *rop, mpr *op1, mpr *op2)
    179 {
    180     mpr_addsub(rop, op1, op2, 1);
    181 }
    182 
    183 void
    184 mpr_subi(mpr *rop, mpr *op1, long op2)
    185 {
    186     mpi prod;
    187 
    188     memset(&prod, '\0', sizeof(mpi));
    189 
    190     mpi_muli(&prod, mpr_den(op1), op2);
    191     mpi_sub(mpr_num(rop), mpr_num(op1), &prod);
    192     mpi_clear(&prod);
    193 }
    194 
    195 static void
    196 mpr_addsub(mpr *rop, mpr *op1, mpr *op2, int sub)
    197 {
    198     mpi prod1, prod2;
    199 
    200     memset(&prod1, '\0', sizeof(mpi));
    201     memset(&prod2, '\0', sizeof(mpi));
    202 
    203     mpi_mul(&prod1, mpr_num(op1), mpr_den(op2));
    204     mpi_mul(&prod2, mpr_num(op2), mpr_den(op1));
    205 
    206     if (sub)
    207 	mpi_sub(mpr_num(rop), &prod1, &prod2);
    208     else
    209 	mpi_add(mpr_num(rop), &prod1, &prod2);
    210 
    211     mpi_clear(&prod1);
    212     mpi_clear(&prod2);
    213 
    214     mpi_mul(mpr_den(rop), mpr_den(op1), mpr_den(op2));
    215 }
    216 
    217 void
    218 mpr_mul(mpr *rop, mpr *op1, mpr *op2)
    219 {
    220     /* check if temporary storage is required */
    221     if (op1 == op2 && rop == op1) {
    222 	mpi prod;
    223 
    224 	memset(&prod, '\0', sizeof(mpi));
    225 
    226 	mpi_mul(&prod, mpr_num(op1), mpr_num(op2));
    227 	mpi_mul(mpr_den(rop), mpr_den(op1), mpr_den(op2));
    228 	mpi_set(mpr_num(rop), &prod);
    229 
    230 	mpi_clear(&prod);
    231     }
    232     else {
    233 	mpi_mul(mpr_num(rop), mpr_num(op1), mpr_num(op2));
    234 	mpi_mul(mpr_den(rop), mpr_den(op1), mpr_den(op2));
    235     }
    236 }
    237 
    238 void
    239 mpr_muli(mpr *rop, mpr *op1, long op2)
    240 {
    241     mpi_muli(mpr_num(rop), mpr_num(op1), op2);
    242 }
    243 
    244 void
    245 mpr_div(mpr *rop, mpr *op1, mpr *op2)
    246 {
    247     /* check if temporary storage is required */
    248     if (op1 == op2 && rop == op1) {
    249 	mpi prod;
    250 
    251 	memset(&prod, '\0', sizeof(mpi));
    252 
    253 	mpi_mul(&prod, mpr_num(op1), mpr_den(op2));
    254 	mpi_mul(mpr_den(rop), mpr_num(op2), mpr_den(op1));
    255 	mpi_set(mpr_num(rop), &prod);
    256 
    257 	mpi_clear(&prod);
    258     }
    259     else {
    260 	mpi_mul(mpr_num(rop), mpr_num(op1), mpr_den(op2));
    261 	mpi_mul(mpr_den(rop), mpr_num(op2), mpr_den(op1));
    262     }
    263 }
    264 
    265 void
    266 mpr_divi(mpr *rop, mpr *op1, long op2)
    267 {
    268     mpi_muli(mpr_den(rop), mpr_den(op1), op2);
    269 }
    270 
    271 void
    272 mpr_inv(mpr *rop, mpr *op)
    273 {
    274     if (rop == op)
    275 	mpi_swap(mpr_num(op), mpr_den(op));
    276     else {
    277 	mpi_set(mpr_num(rop), mpr_den(op));
    278 	mpi_set(mpr_den(rop), mpr_num(op));
    279     }
    280 }
    281 
    282 void
    283 mpr_neg(mpr *rop, mpr *op)
    284 {
    285     mpi_neg(mpr_num(rop), mpr_num(op));
    286     mpi_set(mpr_den(rop), mpr_den(op));
    287 }
    288 
    289 void
    290 mpr_abs(mpr *rop, mpr *op)
    291 {
    292     if (mpr_num(op)->sign)
    293 	mpi_neg(mpr_num(rop), mpr_num(op));
    294     else
    295 	mpi_set(mpr_num(rop), mpr_num(op));
    296 
    297     /* op may not be canonicalized */
    298     if (mpr_den(op)->sign)
    299 	mpi_neg(mpr_den(rop), mpr_den(op));
    300     else
    301 	mpi_set(mpr_den(rop), mpr_den(op));
    302 }
    303 
    304 int
    305 mpr_cmp(mpr *op1, mpr *op2)
    306 {
    307     return (mpr_docmp(op1, op2, 1));
    308 }
    309 
    310 int
    311 mpr_cmpi(mpr *op1, long op2)
    312 {
    313     int cmp;
    314     mpr rat;
    315 
    316     mpr_init(&rat);
    317     mpi_seti(mpr_num(&rat), op2);
    318     cmp = mpr_docmp(op1, &rat, 1);
    319     mpr_clear(&rat);
    320 
    321     return (cmp);
    322 }
    323 
    324 int
    325 mpr_cmpabs(mpr *op1, mpr *op2)
    326 {
    327     return (mpr_docmp(op1, op2, 0));
    328 }
    329 
    330 int
    331 mpr_cmpabsi(mpr *op1, long op2)
    332 {
    333     int cmp;
    334     mpr rat;
    335 
    336     mpr_init(&rat);
    337     mpi_seti(mpr_num(&rat), op2);
    338     cmp = mpr_docmp(op1, &rat, 0);
    339     mpr_clear(&rat);
    340 
    341     return (cmp);
    342 }
    343 
    344 static int
    345 mpr_docmp(mpr *op1, mpr *op2, int sign)
    346 {
    347     int cmp, neg;
    348     mpi prod1, prod2;
    349 
    350     neg = 0;
    351     if (sign) {
    352 	/* if op1 is negative */
    353 	if (mpr_num(op1)->sign ^ mpr_den(op1)->sign) {
    354 	    /* if op2 is positive */
    355 	    if (!(mpr_num(op2)->sign ^ mpr_den(op2)->sign))
    356 		return (-1);
    357 	    else
    358 		neg = 1;
    359 	}
    360 	/* if op2 is negative */
    361 	else if (mpr_num(op2)->sign ^ mpr_den(op2)->sign)
    362 	    return (1);
    363 	/* else same sign */
    364     }
    365 
    366     /* if denominators are equal, compare numerators */
    367     if (mpi_cmpabs(mpr_den(op1), mpr_den(op2)) == 0) {
    368 	cmp = mpi_cmpabs(mpr_num(op1), mpr_num(op2));
    369 	if (cmp == 0)
    370 	    return (0);
    371 	if (sign && neg)
    372 	    return (cmp < 0 ? 1 : -1);
    373 	return (cmp);
    374     }
    375 
    376     memset(&prod1, '\0', sizeof(mpi));
    377     memset(&prod2, '\0', sizeof(mpi));
    378 
    379     /* "divide" op1 by op2
    380      * if result is smaller than 1, op1 is smaller than op2 */
    381     mpi_mul(&prod1, mpr_num(op1), mpr_den(op2));
    382     mpi_mul(&prod2, mpr_num(op2), mpr_den(op1));
    383 
    384     cmp = mpi_cmpabs(&prod1, &prod2);
    385 
    386     mpi_clear(&prod1);
    387     mpi_clear(&prod2);
    388 
    389     if (sign && neg)
    390 	return (cmp < 0 ? 1 : -1);
    391     return (cmp);
    392 }
    393 
    394 void
    395 mpr_swap(mpr *op1, mpr *op2)
    396 {
    397     if (op1 != op2) {
    398 	mpr swap;
    399 
    400 	memcpy(&swap, op1, sizeof(mpr));
    401 	memcpy(op1, op2, sizeof(mpr));
    402 	memcpy(op2, &swap, sizeof(mpr));
    403     }
    404 }
    405 
    406 int
    407 mpr_fiti(mpr *op)
    408 {
    409     return (mpi_fiti(mpr_num(op)) && mpi_fiti(mpr_den(op)));
    410 }
    411 
    412 double
    413 mpr_getd(mpr *op)
    414 {
    415     return (mpi_getd(mpr_num(op)) / mpi_getd(mpr_den(op)));
    416 }
    417 
    418 char *
    419 mpr_getstr(char *str, mpr *op, int base)
    420 {
    421     int len;
    422 
    423     if (str == NULL) {
    424 	len = mpi_getsize(mpr_num(op), base) + mpr_num(op)->sign + 1 +
    425 	      mpi_getsize(mpr_den(op), base) + mpr_den(op)->sign + 1;
    426 
    427 	str = mp_malloc(len);
    428     }
    429 
    430     (void)mpi_getstr(str, mpr_num(op), base);
    431     len = strlen(str);
    432     str[len] = '/';
    433     (void)mpi_getstr(str + len + 1, mpr_den(op), base);
    434 
    435     return (str);
    436 }
    437