📄 spdivide.c
字号:
/* spDivide.c */
/******************* SHORT COPYRIGHT NOTICE*************************
This source code is part of the BigDigits multiple-precision
arithmetic library Version 1.0 originally written by David Ireland,
copyright (c) 2001 D.I. Management Services Pty Limited, all rights
reserved. It is provided "as is" with no warranties. You may use
this software under the terms of the full copyright notice
"bigdigitsCopyright.txt" that should have been included with
this library. To obtain a copy send an email to
<code@di-mgt.com.au> or visit <www.di-mgt.com.au/crypto.html>.
This notice must be retained in any copy.
****************** END OF COPYRIGHT NOTICE*************************/
#include "bigdigits.h"
#define B (MAX_HALF_DIGIT + 1)
static void spMultSub(DIGIT_T uu[2], DIGIT_T qhat,
DIGIT_T v1, DIGIT_T v0);
DIGIT_T spDivide(DIGIT_T *q, DIGIT_T *r, DIGIT_T u[2], DIGIT_T v)
{ /* Computes quotient q = u / v, remainder r = u mod v
where u is a double digit
and q, v, r are single precision digits.
Returns high digit of quotient (max value is 1)
Assumes normalised such that v1 >= b/2
where b is size of HALF_DIGIT
i.e. the most significant bit of v should be one
In terms of half-digits in Knuth notation:
(q2q1q0) = (u4u3u2u1u0) / (v1v0)
(r1r0) = (u4u3u2u1u0) mod (v1v0)
for m = 2, n = 2 where u4 = 0
q2 is either 0 or 1.
We set q = (q1q0) and return q2 as "overflow'
*/
DIGIT_T qhat, rhat, t, v0, v1, u0, u1, u2, u3;
DIGIT_T uu[2], q2;
/* Check for normalisation */
if (!(v & HIBITMASK))
{
*q = *r = 0;
return MAX_DIGIT;
}
/* Split up into half-digits */
v0 = LOHALF(v);
v1 = HIHALF(v);
u0 = LOHALF(u[0]);
u1 = HIHALF(u[0]);
u2 = LOHALF(u[1]);
u3 = HIHALF(u[1]);
/* Do three rounds of Knuth Algorithm D Vol 2 p272 */
/* ROUND 1. Set j = 2 and calculate q2 */
/* Estimate qhat = (u4u3)/v1 = 0 or 1
then set (u4u3u2) -= qhat(v1v0)
where u4 = 0.
*/
qhat = u3 / v1;
if (qhat > 0)
{
rhat = u3 - qhat * v1;
t = TOHIGH(rhat) | u2;
if (qhat * v0 > t)
qhat--;
}
uu[1] = 0; /* (u4) */
uu[0] = u[1]; /* (u3u2) */
if (qhat > 0)
{
/* (u4u3u2) -= qhat(v1v0) where u4 = 0 */
spMultSub(uu, qhat, v1, v0);
if (HIHALF(uu[1]) != 0)
{ /* Add back */
qhat--;
uu[0] += v;
uu[1] = 0;
}
}
q2 = qhat;
/* ROUND 2. Set j = 1 and calculate q1 */
/* Estimate qhat = (u3u2) / v1
then set (u3u2u1) -= qhat(v1v0)
*/
t = uu[0];
qhat = t / v1;
rhat = t - qhat * v1;
/* Test on v0 */
t = TOHIGH(rhat) | u1;
if ((qhat == B) || (qhat * v0 > t))
{
qhat--;
rhat += v1;
t = TOHIGH(rhat) | u1;
if ((rhat < B) && (qhat * v0 > t))
qhat--;
}
/* Multiply and subtract
(u3u2u1)' = (u3u2u1) - qhat(v1v0)
*/
uu[1] = HIHALF(uu[0]); /* (0u3) */
uu[0] = TOHIGH(LOHALF(uu[0])) | u1; /* (u2u1) */
spMultSub(uu, qhat, v1, v0);
if (HIHALF(uu[1]) != 0)
{ /* Add back */
qhat--;
uu[0] += v;
uu[1] = 0;
}
/* q1 = qhat */
*q = TOHIGH(qhat);
/* ROUND 3. Set j = 0 and calculate q0 */
/* Estimate qhat = (u2u1) / v1
then set (u2u1u0) -= qhat(v1v0)
*/
t = uu[0];
qhat = t / v1;
rhat = t - qhat * v1;
/* Test on v0 */
t = TOHIGH(rhat) | u0;
if ((qhat == B) || (qhat * v0 > t))
{
qhat--;
rhat += v1;
t = TOHIGH(rhat) | u0;
if ((rhat < B) && (qhat * v0 > t))
qhat--;
}
/* Multiply and subtract
(u2u1u0)" = (u2u1u0)' - qhat(v1v0)
*/
uu[1] = HIHALF(uu[0]); /* (0u2) */
uu[0] = TOHIGH(LOHALF(uu[0])) | u0; /* (u1u0) */
spMultSub(uu, qhat, v1, v0);
if (HIHALF(uu[1]) != 0)
{ /* Add back */
qhat--;
uu[0] += v;
uu[1] = 0;
}
/* q0 = qhat */
*q |= LOHALF(qhat);
/* Remainder is in (u1u0) i.e. uu[0] */
*r = uu[0];
return q2;
}
static void spMultSub(DIGIT_T uu[2], DIGIT_T qhat,
DIGIT_T v1, DIGIT_T v0)
{
/* Compute uu = uu - q(v1v0)
where uu = u3u2u1u0, u3 = 0
and u_n, v_n are all half-digits
even though v1, v2 are passed as full digits.
*/
DIGIT_T p0, p1, t;
p0 = qhat * v0;
p1 = qhat * v1;
t = p0 + TOHIGH(LOHALF(p1));
uu[0] -= t;
if (uu[0] > MAX_DIGIT - t)
uu[1]--; /* Borrow */
uu[1] -= HIHALF(p1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -