Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   операции с 12-разрядными числами (http://forum.oszone.net/showthread.php?t=134279)

.::.DIMA.::. 10-03-2009 09:44 1059446

операции с 12-разрядными числами
 
Решено

Busla 10-03-2009 12:45 1059588

.::.DIMA.::., ну так двоичный вывод надо самому писать: чтобы число преобразовал в строку символов из нолей и единиц. Разрядность указана для того, чтобы вы в интерфейсе нарисовали эти 12 кнопок, а хранить числа можно и в основных типах.

pva 10-03-2009 19:42 1059907

на этом коде можешь отрепетировать арифметику
Код:

#include <iostream>
#include <string>
using namespace std;

unsigned from_binary(const string& str)
{
    unsigned result = 0;

    for (unsigned pos=0; pos<str.size(); ++pos)
    {
        result = (result << 1) | (str[pos]=='1');
    }

    return result;
}

void print_binary(unsigned value)
{
//    // вариант 1: со сдвигом

//    for (unsigned bitn=32; --bitn<32; )
//    {
//        static const char bit_values[2] = "-x";
//        cout << bit_values[0x1 & (value >> bitn)];
//    }

//    cout << "\n";

    // вариант 2: перебор битов

    for (unsigned bit1=1<<31; bit1; bit1>>=1)
    {
        cout << (bit1 & value ? 'x' : '-');
    }

    cout << "\n";
}

void main()
{
    // перевели из двоичного (в с++ билдере не работает запись 0b1110101010101)
    unsigned value1 = from_binary("00001010001010010111");
    unsigned value2 = from_binary("00000010010100010001");

    print_binary(value1);
    print_binary(value2);
    print_binary(value1 & value2);
}


Drongo 10-03-2009 19:55 1059918

Цитата:

Цитата pva
Код:

unsigned value1 = from_binary("00001010001010010111");
unsigned value2 = from_binary("00000010010100010001");

»

Ух ты, класс, интересное решение. А я думал эти числа можно в два массива загнать.

pva 10-03-2009 20:29 1059952

по сути это и есть два массива типа char[], только вместо 0 и 1 соответсвенно 30 и 31. Даже наверное конструкция типа
Код:

result = (result << 1) | (0x1 & (str[pos] - '0'));
смотрелась бы лучше в from_binary()

Вот ещё прикольная интерпретация: модель микросхемы.
Код:

#include <iostream>
using namespace std;


// в чипе стоит цифровой вольтметр :) на основе простейшего ADC

char __amp_boost [4] = {0, 1, 1, 1}; // у транзистора ниже напряжения отпирания.
char __amp_fade  [4] = {0, 0, 1, 1}; // у транзистора выше напряжения отпирания.
char __amp_wave  [4] = {0, 1, 0, 1}; // фиг знает что, наверное нет такого
char __amp_neg  [4] = {1, 0, 0, 0}; // фиг знает что, наверное нет такого
char __amp_off  [4] = {0, 0, 0, 0}; // разрыв цепи

struct micro_op
{
    char op;
    char hotch_c;      // перенос вкл/выкл
    char hotch_bit1;  // операнд 1 вкл/выкл
    char hotch_bit2;  // операнд 2 вкл/выкл
    char* amp_r;      // усилитель для результата
    char* amp_c;      // усилитель для переноса
};

micro_op micro_ops[5] = {
    {'+', 1, 1, 1,  __amp_wave, __amp_fade},
    {'&', 0, 1, 1,  __amp_fade, __amp_off},
    {'|', 0, 1, 1,  __amp_boost,__amp_off},
    {'^', 0, 1, 1,  __amp_wave, __amp_off},
    {'~', 0, 1, 0,  __amp_neg,  __amp_off}};

struct macro_CPU
{
    char _f[12]; // флаги
    char _a[12]; // аккумулятор
    char _b[12]; // регистр 1
    char _c[12]; // регистр 2

    static void output(const char* name, const char* register1);
    void output();
    void operate(char op);
};

void macro_CPU::output(const char* name, const char* register1)
{
    cout << name << " : ";
    for(unsigned n=0; n<12; ++n) cout << register1[n];
    cout << "\n";
}

void macro_CPU::output()
{
    cout << "CPU state:\n";
    output("F", _f);
    output("A", _a);
    output("B", _b);
    output("C", _c);
}

void macro_CPU::operate(char op)
{
    micro_op* op_scheme;

    for ( op_scheme=micro_ops; op_scheme<micro_ops+5 && op_scheme->op!=op; ++op_scheme) {}

    if ( op_scheme < micro_ops+5)
    {
        // установка переноса полезна для многобайтовых операций
        bool c = (_f[11]=='1'); // перенос

        for (unsigned bit_n=12; --bit_n<12; )
        {
            // напряжение поступает на контакты схемы

            bool bit1 = (_b[bit_n]=='1');
            bool bit2 = (_c[bit_n]=='1');

            // получаем напряжение на смесителе
            int voltage = (c & op_scheme->hotch_c) +
                        (bit1 & op_scheme->hotch_bit1) +
                        (bit2 & op_scheme->hotch_bit2);

            // прогоняем через фильтр
            bool result = op_scheme->amp_r[voltage];
            c          = op_scheme->amp_c[voltage];

            // снимаем со схемы
            _a[bit_n] = '0' + result;
        }

        _f[11] = '0' + c; // для многобайтоывых операций
    }
}

void main()
{

    macro_CPU cpu = {
        "000000000000",  // F
        "000000000000",  // A 
        "000011010001",  // B
        "000010101001"}; // C

    cpu.output();
    cpu.operate('+'); // A = B op C
    cpu.output();
}


pva 12-03-2009 08:52 1061256

Цитата:

Цитата .::.DIMA.::.
В книгах этих примеров, к сожалению, нет »

неправда, в книгах как раз полно, на тему "двоичная арифметика"
http://yandex.ru/yandsearch?rpt=rad&...B8%D0%BA%D0%B0
если нужно просто посчитать и выдать результат, то можно просто произвести указанное действие над числами (сложить там или операцию `&`).
если нужно имитировать действия микропроцессора (то есть показать как меняются биты), то нужно писать имитирующую программу.
Определись, что тебе нужно и почитай книги то ;)

Alan85 12-03-2009 18:56 1061963

для операций AND OR и XOR можно не переводить в тип unsigned short (двойная работа). Я предлагаю вот так:
Код:

#include <iostream>
#include <string>
using namespace std;
string op_and(string s1, string s2)
{    cout<<s1<<'\n'<<"AND\n"<<s2<<'\n'<<"Equals\n";
        string ret="000000000000";
        for (int i = 0; i <= 11; i++)
          if (s1[i]=='1'&&s2[i]=='1') ret[i]='1';

        return  ret;
}

string op_or(string s1, string s2)
{
  cout<<s1<<'\n'<<"OR\n"<<s2<<'\n'<<"Equals\n";
        string ret="000000000000";
        for (int i = 0; i <= 11; i++)
          if (s1[i]=='1'||s2[i]=='1') ret[i]='1';

        return  ret;
}

string op_xor(string s1, string s2)
{
  cout<<s1<<'\n'<<"XOR\n"<<s2<<'\n'<<"Equals\n";
        string ret="111111111111";
        for (int i = 0; i <= 11; i++)
          if ((s1[i]=='1'&&s2[i]=='1')||(s1[i]=='0'&&s2[i]=='0')) ret[i]='0';

        return  ret;
}
int main(int argc, char* argv[])
{
 string s1="001111100011" ;
 string s2="001010100011" ;
 string s3="";
 s3=op_and(s1,s2);
 cout<<s3<<'\n';
 s3=op_or(s1,s2);
 cout<<s3<<'\n';
  s3=op_xor(s1,s2);
 cout<<s3<<'\n';
 cin>>s3;
        return 0;
}

А для операций ADD и SUB придется переводит в число потом добавлять, вычитать и переводить обратно. В этом помогут исходники pva

pva 12-03-2009 20:36 1062056

Alan85, напиши op_plus() :tongue:
я подскажу:
Код:

char carry_bit = '0'; // флаг переноса
...
// побитовые операции
char new_carry_bit = (s1[i]=='1' && s2[i]=='1') || (carry_bit=='1' && (s1[i]=='1' || s2[i]=='1')) ? '1' : '0';
ret[i] = (s1[i]=='0' && s2[i]=='0' && carry_bit=='0') || (new_carry_bit=='1'  && (s1[i]=='0' || s2[i]=='0' || carry_bit=='0') || ? '0' : '1';
carry_bit = new_carry_bit;

Мне просто показалось что через применение суммирования будет гораздо проще, потом пришла на ум физическая подоплёка, а потом просто унифицировал алгоритм для всех операций, поэтому он не очень похож на работу с битами

Alan85 12-03-2009 21:34 1062106

ладно... решил уж закончить раз начал:
Код:

string op_add(string s1, string s2)
{
  cout<<s1<<'\n'<<"ADD\n"<<s2<<'\n'<<"Equals\n";
  string ret="000000000000";
  int a=0;
  int b=0;
  for (int i = 0; i <= 11; i++)
  {
        if (s1[i]=='1')  {a<<=1;a+=1;  }else a<<=1  ; // преобразование строка -> число
        if (s2[i]=='1')  {b<<=1;b+=1;  }else b<<=1  ; // путем смещения разрядов
  }
  a+=b;
  for (int i = 11; i >= 0; i--) if (a%2) {ret[i]='1'; a>>=1;} else a>>=1  ; //преобразование число -> строка тем же макаром (только наоборот)

        return  ret;
}

string op_sub(string s1, string s2)
{
  cout<<s1<<'\n'<<"SUB\n"<<s2<<'\n'<<"Equals\n";
  string ret="000000000000";
  int a=0;
  int b=0;
  for (int i = 0; i <= 11; i++)
  {
        if (s1[i]=='1')  {a<<=1;a+=1;  }else a<<=1  ;
        if (s2[i]=='1')  {b<<=1;b+=1;  }else b<<=1  ;
  }
  a-=b;
  for (int i = 11; i >= 0; i--) if (a%2) {ret[i]='1'; a>>=1;} else a>>=1  ;

        return  ret;
}


pva 13-03-2009 13:54 1062670

Цитата:

Цитата Alan85
Код:

for (int i = 0; i <= 11; i++)
 {
 if (s1[i]=='1') {a<<=1;a+=1; }else a<<=1 ; // преобразование строка -> число
 if (s2[i]=='1') {b<<=1;b+=1; }else b<<=1 ; // путем смещения разрядов
 }
 a+=b;
 for (int i = 11; i >= 0; i--) if (a%2) {ret[i]='1'; a>>=1;} else a>>=1 ; //преобразование число -> строка тем же макаром (только наоборот)

»

Так не честно, побитно начал - так побитно заканчивай, не надо хитрить ;-)

Alan85 13-03-2009 13:59 1062676

ок. домой доберусь сделаю раз начал :teeth:

Alan85 13-03-2009 20:29 1063024

Код:

string op_add2(string s1, string s2)
{
  cout<<s1<<'\n'<<"ADD\n"<<s2<<'\n'<<"Equals\n";
  string ret="000000000000";
  char p=0;
  for (int i=11 ; i>=0; i--)
  {
        if (p==0&&s1[i]==s2[i]&&s1[i]=='1')  {p=1; continue;}
        if ((p==0&&s1[i]!=s2[i])||(p==1&&s1[i]==s2[i]&&s1[i]=='1')) ret[i]='1';
        if (p==1&&s1[i]==s2[i]&&s1[i]=='0') {ret[i]='1'; p=0;}
  }

        return  ret;
}


pva 14-03-2009 13:41 1063508

Цитата:

Цитата Alan85
Код:

if ((p==0&&s1[i]!=s2[i])||(p==1&&s1[i]==s2[i]&&s1[i]=='1')) ret[i]='1';
»

Какой бит переноса установится в случае p=1, s1[i]='1' и s2[i]='1'? разобрался (тут надо бы комментарий)
Ещё хочу попросить придерживаться "хорошего" стиля, то есть не использовать break, continue и goto, плохой пример подаёшь :drug: и людей запутываешь

Автор темы, мы уже всё сделали практически, ждём вашего слова

Alan85 14-03-2009 13:52 1063520

Использование goto плохой стиль (хоть и эффективный с точки зрения машинного времени - в ядре линуха вроде оно часто используется в критических секциях) . break - например в case без него никуда - чтож теперь выкидывать? а такая вещь как continue не является плохим стилем - первый раз слышу

pva 17-03-2009 17:50 1066502


Цитата:

Цитата Alan85
с точки зрения машинного времени »

Не согласен, инструкция if использует те же jmp, jne и проч. А со стальным могу на 70% согласиться пожалуй, тут уже дело вкуса играет


Время: 07:07.

Время: 07:07.
© OSzone.net 2001-