Умножения целых переменных произвольной длины
От: lso  
Дата: 26.03.03 12:00
Оценка:
Стоит такая задача: необходимо написать пограмму на СИ++ умножения целых переменных произвольной длины с использованием операций сложения и сдвига.
Порывшись в источниках на эту тему получил вот что:

#include <stdio.h>
#include <conio.h>

void add(unsigned char out[], unsigned char in1[],
unsigned char in2[], int n)
{int i;
int carry; // Бит переноса
unsigned w; // Рабочая переменная для сложения двух байтов
for (i=0, carry=0; i<n; i++)
{
out [i] = w = in1[i]+in2[i]+carry;
carry = (w & 0x0100) >>8;
}}

void lshift(unsigned char in[], int n)
{ int carry; // Бит переноса
int i,z;
for (carry=0, i=0; i<n; i++)
{
z=(in[i] & 0x80)>>7; // Выделить старший бит (перенос)
in[i] <<= 1; // Сдвинуть влево и установить
in[i] |=carry; // старый перенос в младший бит
carry = z; // Запомнить новый перенос
}}
void rshift(unsigned char in[], int n)
{
int carry; // Бит переноса
int i,z;
for (carry=0, i=n-1; i>=0; i--)
{
z = in[i] & 1; // Выделить младший бит (перенос)
in[i] >>= 1; // Сдвинуть вправо и установить
in[i] |= carry <<7; // старый перенос в старший бит
carry = z; // Запомнить новый перенос
}}

void mul(unsigned char out[], unsigned char aa[], unsigned char bb[], int n)
{
int i;
for (i=0; i<n; i++) out[i]=0;
for (i=0; i< n* 8; i++)
{ // Цикл по количеству битов
if (bb[0] & 1 ) // Разряд множителя равен 1
add(out,out,aa,n); // Добавить множимое к произведению
lshift(aa,n); // Множимое — влево
rshift(bb,n); // Множитель — вправо
}}


void main()
{

unsigned int a1, b1, out1;
unsigned char *out, *a, *b;

clrscr();

printf("Введите два числа : \n");
scanf("%d",&a1);
scanf("%d",&b1);

a = new char[sizeof(int)];
b = new char[sizeof(int)];
out = new char[sizeof(long int)];

a = (unsigned char*) a1;
b = (unsigned char*) b1;


mul(out,a,b,sizeof(long));

for(int i=0; i<8; i++)
printf("%d ", out[i]);

out1 = (int) out;

printf("\n%d\n",out1);

getch();
}

но проблема заключается в том, что в out записывается 0, помогите найти ошибку пожалуйста!
Re: Умножения целых переменных произвольной длины
От: UgN  
Дата: 26.03.03 15:47
Оценка:
Здравствуйте, lso, Вы писали:

lso>Стоит такая задача: необходимо написать пограмму на СИ++ умножения целых переменных произвольной длины с использованием операций сложения и сдвига.

lso>Порывшись в источниках на эту тему получил вот что:

Вспомнив, как умножать в столбик, написал:


Числа хранятся в виде двоичного массива произвольной длины младшими разрядами справа.

2All: Хочу услышать ваши замечания по использованию STL. В частности, как красиво заменить printf в CMultiplier::Print()

class CMultiplier
{
    static void Print( int n )        { printf(".%02X", n); };
public:
    typedef unsigned char  byte;
    typedef unsigned short word;
    typedef vector < byte > ByteVector;

    ByteVector Calculate( ByteVector& a, ByteVector& b )
    {
        ByteVector    r;
        r.resize( a.size() + b.size() );
        int Idx = r.size() - 1;
        int aIdx = a.size();
        while( aIdx-- )
        {
            int rIdx = Idx--;
            int bIdx = b.size();
            while( bIdx-- )
            {
                word m = multiply(  a[aIdx], b[bIdx] ) ;                
                int i = rIdx--;
                do 
                {
                    m += r[ i ];
                    r[ i -- ] = byte( m );
                } while( m >>= 8 );
            }
        };
        return r;
    };

    ByteVector Calculate( long a, long b )
    {
        ByteVector aVec;
        ByteVector bVec;
        Init( aVec, a );
        Init( bVec, b );
        return Calculate( aVec, bVec );
    };

    void Print( ByteVector& V ){ for_each( V.begin(), V.end(), print );};    
    
protected:

    word multiply( word m1, byte m2 )
    {
        word a = m1;
        word result = 0;
        while( m2 )
        {
            result += (  ( m2 & 1 ) ? a : 0 );
            a <<= 1;
            m2 >>= 1;
        }; 
        return result;
    };

    void Init( ByteVector& V, unsigned int n )
    {
        while( n )
        {
            V.push_back( n & 0xFF );
            n >>= 8;
        };
        reverse( V.begin(), V.end() );
    };
};



А вот так использовать:

int main(int argc, char* argv[])
{
    int m = 0xFFFFFFFF;
    int n = 0xFFFFFFFF;
    int x = 0xFFFFFFFF;
    int y = 0xFFFFFFFF;
    
    CMultiplier M;
    M.Print( M.Calculate( CMultiplier().Calculate( x, y ), CMultiplier().Calculate( m, n ) ) );
    return 0;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.