📄 ch24aok2.c
字号:
* a pointer to an array of INT. This array may be un-normalized.
* The second argument is a pointer to a pointer. This latter is
* not yet pointing to anything, but will (at the termination of
* this routine) be an array of INT. This will be a normalized
* copy of the first argument. If the first array is normal then
* this pointer is identical to the first. If the first argument
* is not normal, then a new array is allocated, and the first is
* de-allocated, and the incoming first pointer set to NULL
*/
if ((aUnNormal==NULL) || (aNormal==NULL) || ((*aUnNormal)==NULL))
{
/*
* If any of the incoming pointers is NULL, or the first
* array does not exist, then indicate an error:
*/
iStatus = EXIT_FAILURE;
}
else
{
/*
* We know that the incoming pointers are (apparently) OK, So
* set the initial outgoing value to be simply a copy of the
* incoming:
*/
plNormal = *aUnNormal;
/*
* Determine how many words (INTs) in the first array we have
* to scan:
*/
k = abs(**aUnNormal);
if (**aUnNormal<0)
iSign = -1;
/* Number of these which are after the point: */
n = (*aUnNormal)[1];
/* Therefore the number which are before the point: */
b = k - n - 1;
/*
* If there is anything at all in the first array, then count
* the number of zero words with which it begins:
*/
if (b>0)
{
j = (*aUnNormal)[2];
m = 0;
for (i = 2; ((j==0)&&(i<=b)); i++)
{
j = (*aUnNormal)[i];
if (j==0)
m++;
} /* end of "for/i" count loop of zero prefix words */
} /* end of "if/then" there are places before the point */
/*
* At this point we know that 'm' contains a count of the
* number of zero words at the start of the UnNormal input.
* Now count backwards (provided that there is something
* following the point) up the array, counting the number
* of zero words with which the array ends, after the point:
*/
if (n>0)
{
j = (*aUnNormal)[k];
mm = 0;
for (i = 0; ((j==0)&&(i<n)); i--)
{
j = (*aUnNormal)[k-i];
if (j==0)
mm++;
} /* End of "for/i" count loop of zero trailing words */
} /* End of "if/then" there are places after the point */
/*
* So now in 'm' we have the count of the number of leading
* words to omit, and in 'mm' we have the count of the trailing
* words to omit.
* So we need to (a) allocate a new array, and (b) copy the
* old into the new, and (c) deallocate the old array:
*/
if ((m+mm)>0)
{
/* Allocate the new normal array: */
k = abs((*aUnNormal)[0]) - m - mm;
/* Note that a normal zero has at least one leading word: */
/* do not normalize away all the digits! */
if (k<=1)
{
k = 2;
m--;
}
j = aAllocate(k, pplNormal);
/* Copy the un-normal to the normal: */
for (i=1; (i<(k+1)); i++)
{
j = i + m;
*(plNormal + i) = (*aUnNormal)[j];
}
/* Set the sign in the new, remembered from the old: */
if (iSign<0)
*plNormal = - (*plNormal);
/* de-allocate the old un-normal: */
free(*aUnNormal);
/* And tell the caller this has happened: */
*aUnNormal = NULL;
} /* end of "if/then" there was a necessity to allocate new */
/* And point the caller to the new normalized value: */
*aNormal = plNormal;
} /* end of "if/else" incoming pointers were OK */
return iStatus;
}
/* Add an INT array to an INT array */
int aAdd ( INT * aOne, INT * aTwo, INT ** aAnswer )
{
/* This routine allocates space for the answer, which the caller */
/* must, at some time, release */
int iStatus = EXIT_SUCCESS;
int i = 0;
int j = 0;
int k = 0;
int iBefore = 0;
int iAfter = 0;
int iAllocateLength = 0;
int iSign = 1;
int bUseAdd = 1;
INT carry = 0;
INT * pInt;
INT ** ppInt = &pInt;
/*
* This routine adds together two very large numbers. Each of the
* arguments is assumed to be in an array of INT. This routine
* allocates enough space for the answer, and computes the sum.
* The answer is normalized before returning to the caller.
*/
/*
* Before performing the addition the numbers have to be aligned,
* so that the number of places after the point are the same for
* both numbers. This means possibly extending the shorted number.
*/
/* Test the incoming pointers for validity: */
if ((aOne==NULL) || (aTwo==NULL) || (aAnswer==NULL))
{
/* At least one of the arguments was bad: indicate to caller: */
iStatus = EXIT_FAILURE;
return iStatus;
}
else
{
/*
* How many places are before and after the point in each
* of the addends?
*/
iAfter = max(aOne[1],aTwo[1]);
iBefore = max (abs(aOne[0])-aOne[1],abs(aTwo[0])-aTwo[1]);
/*
* Compute the maximum length of the answer array. This caters
* for the worst case of carry upwards from the top word:
*/
iAllocateLength = iBefore + iAfter + 1;
/* Allocate enough space for the answer, but only point to it */
/* locally: */
j = aAllocate(iAllocateLength, ppInt);
/*
* Now set the number of places after the point in the answer to
* be the maximum number of places af the two incoming addends:
*/
*(pInt+1) = iAfter;
/*
* We need to look at the signs of the incoming arguments. If
* these are the same, then we simply add the arguments, as if
* they were both positive, and give the answer that sign. If,
* however, they differ in sign, then we force them both positive
* and do a subtraction. After the subtraction we determine the
* outgoing sign. Hence we call either "internalAdd" or "internal-
* Subtract" to do the real calculation. Note that each of these
* internal routines normalizes its answer before returning, so
* we can just hand that answer back to the caller (after any
* adjustment of sign).
*/
if ((*aOne>0) && (*aTwo>0))
{
bUseAdd = 1;
iSign = 1;
}
else if ((*aOne<0) && (*aTwo<0))
{
bUseAdd = 1;
iSign = -1;
}
else
{
bUseAdd = 0;
iSign = 1;
}
if (bUseAdd==1)
j = internalAdd ( aOne, aTwo, ppInt );
else
{
/*
* We know that we have to subtract - these elements
* differ in sign. Place the positive element first.
* We do NOT compare the absolute or signed values of
* the two arguments here (using aCompare) - we only
* need to know their signs:
*/
if (*aOne>0)
j = internalSubtract ( aOne, aTwo, ppInt );
else
j = internalSubtract ( aTwo, aOne, ppInt );
/*
* Note that the sign will have been computed by the
* internalSubtract routine, so there is no need to
* alter it in this routine.
*/
} /* end of "if/else" we have to use internalSubtract */
/* Correct the sign of the answer: */
if (iSign<0)
**ppInt = - (**ppInt);
/* Tell caller the address of the answer: */
aAnswer = ppInt;
} /* end of "if/else" incoming pointers were OK */
return iStatus;
}
/* Subtract an INT array from an INT array */
int aSubtract ( INT * aOne, INT * aTwo, INT ** aAnswer )
{
/* This routine allocates space for the answer, which the caller */
/* must, at some time, release */
int iStatus = EXIT_SUCCESS;
int i = 0;
int j = 0;
int k = 0;
int iBefore = 0;
int iAfter = 0;
int iAllocateLength = 0;
int iSign = 1;
int bUseAdd = 1;
INT carry = 0;
INT * pInt;
INT ** ppInt = &pInt;
/*
* This routine subtracts two very large numbers. Each of the
* arguments is assumed to be in an array of INT. This routine
* allocates enough space for the answer, and computes the difference.
* The answer is normalized before returning to the caller.
*/
/* Test the incoming pointers for validity: */
if ((aOne==NULL) || (aTwo==NULL) || (aAnswer==NULL))
{
/* At least one of the arguments was bad: indicate to caller: */
iStatus = EXIT_FAILURE;
return iStatus;
}
else
{
/*
* How many places are before and after the point in each
* of the addends?
*/
iAfter = max(aOne[1],aTwo[1]);
iBefore = max (abs(aOne[0])-aOne[1],abs(aTwo[0])-aTwo[1]);
/*
* Compute the maximum length of the answer array. This caters
* for the worst case of borrow upwards from/to the top word:
*/
iAllocateLength = iBefore + iAfter + 1;
/* Allocate enough space for the answer, but only point to it */
/* locally: */
j = aAllocate(iAllocateLength, ppInt);
/*
* Now set the number of places after the point in the answer to
* be the maximum number of places af the two incoming addends:
*/
*(pInt+1) = iAfter;
/*
* We need to look at the signs of the incoming arguments. If
* these are the same, then we subtract the absolutely smaller
* from the absolutely larger, and give the result the sign of
* the absolutely larger. If the signs are different, then we
* add together the absolute values, and give the result the
* appropriate sign.
*/
if ((*aOne>0) && (*aTwo<0))
{
bUseAdd = 1;
}
else if ((*aOne<0) && (*aTwo>0))
{
bUseAdd = 1;
}
else
{
/*
* The signs are the same. Perform an internalSubtract
*/
bUseAdd = 0;
iSign = aAbsCompare ( aOne, aTwo );
if (iSign<0)
{
/*
* The first argument is smaller than the second. Take
* the first from the second, and use the sign of the
* second:
*/
j = internalSubtract ( aTwo, aOne, ppInt );
if (*aTwo<0)
*pInt = - *pInt;
} /* end of "if/then" first arg. is smaller than second */
else if (iSign>0)
{
/*
* The first argument is larger than the second. Take
* the second from the first, and use the sign of the
* first:
*/
j = internalSubtract ( aOne, aTwo, ppInt );
if (*aOne<0)
*pInt = - *pInt;
} /* end of "if/then" first arg is larger than second */
else
{
/*
* This is the special case where we know that the two
* arguments have the same sign AND are equal in magnitude,
* so the answer is zero. We simply allocate a zero array
* (which we have already done), and normalize it:
*/
j = aNormalize(ppInt, ppInt);
} /* end of "if/else" arguments are equal and opposite */
/*
* We have the answer - return to caller, indicating failure
* if detected:
*/
if (j!=0)
iStatus = EXIT_FAILURE;
return iStatus;
} /* end of "if/else" perform internalSubtract */
/*
* If control falls through to here, then we have to
* add the absolute values together, and take the
* sign of the first as the outgoing sign:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -