mldiv.cpp
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C++ 代码 · 共 259 行
CPP
259 行
#include <iostream.h>
// SP&E Vol.24(6) 579-601 (June 1994)
// "Multiple-length Division Revisited: a Tour of the Minefield"
// Per Brinch Hansen
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma inline_depth 0
template <UBIG w,UBIG b>
struct MLDiv {
UBIG d[w+1];
MLDiv( void ) {
zero( *this );
}
MLDiv( UBIG x ) {
UBIG i;
for( i = 0; i <= w; ++i ) {
if( x == 0 ) break;
d[i] = x % 10;
x /= 10;
}
for( i = i; i <= w; ++i ) {
d[i] = 0;
}
}
static void fatal( char *m ) {
fprintf( stderr, "'%s'\n", m );
exit( EXIT_FAILURE );
}
static UBIG length( MLDiv const &r ) {
UBIG i;
UBIG j;
i = w;
j = 0;
while( i != j ) {
if( r.d[i] != 0 ) {
j = i;
} else {
--i;
}
}
// cout << "length(" << r << ") " << (i+1) << endl;
return( i + 1 );
}
static void zero( MLDiv &r ) {
memset( r.d, 0, sizeof( r.d ) );
}
static void product( MLDiv &x, MLDiv const &y, UBIG k ) {
UBIG i;
UBIG m;
UBIG carry;
UBIG temp;
m = length( y );
zero( x );
carry = 0;
for( i = 0; i < m; ++i ) {
temp = y.d[i] * k + carry;
x.d[i] = temp % b;
carry = temp / b;
}
if( m <= w ) {
x.d[m] = carry;
} else {
if( carry != 0 ) {
fatal( "product overflow" );
}
}
// cout << "product: " << y << "*" << k << "=" << x << endl;
}
static void quotient( MLDiv &x, MLDiv const &y, UBIG k ) {
int i;
UBIG m;
UBIG carry;
UBIG temp;
assert( &x != &y );
m = length( y );
zero( x );
carry = 0;
for( i = m-1; i >= 0; --i ) {
temp = carry * b + y.d[i];
x.d[i] = temp / k;
carry = temp % k;
}
// cout << "quotient: " << y << "/" << k << "=" << x << endl;
}
static void remainder( MLDiv &x, MLDiv const &y, UBIG k ) {
int i;
UBIG m;
UBIG carry;
m = length( y );
zero( x );
carry = 0;
for( i = m-1; i >= 0; --i ) {
carry = ( carry * b + y.d[i] ) % k;
}
x.d[0] = carry;
// cout << "remainder: " << y << "%" << k << "=" << x << endl;
}
static MLDiv prefix( MLDiv const &r, UBIG m, UBIG n ) {
MLDiv p;
zero( p );
while( n != 0 ) {
p.d[ n-1 ] = r.d[ m ];
--n;
--m;
}
return( p );
}
static UBIG trial( MLDiv const &r, MLDiv const &d, UBIG k, UBIG m ) {
UBIG d2;
UBIG km;
UBIG r3;
UBIG x;
assert( 2 <= m && m <= (k+m) && (k+m) <= w );
km = k + m;
r3 = ( r.d[km]*b + r.d[ km-1 ] ) * b + r.d[ km-2 ];
d2 = d.d[ m-1 ]*b + d.d[ m - 2 ];
x = r3 / d2;
if( (b-1) < x ) {
x = b-1;
}
// cout << "trial: " << prefix( r, km, 3 ) << "/" << prefix( d, m-1, 2 ) << "=" << x << endl;
return( x );
}
static UBIG smaller( MLDiv const &r, MLDiv const &dq, UBIG k, UBIG m ) {
UBIG i;
UBIG j;
int ret;
assert( k <= (k+m) && (k+m) <= w );
i = m;
j = 0;
while( i != j ) {
if( r.d[i+k] != dq.d[i] ) {
j = i;
} else {
--i;
}
}
ret = ( r.d[i+k] < dq.d[i] );
// cout << "smaller: " << prefix( r, k+m, m + 1 ) << "<" << dq << "=" << ret << endl;
return( ret );
}
static void difference( MLDiv &r, MLDiv const &dq, UBIG k, UBIG m ) {
UBIG borrow;
int diff;
UBIG i;
//MLDiv sr( prefix( r, m+k, m+1 ) );
assert( k <= (k+m) && (k+m) <= w );
// cout << "difference: " << sr << "-" << dq << "=" << prefix( r, m+k, m+1 ) << endl;
borrow = 0;
for( i = 0; i <= m; ++i ) {
diff = r.d[ i+k ] - dq.d[i] - borrow + b;
r.d[ i+k ] = diff % b;
borrow = 1 - diff / b;
}
if( borrow != 0 ) {
fatal( "difference overflow" );
}
// cout << "difference: " << sr << "-" << dq << "=" << prefix( r, m+k, m+1 ) << endl;
}
static void longdivide( MLDiv const &x, MLDiv const &y,
MLDiv &q, MLDiv &r,
UBIG n, UBIG m ) {
MLDiv d;
MLDiv dq;
MLDiv tr;
UBIG f;
int k;
UBIG qt;
assert( 2 <= m && m <= n && n <= w );
f = b / ( y.d[m-1] + 1 );
product( tr, x, f );
product( d, y, f );
zero( q );
for( k = n-m; k >= 0; --k ) {
assert( 2 <= m && m <= (k+m) && (k+m) <= n && n <= w );
qt = trial( tr, d, k, m );
product( dq, d, qt );
if( smaller( tr, dq, k, m ) ) {
--qt;
product( dq, d, qt );
}
q.d[k] = qt;
difference( tr, dq, k, m );
}
quotient( r, tr, f );
}
static void division( MLDiv const &x, MLDiv const &y,
MLDiv &q, MLDiv &r ) {
UBIG m;
UBIG n;
UBIG y1;
m = length( y );
if( m == 1 ) {
y1 = y.d[ m - 1 ];
if( y1 > 0 ) {
quotient( q, x, y1 );
remainder( r, x, y1 );
} else {
fatal( "divide by 0" );
}
} else {
n = length( x );
if( m > n ) {
zero( q );
r = x;
} else {
assert( 2 <= m && m <= n && n <= w );
longdivide( x, y, q, r, n, m );
}
}
}
friend ostream & operator <<( ostream &o, MLDiv const &r ) {
int i;
for( i = w-1; i > 0; --i ) {
if( r.d[i] != 0 ) break;
}
for( i = i; i >= 0; --i ) {
cout << (unsigned)r.d[i];
}
return o;
}
};
#define IBOUND 10000
#define I_INCR 1721
#define JBOUND 10000
#define J_INCR 1193
int main() {
MLDiv<18,10> q;
MLDiv<18,10> r;
for( int i = 1; i < IBOUND; i += I_INCR ) {
MLDiv<18,10> y(i);
for( int j = 1; j < JBOUND; j += J_INCR ) {
MLDiv<18,10> x(j);
x.division( x, y, q, r );
cout << x << "/" << y << " = " << q << " (remainder " << r << ")" << endl;
}
}
return 0;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?