Показать полную графическую версию : операции с 12-разрядными числами
.::.DIMA.::.
10-03-2009, 09:44
Решено
.::.DIMA.::., ну так двоичный вывод надо самому писать: чтобы число преобразовал в строку символов из нолей и единиц. Разрядность указана для того, чтобы вы в интерфейсе нарисовали эти 12 кнопок, а хранить числа можно и в основных типах.
на этом коде можешь отрепетировать арифметику
#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);
}
unsigned value1 = from_binary("00001010001010010111");
unsigned value2 = from_binary("00000010010100010001"); »Ух ты, класс, интересное решение. А я думал эти числа можно в два массива загнать.
по сути это и есть два массива типа 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();
}
В книгах этих примеров, к сожалению, нет »
неправда, в книгах как раз полно, на тему "двоичная арифметика"
http://yandex.ru/yandsearch?rpt=rad&text=%D0%B4%D0%B2%D0%BE%D0%B8%D1%87%D0%BD%D0%B0%D1%8F%20%D0%B0%D1%80%D0%B8%D1%84%D0%BC%D0%B5%D1%82%D 0%B8%D0%BA%D0%B0
если нужно просто посчитать и выдать результат, то можно просто произвести указанное действие над числами (сложить там или операцию `&`).
если нужно имитировать действия микропроцессора (то есть показать как меняются биты), то нужно писать имитирующую программу.
Определись, что тебе нужно и почитай книги то ;)
для операций 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
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;
Мне просто показалось что через применение суммирования будет гораздо проще, потом пришла на ум физическая подоплёка, а потом просто унифицировал алгоритм для всех операций, поэтому он не очень похож на работу с битами
ладно... решил уж закончить раз начал:
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;
}
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 ; //преобразование число -> строка тем же макаром (только наоборот)
»
Так не честно, побитно начал - так побитно заканчивай, не надо хитрить ;-)
ок. домой доберусь сделаю раз начал :teeth:
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;
}
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: и людей запутываешь
Автор темы, мы уже всё сделали практически, ждём вашего слова
Использование goto плохой стиль (хоть и эффективный с точки зрения машинного времени - в ядре линуха вроде оно часто используется в критических секциях) . break - например в case без него никуда - чтож теперь выкидывать? а такая вещь как continue не является плохим стилем - первый раз слышу
с точки зрения машинного времени »
Не согласен, инструкция if использует те же jmp, jne и проч. А со стальным могу на 70% согласиться пожалуй, тут уже дело вкуса играет
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.