You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1070 lines
26 KiB
1070 lines
26 KiB
/**
|
|
@file
|
|
|
|
@ingroup cudd
|
|
|
|
@brief Arbitrary precision arithmetic functions.
|
|
|
|
@details This file provides just enough functionality as needed
|
|
by CUDD to compute the number of minterms of functions with many
|
|
variables.
|
|
|
|
@author Fabio Somenzi
|
|
|
|
@copyright@parblock
|
|
Copyright (c) 1995-2015, Regents of the University of Colorado
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
Neither the name of the University of Colorado nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
@endparblock
|
|
|
|
*/
|
|
|
|
#include "util.h"
|
|
#include "cuddInt.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Constant declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* These constants define the digits used in the representation of
|
|
** arbitrary precision integers.
|
|
*/
|
|
#define DD_APA_BITS ((int) sizeof(DdApaDigit) * 8)
|
|
#define DD_APA_BASE ((DdApaDoubleDigit) 1 << DD_APA_BITS)
|
|
#define DD_APA_MASK (DD_APA_BASE - 1)
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Stucture declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Type declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
@brief Type used for intermediate results.
|
|
*/
|
|
typedef uint64_t DdApaDoubleDigit;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Macro declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
@brief Extract the least significant digit of a double digit.
|
|
|
|
@sideeffect None
|
|
|
|
@see DD_MSDIGIT
|
|
|
|
*/
|
|
#define DD_LSDIGIT(x) ((x) & DD_APA_MASK)
|
|
|
|
|
|
/**
|
|
@brief Extract the most significant digit of a double digit.
|
|
|
|
@sideeffect None
|
|
|
|
@see DD_LSDIGIT
|
|
|
|
*/
|
|
#define DD_MSDIGIT(x) ((x) >> DD_APA_BITS)
|
|
|
|
/** \cond */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static DdApaNumber cuddApaCountMintermAux (DdManager const * manager, DdNode * node, int digits, DdApaNumber mmax, DdApaNumber mmin, st_table * table);
|
|
static enum st_retval cuddApaStCountfree (void * key, void * value, void * arg);
|
|
|
|
/** \endcond */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Returns the number of digits for an arbitrary precision
|
|
integer.
|
|
|
|
@details Finds the number of digits for an arbitrary precision
|
|
integer given the maximum number of binary digits. The number of
|
|
binary digits should be positive.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaNumberOfDigits(
|
|
int binaryDigits)
|
|
{
|
|
int digits;
|
|
|
|
digits = binaryDigits / DD_APA_BITS;
|
|
if ((digits * DD_APA_BITS) != binaryDigits)
|
|
digits++;
|
|
return(digits);
|
|
|
|
} /* end of Cudd_ApaNumberOfDigits */
|
|
|
|
|
|
/**
|
|
@brief Allocates memory for an arbitrary precision integer.
|
|
|
|
@return a pointer to the allocated memory if successful;
|
|
NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_FreeApaNumber
|
|
*/
|
|
DdApaNumber
|
|
Cudd_NewApaNumber(
|
|
int digits)
|
|
{
|
|
return(ALLOC(DdApaDigit, digits));
|
|
|
|
} /* end of Cudd_NewApaNumber */
|
|
|
|
|
|
/**
|
|
@brief Frees an arbitrary precision integer.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_NewApaNumber
|
|
*/
|
|
void
|
|
Cudd_FreeApaNumber(
|
|
DdApaNumber number)
|
|
{
|
|
FREE(number);
|
|
|
|
} /* end of Cudd_FreeApaNumber */
|
|
|
|
|
|
/**
|
|
@brief Makes a copy of an arbitrary precision integer.
|
|
|
|
@sideeffect Changes parameter <code>dest</code>.
|
|
|
|
*/
|
|
void
|
|
Cudd_ApaCopy(
|
|
int digits,
|
|
DdConstApaNumber source,
|
|
DdApaNumber dest)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < digits; i++) {
|
|
dest[i] = source[i];
|
|
}
|
|
|
|
} /* end of Cudd_ApaCopy */
|
|
|
|
|
|
/**
|
|
@brief Adds two arbitrary precision integers.
|
|
|
|
@return the carry out of the most significant digit.
|
|
|
|
@sideeffect The result of the sum is stored in parameter <code>sum</code>.
|
|
|
|
*/
|
|
DdApaDigit
|
|
Cudd_ApaAdd(
|
|
int digits,
|
|
DdConstApaNumber a,
|
|
DdConstApaNumber b,
|
|
DdApaNumber sum)
|
|
{
|
|
int i;
|
|
DdApaDoubleDigit partial = 0;
|
|
|
|
for (i = digits - 1; i >= 0; i--) {
|
|
partial = DD_MSDIGIT(partial) + a[i] + b[i];
|
|
sum[i] = (DdApaDigit) DD_LSDIGIT(partial);
|
|
}
|
|
return((DdApaDigit) DD_MSDIGIT(partial));
|
|
|
|
} /* end of Cudd_ApaAdd */
|
|
|
|
|
|
/**
|
|
@brief Subtracts two arbitrary precision integers.
|
|
|
|
@return the borrow out of the most significant digit.
|
|
|
|
@sideeffect The result of the subtraction is stored in parameter
|
|
<code>diff</code>.
|
|
|
|
*/
|
|
DdApaDigit
|
|
Cudd_ApaSubtract(
|
|
int digits,
|
|
DdConstApaNumber a,
|
|
DdConstApaNumber b,
|
|
DdApaNumber diff)
|
|
{
|
|
int i;
|
|
DdApaDoubleDigit partial = DD_APA_BASE;
|
|
|
|
for (i = digits - 1; i >= 0; i--) {
|
|
partial = DD_MSDIGIT(partial) + DD_APA_MASK + a[i] - b[i];
|
|
diff[i] = (DdApaDigit) DD_LSDIGIT(partial);
|
|
}
|
|
return((DdApaDigit) DD_MSDIGIT(partial) - 1);
|
|
|
|
} /* end of Cudd_ApaSubtract */
|
|
|
|
|
|
/**
|
|
@brief Divides an arbitrary precision integer by a digit.
|
|
|
|
@return the remainder digit.
|
|
|
|
@sideeffect The quotient is returned in parameter <code>quotient</code>.
|
|
|
|
*/
|
|
DdApaDigit
|
|
Cudd_ApaShortDivision(
|
|
int digits,
|
|
DdConstApaNumber dividend,
|
|
DdApaDigit divisor,
|
|
DdApaNumber quotient)
|
|
{
|
|
int i;
|
|
DdApaDigit remainder;
|
|
DdApaDoubleDigit partial;
|
|
|
|
remainder = 0;
|
|
for (i = 0; i < digits; i++) {
|
|
partial = remainder * DD_APA_BASE + dividend[i];
|
|
quotient[i] = (DdApaDigit) (partial/(DdApaDoubleDigit)divisor);
|
|
remainder = (DdApaDigit) (partial % divisor);
|
|
}
|
|
|
|
return(remainder);
|
|
|
|
} /* end of Cudd_ApaShortDivision */
|
|
|
|
|
|
/**
|
|
@brief Divides an arbitrary precision integer by an integer.
|
|
|
|
@details Divides an arbitrary precision integer by a 32-bit unsigned
|
|
integer. This procedure relies on the assumption that the number of
|
|
bits of a DdApaDigit plus the number of bits of an unsigned int is
|
|
less the number of bits of the mantissa of a double. This guarantees
|
|
that the product of a DdApaDigit and an unsigned int can be
|
|
represented without loss of precision by a double. On machines where
|
|
this assumption is not satisfied, this procedure will malfunction.
|
|
|
|
@return the remainder.
|
|
|
|
@sideeffect The quotient is returned in parameter <code>quotient</code>.
|
|
|
|
@deprecated The assumption on which the correctness of this function rests
|
|
is not satisfied by modern-day 64-bit CPUs.
|
|
|
|
@see Cudd_ApaShortDivision
|
|
|
|
*/
|
|
unsigned int
|
|
Cudd_ApaIntDivision(
|
|
int digits,
|
|
DdConstApaNumber dividend,
|
|
unsigned int divisor,
|
|
DdApaNumber quotient)
|
|
{
|
|
int i;
|
|
double partial;
|
|
unsigned int remainder = 0;
|
|
double ddiv = (double) divisor;
|
|
|
|
for (i = 0; i < digits; i++) {
|
|
partial = (double) remainder * DD_APA_BASE + dividend[i];
|
|
quotient[i] = (DdApaDigit) (partial / ddiv);
|
|
remainder = (unsigned int) (partial - ((double)quotient[i] * ddiv));
|
|
}
|
|
|
|
return(remainder);
|
|
|
|
} /* end of Cudd_ApaIntDivision */
|
|
|
|
|
|
/**
|
|
@brief Shifts right an arbitrary precision integer by one binary
|
|
place.
|
|
|
|
@details The most significant binary digit of the result is taken
|
|
from parameter <code>in</code>.
|
|
|
|
@sideeffect The result is returned in parameter <code>b</code>.
|
|
|
|
*/
|
|
void
|
|
Cudd_ApaShiftRight(
|
|
int digits,
|
|
DdApaDigit in,
|
|
DdConstApaNumber a,
|
|
DdApaNumber b)
|
|
{
|
|
int i;
|
|
|
|
for (i = digits - 1; i > 0; i--) {
|
|
b[i] = (a[i] >> 1) | ((a[i-1] & 1) << (DD_APA_BITS - 1));
|
|
}
|
|
b[0] = (a[0] >> 1) | (in << (DD_APA_BITS - 1));
|
|
|
|
} /* end of Cudd_ApaShiftRight */
|
|
|
|
|
|
/**
|
|
@brief Sets an arbitrary precision integer to a one-digit literal.
|
|
|
|
@sideeffect The result is returned in parameter <code>number</code>.
|
|
|
|
*/
|
|
void
|
|
Cudd_ApaSetToLiteral(
|
|
int digits,
|
|
DdApaNumber number,
|
|
DdApaDigit literal)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < digits - 1; i++)
|
|
number[i] = 0;
|
|
number[digits - 1] = literal;
|
|
|
|
} /* end of Cudd_ApaSetToLiteral */
|
|
|
|
|
|
/**
|
|
@brief Sets an arbitrary precision integer to a power of two.
|
|
|
|
@details If the power of two is too large to be represented, the number
|
|
is set to 0.
|
|
|
|
@sideeffect The result is returned in parameter <code>number</code>.
|
|
|
|
*/
|
|
void
|
|
Cudd_ApaPowerOfTwo(
|
|
int digits,
|
|
DdApaNumber number,
|
|
int power)
|
|
{
|
|
int i;
|
|
int index;
|
|
|
|
for (i = 0; i < digits; i++)
|
|
number[i] = 0;
|
|
i = digits - 1 - power / DD_APA_BITS;
|
|
if (i < 0) return;
|
|
index = power & (DD_APA_BITS - 1);
|
|
number[i] = (DdApaDigit) 1 << index;
|
|
|
|
} /* end of Cudd_ApaPowerOfTwo */
|
|
|
|
|
|
/**
|
|
@brief Compares two arbitrary precision integers.
|
|
|
|
@return 1 if the first number is larger; 0 if they are equal; -1 if
|
|
the second number is larger.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaCompare(
|
|
int digitsFirst,
|
|
DdConstApaNumber first,
|
|
int digitsSecond,
|
|
DdConstApaNumber second)
|
|
{
|
|
int i;
|
|
int firstNZ, secondNZ;
|
|
|
|
/* Find first non-zero in both numbers. */
|
|
for (firstNZ = 0; firstNZ < digitsFirst; firstNZ++)
|
|
if (first[firstNZ] != 0) break;
|
|
for (secondNZ = 0; secondNZ < digitsSecond; secondNZ++)
|
|
if (second[secondNZ] != 0) break;
|
|
if (digitsFirst - firstNZ > digitsSecond - secondNZ) return(1);
|
|
else if (digitsFirst - firstNZ < digitsSecond - secondNZ) return(-1);
|
|
for (i = 0; i < digitsFirst - firstNZ; i++) {
|
|
if (first[firstNZ + i] > second[secondNZ + i]) return(1);
|
|
else if (first[firstNZ + i] < second[secondNZ + i]) return(-1);
|
|
}
|
|
return(0);
|
|
|
|
} /* end of Cudd_ApaCompare */
|
|
|
|
|
|
/**
|
|
@brief Compares the ratios of two arbitrary precision integers to two
|
|
unsigned ints.
|
|
|
|
@return 1 if the first number is larger; 0 if they are equal; -1 if
|
|
the second number is larger.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaCompareRatios(
|
|
int digitsFirst,
|
|
DdConstApaNumber firstNum,
|
|
unsigned int firstDen,
|
|
int digitsSecond,
|
|
DdConstApaNumber secondNum,
|
|
unsigned int secondDen)
|
|
{
|
|
int result;
|
|
DdApaNumber first, second;
|
|
unsigned int firstRem, secondRem;
|
|
|
|
first = Cudd_NewApaNumber(digitsFirst);
|
|
firstRem = Cudd_ApaIntDivision(digitsFirst,firstNum,firstDen,first);
|
|
second = Cudd_NewApaNumber(digitsSecond);
|
|
secondRem = Cudd_ApaIntDivision(digitsSecond,secondNum,secondDen,second);
|
|
result = Cudd_ApaCompare(digitsFirst,first,digitsSecond,second);
|
|
FREE(first);
|
|
FREE(second);
|
|
if (result == 0) {
|
|
if ((double)firstRem/firstDen > (double)secondRem/secondDen)
|
|
return(1);
|
|
else if ((double)firstRem/firstDen < (double)secondRem/secondDen)
|
|
return(-1);
|
|
}
|
|
return(result);
|
|
|
|
} /* end of Cudd_ApaCompareRatios */
|
|
|
|
|
|
/**
|
|
@brief Prints an arbitrary precision integer in hexadecimal format.
|
|
|
|
@return 1 if successful; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_ApaPrintDecimal Cudd_ApaPrintExponential
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaPrintHex(
|
|
FILE * fp,
|
|
int digits,
|
|
DdConstApaNumber number)
|
|
{
|
|
int i, result;
|
|
|
|
for (i = 0; i < digits; i++) {
|
|
result = fprintf(fp, "%0*x", (int) sizeof(DdApaDigit) * 2, number[i]);
|
|
if (result == EOF)
|
|
return(0);
|
|
}
|
|
return(1);
|
|
|
|
} /* end of Cudd_ApaPrintHex */
|
|
|
|
|
|
/**
|
|
@brief Prints an arbitrary precision integer in decimal format.
|
|
|
|
@return 1 if successful; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_ApaPrintHex Cudd_ApaPrintExponential
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaPrintDecimal(
|
|
FILE * fp,
|
|
int digits,
|
|
DdConstApaNumber number)
|
|
{
|
|
int i, result;
|
|
DdApaDigit remainder;
|
|
DdApaNumber work;
|
|
unsigned char *decimal;
|
|
int leadingzero;
|
|
int decimalDigits = (int) (digits * log10((double) DD_APA_BASE)) + 1;
|
|
|
|
work = Cudd_NewApaNumber(digits);
|
|
if (work == NULL)
|
|
return(0);
|
|
decimal = ALLOC(unsigned char, decimalDigits);
|
|
if (decimal == NULL) {
|
|
FREE(work);
|
|
return(0);
|
|
}
|
|
Cudd_ApaCopy(digits,number,work);
|
|
for (i = decimalDigits - 1; i >= 0; i--) {
|
|
remainder = Cudd_ApaShortDivision(digits,work,(DdApaDigit) 10,work);
|
|
decimal[i] = (unsigned char) remainder;
|
|
}
|
|
FREE(work);
|
|
|
|
leadingzero = 1;
|
|
for (i = 0; i < decimalDigits; i++) {
|
|
leadingzero = leadingzero && (decimal[i] == 0);
|
|
if ((!leadingzero) || (i == (decimalDigits - 1))) {
|
|
result = fprintf(fp,"%1d",decimal[i]);
|
|
if (result == EOF) {
|
|
FREE(decimal);
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
FREE(decimal);
|
|
return(1);
|
|
|
|
} /* end of Cudd_ApaPrintDecimal */
|
|
|
|
|
|
/**
|
|
@brief converts an arbitrary precision integer to a string in decimal format.
|
|
|
|
@return the string if successful; NULL otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_ApaPrintDecimal
|
|
|
|
*/
|
|
char *
|
|
Cudd_ApaStringDecimal(
|
|
int digits,
|
|
DdConstApaNumber number)
|
|
{
|
|
int i, fsd;
|
|
DdApaDigit remainder;
|
|
DdApaNumber work;
|
|
char *decimal, *ret;
|
|
int decimalDigits = (int) (digits * log10((double) DD_APA_BASE)) + 1;
|
|
|
|
work = Cudd_NewApaNumber(digits);
|
|
if (work == NULL) {
|
|
return(0);
|
|
}
|
|
decimal = ALLOC(char, decimalDigits);
|
|
if (decimal == NULL) {
|
|
FREE(work);
|
|
return(0);
|
|
}
|
|
Cudd_ApaCopy(digits,number,work);
|
|
for (i = decimalDigits - 1; i >= 0; i--) {
|
|
remainder = Cudd_ApaShortDivision(digits,work,(DdApaDigit) 10,work);
|
|
decimal[i] = (char) remainder;
|
|
}
|
|
FREE(work);
|
|
|
|
/* Find first significant digit. */
|
|
for (fsd = 0; fsd < decimalDigits-1; fsd++) {
|
|
if (decimal[fsd] != 0)
|
|
break;
|
|
}
|
|
ret = ALLOC(char, decimalDigits - fsd + 1);
|
|
if (ret == NULL) {
|
|
FREE(decimal);
|
|
return(NULL);
|
|
}
|
|
for (i = fsd; i < decimalDigits; i++) {
|
|
ret[i-fsd] = decimal[i] + '0';
|
|
}
|
|
ret[decimalDigits-fsd] = '\0';
|
|
FREE(decimal);
|
|
return(ret);
|
|
|
|
} /* end of Cudd_ApaStringDecimal */
|
|
|
|
|
|
/**
|
|
@brief Prints an arbitrary precision integer in exponential format.
|
|
|
|
@details Prints as an integer if precision is at least the number of
|
|
digits to be printed. If precision does not allow printing of all
|
|
digits, rounds to nearest breaking ties so that the last printed
|
|
digit is even.
|
|
|
|
@return 1 if successful; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_ApaPrintHex Cudd_ApaPrintDecimal
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaPrintExponential(
|
|
FILE * fp,
|
|
int digits,
|
|
DdConstApaNumber number,
|
|
int precision)
|
|
{
|
|
int i, first, last, result;
|
|
DdApaDigit remainder;
|
|
DdApaNumber work;
|
|
unsigned char *decimal, carry;
|
|
/* We add an extra digit to have room for rounding up. */
|
|
int decimalDigits = (int) (digits * log10((double) DD_APA_BASE)) + 2;
|
|
|
|
/* Convert to decimal. */
|
|
work = Cudd_NewApaNumber(digits);
|
|
if (work == NULL)
|
|
return(0);
|
|
decimal = ALLOC(unsigned char, decimalDigits);
|
|
if (decimal == NULL) {
|
|
FREE(work);
|
|
return(0);
|
|
}
|
|
Cudd_ApaCopy(digits,number,work);
|
|
first = decimalDigits - 1;
|
|
for (i = decimalDigits - 1; i >= 0; i--) {
|
|
remainder = Cudd_ApaShortDivision(digits,work,(DdApaDigit) 10,work);
|
|
decimal[i] = (unsigned char) remainder;
|
|
if (remainder != 0) first = i; /* keep track of MS non-zero */
|
|
}
|
|
FREE(work);
|
|
last = ddMin(first + precision, decimalDigits);
|
|
|
|
/* See if we can print as integer. */
|
|
if (decimalDigits - first <= precision) {
|
|
for (i = first; i < last; i++) {
|
|
result = fprintf(fp,"%1d", decimal[i]);
|
|
if (result == EOF) {
|
|
FREE(decimal);
|
|
return(0);
|
|
}
|
|
}
|
|
FREE(decimal);
|
|
return(1);
|
|
}
|
|
|
|
/* If we get here we need to print an exponent. Take care of rounding. */
|
|
if (last == decimalDigits) {
|
|
carry = 0;
|
|
} else if (decimal[last] < 5) {
|
|
carry = 0;
|
|
} else if (decimal[last] == 5) {
|
|
int nonZero = CUDD_FALSE;
|
|
for (i = last + 1; i < decimalDigits; i++) {
|
|
if (decimal[i] > 0) {
|
|
nonZero = CUDD_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (nonZero) {
|
|
carry = 1;
|
|
} else if (decimal[last - 1] & 1) { /* odd */
|
|
carry = 1;
|
|
} else {
|
|
carry = 0;
|
|
}
|
|
} else {
|
|
carry = 1;
|
|
}
|
|
|
|
/* Add carry. */
|
|
for (i = last - 1; i >= 0; i--) {
|
|
unsigned char tmp = decimal[i] + carry;
|
|
if (tmp < 10) {
|
|
decimal[i] = tmp;
|
|
break;
|
|
} else {
|
|
decimal[i] = tmp - 10;
|
|
}
|
|
}
|
|
|
|
/* Don't print trailing zeros. */
|
|
while (last > first && decimal[last - 1] == 0)
|
|
last--;
|
|
|
|
/* Print. */
|
|
for (i = first; i < last; i++) {
|
|
result = fprintf(fp,"%s%1d",i == first+1 ? "." : "", decimal[i]);
|
|
if (result == EOF) {
|
|
FREE(decimal);
|
|
return(0);
|
|
}
|
|
}
|
|
FREE(decimal);
|
|
result = fprintf(fp,"e+%02d",decimalDigits - first - 1);
|
|
if (result == EOF) {
|
|
return(0);
|
|
}
|
|
return(1);
|
|
|
|
} /* end of Cudd_ApaPrintExponential */
|
|
|
|
|
|
/**
|
|
@brief Counts the number of minterms of a %DD.
|
|
|
|
@details The function is assumed to depend on nvars variables. The
|
|
minterm count is represented as an arbitrary precision unsigned
|
|
integer, to allow for any number of variables CUDD supports.
|
|
|
|
@return a pointer to the array representing the number of minterms
|
|
of the function rooted at node if successful; NULL otherwise.
|
|
|
|
@sideeffect The number of digits of the result is returned in
|
|
parameter <code>digits</code>.
|
|
|
|
@see Cudd_CountMinterm
|
|
|
|
*/
|
|
DdApaNumber
|
|
Cudd_ApaCountMinterm(
|
|
DdManager const * manager,
|
|
DdNode * node,
|
|
int nvars,
|
|
int * digits)
|
|
{
|
|
DdApaNumber mmax, mmin;
|
|
st_table *table;
|
|
DdApaNumber i,count;
|
|
|
|
*digits = Cudd_ApaNumberOfDigits(nvars+1);
|
|
mmax = Cudd_NewApaNumber(*digits);
|
|
if (mmax == NULL) {
|
|
return(NULL);
|
|
}
|
|
Cudd_ApaPowerOfTwo(*digits,mmax,nvars);
|
|
mmin = Cudd_NewApaNumber(*digits);
|
|
if (mmin == NULL) {
|
|
FREE(mmax);
|
|
return(NULL);
|
|
}
|
|
Cudd_ApaSetToLiteral(*digits,mmin,0);
|
|
table = st_init_table(st_ptrcmp,st_ptrhash);
|
|
if (table == NULL) {
|
|
FREE(mmax);
|
|
FREE(mmin);
|
|
return(NULL);
|
|
}
|
|
i = cuddApaCountMintermAux(manager, Cudd_Regular(node),*digits,mmax,mmin,table);
|
|
if (i == NULL) {
|
|
FREE(mmax);
|
|
FREE(mmin);
|
|
st_foreach(table, cuddApaStCountfree, NULL);
|
|
st_free_table(table);
|
|
return(NULL);
|
|
}
|
|
count = Cudd_NewApaNumber(*digits);
|
|
if (count == NULL) {
|
|
FREE(mmax);
|
|
FREE(mmin);
|
|
st_foreach(table, cuddApaStCountfree, NULL);
|
|
st_free_table(table);
|
|
if (Cudd_Regular(node)->ref == 1) FREE(i);
|
|
return(NULL);
|
|
}
|
|
if (Cudd_IsComplement(node)) {
|
|
(void) Cudd_ApaSubtract(*digits,mmax,i,count);
|
|
} else {
|
|
Cudd_ApaCopy(*digits,i,count);
|
|
}
|
|
FREE(mmax);
|
|
FREE(mmin);
|
|
st_foreach(table, cuddApaStCountfree, NULL);
|
|
st_free_table(table);
|
|
if (Cudd_Regular(node)->ref == 1) FREE(i);
|
|
return(count);
|
|
|
|
} /* end of Cudd_ApaCountMinterm */
|
|
|
|
|
|
/**
|
|
@brief Prints the number of minterms of a %BDD or %ADD using arbitrary
|
|
precision arithmetic.
|
|
|
|
@return 1 if successful; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_ApaPrintMintermExp
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaPrintMinterm(
|
|
FILE * fp,
|
|
DdManager const * dd,
|
|
DdNode * node,
|
|
int nvars)
|
|
{
|
|
int digits;
|
|
int result;
|
|
DdApaNumber count;
|
|
|
|
count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
|
|
if (count == NULL)
|
|
return(0);
|
|
result = Cudd_ApaPrintDecimal(fp,digits,count);
|
|
FREE(count);
|
|
if (fprintf(fp,"\n") == EOF) {
|
|
return(0);
|
|
}
|
|
return(result);
|
|
|
|
} /* end of Cudd_ApaPrintMinterm */
|
|
|
|
|
|
/**
|
|
@brief Prints the number of minterms of a %BDD or %ADD in
|
|
exponential format using arbitrary precision arithmetic.
|
|
|
|
@details Parameter precision controls the number of signficant
|
|
digits printed.
|
|
|
|
@return 1 if successful; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
@see Cudd_ApaPrintMinterm
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaPrintMintermExp(
|
|
FILE * fp,
|
|
DdManager const * dd,
|
|
DdNode * node,
|
|
int nvars,
|
|
int precision)
|
|
{
|
|
int digits;
|
|
int result;
|
|
DdApaNumber count;
|
|
|
|
count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
|
|
if (count == NULL)
|
|
return(0);
|
|
result = Cudd_ApaPrintExponential(fp,digits,count,precision);
|
|
FREE(count);
|
|
if (fprintf(fp,"\n") == EOF) {
|
|
return(0);
|
|
}
|
|
return(result);
|
|
|
|
} /* end of Cudd_ApaPrintMintermExp */
|
|
|
|
|
|
/**
|
|
@brief Prints the density of a %BDD or %ADD using arbitrary
|
|
precision arithmetic.
|
|
|
|
@return 1 if successful; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
int
|
|
Cudd_ApaPrintDensity(
|
|
FILE * fp,
|
|
DdManager * dd,
|
|
DdNode * node,
|
|
int nvars)
|
|
{
|
|
int digits;
|
|
int result;
|
|
DdApaNumber count,density;
|
|
unsigned int size, remainder, fractional;
|
|
|
|
count = Cudd_ApaCountMinterm(dd,node,nvars,&digits);
|
|
if (count == NULL)
|
|
return(0);
|
|
size = (unsigned int) Cudd_DagSize(node);
|
|
density = Cudd_NewApaNumber(digits);
|
|
remainder = Cudd_ApaIntDivision(digits,count,size,density);
|
|
result = Cudd_ApaPrintDecimal(fp,digits,density);
|
|
FREE(count);
|
|
FREE(density);
|
|
fractional = (unsigned int)((double)remainder / size * 1000000);
|
|
if (fprintf(fp,".%u\n", fractional) == EOF) {
|
|
return(0);
|
|
}
|
|
return(result);
|
|
|
|
} /* end of Cudd_ApaPrintDensity */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Performs the recursive step of Cudd_ApaCountMinterm.
|
|
|
|
@details It is based on the following identity. Let <code>|f|</code> be the
|
|
number of minterms of <code>f</code>. Then:
|
|
|
|
|f| = (|f0|+|f1|)/2
|
|
|
|
where f0 and f1 are the two cofactors of f.
|
|
Uses the identity <code>|f'| = mmax - |f|</code>.
|
|
The procedure expects the argument "node" to be a regular pointer, and
|
|
guarantees this condition is met in the recursive calls.
|
|
For efficiency, the result of a call is cached only if the node has
|
|
a reference count greater than 1.
|
|
|
|
@return the number of minterms of the function rooted at node.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
static DdApaNumber
|
|
cuddApaCountMintermAux(
|
|
DdManager const * manager,
|
|
DdNode * node,
|
|
int digits,
|
|
DdApaNumber mmax,
|
|
DdApaNumber mmin,
|
|
st_table * table)
|
|
{
|
|
DdNode *Nt, *Ne;
|
|
DdApaNumber mint, mint1, mint2;
|
|
DdApaDigit carryout;
|
|
|
|
if (cuddIsConstant(node)) {
|
|
int singleRef = Cudd_Regular(node)->ref == 1;
|
|
if (node == manager->background || node == Cudd_Not(manager->one)) {
|
|
if (singleRef) {
|
|
mint = Cudd_NewApaNumber(digits);
|
|
if (mint == NULL) {
|
|
return(NULL);
|
|
}
|
|
Cudd_ApaCopy(digits, mmin, mint);
|
|
return(mint);
|
|
} else {
|
|
return(mmin);
|
|
}
|
|
} else {
|
|
if (singleRef) {
|
|
mint = Cudd_NewApaNumber(digits);
|
|
if (mint == NULL) {
|
|
return(NULL);
|
|
}
|
|
Cudd_ApaCopy(digits, mmax, mint);
|
|
return(mint);
|
|
} else {
|
|
return(mmax);
|
|
}
|
|
}
|
|
}
|
|
if (node->ref > 1 && st_lookup(table, node, (void **) &mint)) {
|
|
return(mint);
|
|
}
|
|
|
|
Nt = cuddT(node); Ne = cuddE(node);
|
|
|
|
mint1 = cuddApaCountMintermAux(manager, Nt, digits, mmax, mmin, table);
|
|
if (mint1 == NULL) return(NULL);
|
|
mint2 = cuddApaCountMintermAux(manager, Cudd_Regular(Ne), digits, mmax, mmin, table);
|
|
if (mint2 == NULL) {
|
|
if (Nt->ref == 1) FREE(mint1);
|
|
return(NULL);
|
|
}
|
|
mint = Cudd_NewApaNumber(digits);
|
|
if (mint == NULL) {
|
|
if (Nt->ref == 1) FREE(mint1);
|
|
if (Cudd_Regular(Ne)->ref == 1) FREE(mint2);
|
|
return(NULL);
|
|
}
|
|
if (Cudd_IsComplement(Ne)) {
|
|
(void) Cudd_ApaSubtract(digits,mmax,mint2,mint);
|
|
carryout = Cudd_ApaAdd(digits,mint1,mint,mint);
|
|
} else {
|
|
carryout = Cudd_ApaAdd(digits,mint1,mint2,mint);
|
|
}
|
|
Cudd_ApaShiftRight(digits,carryout,mint,mint);
|
|
/* If the refernce count of a child is 1, its minterm count
|
|
** hasn't been stored in table. Therefore, it must be explicitly
|
|
** freed here. */
|
|
if (Nt->ref == 1) FREE(mint1);
|
|
if (Cudd_Regular(Ne)->ref == 1) FREE(mint2);
|
|
|
|
if (node->ref > 1) {
|
|
if (st_insert(table, node, mint) == ST_OUT_OF_MEM) {
|
|
FREE(mint);
|
|
return(NULL);
|
|
}
|
|
}
|
|
return(mint);
|
|
|
|
} /* end of cuddApaCountMintermAux */
|
|
|
|
|
|
/**
|
|
@brief Frees the memory used to store the minterm counts recorded
|
|
in the visited table.
|
|
|
|
@return ST_CONTINUE.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
static enum st_retval
|
|
cuddApaStCountfree(
|
|
void * key,
|
|
void * value,
|
|
void * arg)
|
|
{
|
|
DdApaNumber d;
|
|
|
|
(void) key; /* avoid warning */
|
|
(void) arg; /* avoid warning */
|
|
d = (DdApaNumber) value;
|
|
FREE(d);
|
|
return(ST_CONTINUE);
|
|
|
|
} /* end of cuddApaStCountfree */
|