Перевод дробных чисел в различных с/с в Паскале

Модераторы: Duncon, Naeel Maqsudov, Игорь Акопян, Хыиуду

somebody_now
Сообщения: 35
Зарегистрирован: 02 окт 2007, 14:43

требуется написать прогу на паскале по переводу дробных чисел из 3с/с в 2с/с (выбран путь транзитом через 10с/с)
привожу пример аналогичного перевода целых:

Код: Выделить всё

program perevod;
  var i,j,ost,x1:integer;
  n:real;
  x,r:string;
    begin
    writeln('enter number for tranclate to 2c/c from 3c/c');
    readln(x);
    n:=0;
      for i:=1 to length(x) do
        begin
        j:=length(x)-i;
          if copy(x,i,1)='1' then begin
          n:=n+exp(j*ln(3));
          end else begin
            if copy(x,i,1)='2' then begin
            n:=n+2*exp(j*ln(3));
            end;
          end;
        end;
x1=trunc(n);
r:='';
       while x1>0 do
         begin
         ost:=x1 mod 2;
           if ost=0 then r:='0'+r else r:='1'+r;
           x1:=x1 div 2;
         end;
writeln('number ',x, ' has double code', r);
readln;
end.
но дробные как перевести не представляю поэтому прошу помочь!
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

Попробуй так:

Код: Выделить всё

uses crt;

var
num1s        : String;
pointpos     : Integer;
base, num  : Real;
digit	 : Integer;
i	 : Integer;

function dec2binR(x:real):string;
var
s 	: string;
xi   : Longint;
xf	: Real;
base 	: Real;
begin
s:='';
xi := trunc(x);
xf := x - xi;
repeat
	s :=chr($30 + xi and 1) + s;
        xi:=xi shr 1;
until xi=0;
if xf <> 0 then
        begin
        s := s + '.';
        base := 0.5;
        while (xf > 0) and (length(s) < 256) do
	begin
                s := s + chr(ord('0')+trunc(xf/base));
        	xf:= xf - trunc(xf/base)*base;
                base := base / 2;
        	end;
        end;
dec2binR:=s;
end;

Function IntPower(x, a:Longint):Longint;
var i:Integer;
    r:Longint;
begin
Intpower := 1;
if a = 0 then exit;
r := 1;
for i := 1 to a do r := r * x;
IntPower := r;
end;

begin
ClrScr;
Write('Input 3 CS number: ');
Readln(num1s);
pointpos := pos('.', num1s);
if pointpos = 0 then pointpos := length(num1s)+1;
Base := IntPower(3, pointpos-2);
num := 0;
For i := 1 to Length(num1s) do
    if num1s[i] <> '.' then
	begin
        digit := ord(num1s[i]) - $30;
	num := num + base * digit;
        base := base / 3;
        end;
Writeln('Representing number : ', num:10:6);
Writeln('Binary representation : ', Dec2BinR(num));
end.
It's a long way to the top if you wanna rock'n'roll
Аватара пользователя
Naeel Maqsudov
Сообщения: 2570
Зарегистрирован: 20 фев 2004, 19:17
Откуда: Moscow, Russia
Контактная информация:

Вот ссылка по теме: http://alglib.sources.ru/numbers/trans.php
Попробуйте все-таки без десятичной системы обойтись.
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

Naeel Maqsudov, здесь тогда придется создавать целый класс с поддержкой вычитания/сложения и умножения/деления чисел, которые по сути представлены как байтовый массив. С точки зрения математики: это конечно правильно - универсально и рационально, но с учетом именно этой задачи - переводящей дробное число из 3 с/с в 2 с/с представленый выше подход не принесет никаких плюсов (громадный объем кода и вычислительный операций). Дабы не реализовывать математику самому, ее целесообразно поручить процессору, переведя число в 10 с/с.
Однажды решая олимиадную задачу в году так 1998 пошел по такому пути. Требовалось определить количество девяток в числе 1*3*5*..*1997 (или другом, но в большом). Вот и пришлось реализовывать математику (благо только сумму и умножение) самому, через байтовые массивы. Это число состояло из нескольких тысяч знаков. В результате все она считала верно, но зачли 3 балла из 5. Почему? Потому что проиграл секунду времени и то что способ оригинальный, но в рамках именно этой задачи крайне не рационален. Зато универсален, т.к. можно определить кол-во любых цифр в любом громадном числе. Вопрос универсальности и решений для конкретных задач вечен и неразрешим. У каждого равное кол-во как плюсов так и минусов.
It's a long way to the top if you wanna rock'n'roll
somebody_now
Сообщения: 35
Зарегистрирован: 02 окт 2007, 14:43

somewhere,Naeel Maqsudov, спасибо за помощь, написал так, но ошибка гшдето в вычислениях перевода из 3 в 10 в последнем разряде целой части и первого в доробной (две ближайшие к запятой цифры):

Код: Выделить всё

program perto2from3;
var cel,k,i:longint;
j,c,j1,i1,k1:integer;
a,x,n,drob,b,l,u,b1,v,l1,chislo10:real;
s:string;
xx1,ost,aa,celcel:integer;
 xx,yy,bb,drobdrob:real;
 ss,rr,chislo:string;
begin
writeln('enter number:');
readln(x);
cel:=trunc(x);
drob:=x-cel;
a:=cel;
l:=cel;

  while a>=1 do
  begin
  k:=k+1;
  a:=a/10;
  end;

  for i:=1 to k do
  begin
  j:=k-i;
  b:=l/exp((k-i)*ln(10));
  c:=trunc(b);
  if trunc(b)=1 then begin
  u:=u+exp(j*ln(3));
  end else begin
  if trunc(b)=2 then begin
  u:=u+2*exp(j*ln(3));
  end;
  end;
  l:=(b-trunc(b))*(exp(j*ln(10)));
  {writeln(i,'    ',j,'    ',b:7:5,'    ',c,'    ',u,'    ',l:7:5);}
  end;
u:=u+1;

writeln('kol-vo razradov drobnoi chasti ravno: ');
readln(k1);
l1:=drob*exp(k1*ln(10));
for i1:=1 to k1 do
   begin
   j1:=-i1;
   b1:=l1/exp((k1-i1)*ln(10));
                            if trunc(b1)=1 then begin
                            v:=v+exp(j1*ln(3));
                            end else begin
                            if trunc(b1)=2 then begin
                            v:=v+2*exp(j1*ln(3));
                            end;
                            end;
   l1:=(b1-trunc(b1))*exp((k1-i1)*ln(10));
end;
chislo10:=u+v;
writeln(chislo10:9:7);

celcel:=trunc(chislo10);
drobdrob:=chislo10-celcel;
rr:='';
ss:='.';
      while celcel>0 do
      begin
      ost:=celcel mod 2;
      If ost=0 then rr:='0'+rr else rr:='1'+rr;
      celcel:=celcel div 2;
      end;

      while length(ss)<10 do
      begin
      yy:=drobdrob*2;
      aa:=trunc(yy);
      If aa=0 then ss:=ss+'0' else ss:=ss+'1';
      drobdrob:=yy-trunc(yy);
      end;

chislo:=rr+ss;
writeln('number ',x:9:7,' in 2 c/c is ',chislo:9);
readln;
end.
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

С трудом понимаю (или не понимаю) этот код, наверное мне мешают 30 глобальных переменных ))))))
Совершенно уверен что такое их количество и выражения вида exp(j*ln(3)) здесь совершенно не нужны. Воистину чужой код - потемки :-)
А чем мой вариант препода не устроил?
It's a long way to the top if you wanna rock'n'roll
somebody_now
Сообщения: 35
Зарегистрирован: 02 окт 2007, 14:43

почему же не устроил, сегодня и понесу два варианта, один как резерв..устроить должны оба)
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

свой лучше не носи... :-))
It's a long way to the top if you wanna rock'n'roll
somebody_now
Сообщения: 35
Зарегистрирован: 02 окт 2007, 14:43

пргограмма эта натолкнула меня на такой вопрос:
как любым числовым методом (не преобразуя в строку) подсчитать кол-во разрядов дробной части числа..можно было бы while'om множить на 10 но нет границы цикла..
в общем интересный такой вопрос и надеюсь не чисто риторический ;)
Аватара пользователя
somewhere
Сообщения: 1858
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

во всех системах счисления существуют "периодические" дроби, т.е. такие как
(10) 0.14285714285714... (1/7)
(2) 0.101010101010101... (~0,64) и выяснить заранее кол-во разрядов числа после запятой, думаю, невозможно. Даже 80 бит недостаточно для хранения абсолютно точного значения непериодической дроби. В теории дробь вида Х/У имеет период не более У-1 знаков.
1/7 = 0.(142857)
1/17 = 0.0(5882352941176470)
It's a long way to the top if you wanna rock'n'roll
Ответить