Zapis zmiennoprzecinkowy

ef559f3daa68e17025a47864632e4f7e.gif

Z liczbami zmiennoprzecinkowymi (ang. floating point numbers) spotkaliście się już zapewne na zajęciach z fizyki. Otóż zapis dużych liczb (lub bardzo małych) w normalnej notacji pozycyjnej jest niewygodny, gdyż wymaga sporej ilości cyfr. Dlatego  liczby takie zapisuje się w sposób następujący:

3,25 99c4c1f6491e9fb0d2fe47790db0018d.gif 1033

Zapis składa się z trzech liczb:

m - mantysy, u nas równej 3,25
p - podstawy systemu, u nas równej 10
c - cechy, u nas równej 33

Wartość liczby zmiennoprzecinkowej obliczamy zgodnie ze wzorem:

L = m 99c4c1f6491e9fb0d2fe47790db0018d.gif pc

Wzór pozwala obliczyć wartość liczby zmiennoprzecinkowej zapisanej w dowolnym systemie pozycyjnym, a nie tylko dziesiętnym.

92094525c038e62d2f6a3cdca75c1d57.gif

 

Obliczyć wartość zmiennoprzecinkowej liczby trójkowej 2,21 99c4c1f6491e9fb0d2fe47790db0018d.gif 1021(3).

Najpierw obliczamy wartości poszczególnych składników liczby zmiennoprzecinkowej pamiętając, iż każdy z nich jest zapisany w systemie trójkowym:

m = 2,21(3) = 2 99c4c1f6491e9fb0d2fe47790db0018d.gif 30 + 2 99c4c1f6491e9fb0d2fe47790db0018d.gif 3-1 + 1 99c4c1f6491e9fb0d2fe47790db0018d.gif 3-2 = 2 99c4c1f6491e9fb0d2fe47790db0018d.gif 1 + 2 99c4c1f6491e9fb0d2fe47790db0018d.gif 1/3 + 1 99c4c1f6491e9fb0d2fe47790db0018d.gif 1/9 = 2 + 2/3 + 1/9 = 2 7/9

p = 10(3) = 1 99c4c1f6491e9fb0d2fe47790db0018d.gif 31 + 0 99c4c1f6491e9fb0d2fe47790db0018d.gif 30 = 3

c = 21(3) = 2 99c4c1f6491e9fb0d2fe47790db0018d.gif 31 + 1 99c4c1f6491e9fb0d2fe47790db0018d.gif 30 = 2 99c4c1f6491e9fb0d2fe47790db0018d.gif 3 + 1 99c4c1f6491e9fb0d2fe47790db0018d.gif 1 = 6 + 1 = 7

Teraz wykorzystujemy podany wzór do wyznaczenia wartości dziesiętnej tej liczby:

L = m 99c4c1f6491e9fb0d2fe47790db0018d.gif pc = 2 7/9 99c4c1f6491e9fb0d2fe47790db0018d.gif 37 = 25/9 99c4c1f6491e9fb0d2fe47790db0018d.gif 37 = 25 99c4c1f6491e9fb0d2fe47790db0018d.gif 35 = 25 99c4c1f6491e9fb0d2fe47790db0018d.gif 243 = 6075


Obliczyć wartość zmiennoprzecinkowej liczby szesnastkowej A,CB 99c4c1f6491e9fb0d2fe47790db0018d.gif 10D.

m = A,CB(16) = A 99c4c1f6491e9fb0d2fe47790db0018d.gif 160 + C 99c4c1f6491e9fb0d2fe47790db0018d.gif 16-1 + B 99c4c1f6491e9fb0d2fe47790db0018d.gif 16-2
m = A,CB(16) = 10 99c4c1f6491e9fb0d2fe47790db0018d.gif 160 + 12 99c4c1f6491e9fb0d2fe47790db0018d.gif 16-1 + 11 99c4c1f6491e9fb0d2fe47790db0018d.gif 16-2
m = A,CB(16) = 10 99c4c1f6491e9fb0d2fe47790db0018d.gif 1 + 12 99c4c1f6491e9fb0d2fe47790db0018d.gif 1/16 + 11 99c4c1f6491e9fb0d2fe47790db0018d.gif 1/256
m = A,CB(16) = 10 + 12/16 + 11/256
m = A,CB(16) = 10 + 192/256 + 11/256
m = A,CB(16) = 10 203/256

p = 10(16) = 1 99c4c1f6491e9fb0d2fe47790db0018d.gif 161 + 0 99c4c1f6491e9fb0d2fe47790db0018d.gif 160 = 16

c = D(16) = D 99c4c1f6491e9fb0d2fe47790db0018d.gif 160 = 13 99c4c1f6491e9fb0d2fe47790db0018d.gif 160 = 13

L = m 99c4c1f6491e9fb0d2fe47790db0018d.gif pc = 10 203/256 99c4c1f6491e9fb0d2fe47790db0018d.gif 1613 = 2763/256 99c4c1f6491e9fb0d2fe47790db0018d.gif 1613 = 2763 99c4c1f6491e9fb0d2fe47790db0018d.gif 1611 = 2763 99c4c1f6491e9fb0d2fe47790db0018d.gif 17592186044416

L = 48607210040721408

Zapis zmiennoprzecinkowy - skąd wzięła się nazwa tego sposobu zapisu liczb? Otóż położenie przecinka w mantysie nie jest ustalone i może się dowolnie zmieniać. Poniższe zapisy oznaczają tę samą liczbę:

325 99c4c1f6491e9fb0d2fe47790db0018d.gif 1020 = 32,5 99c4c1f6491e9fb0d2fe47790db0018d.gif 1021 = 3,25 99c4c1f6491e9fb0d2fe47790db0018d.gif 1022 = 0,325 99c4c1f6491e9fb0d2fe47790db0018d.gif 1023 = 0,0325 99c4c1f6491e9fb0d2fe47790db0018d.gif 1024, itd.

Oczywiście zmiana położenia przecinka w mantysie wpływa na wartość cechy liczby. Reguła jest bardzo prosta i obowiązuje we wszystkich systemach pozycyjnych (dlaczego?):

Przesunięcie przecinka o 1 pozycję w lewo wymaga zwiększenia cechy o 1.

Przesunięcie przecinka o 1 pozycję w prawo wymaga zmniejszenia cechy o 1.

Postaraj się uzasadnić te reguły dla dowolnego systemu pozycyjnego.

Ponieważ liczbę zmiennoprzecinkową można zapisywać w różny sposób, przyjęto tzw. postać znormalizowaną.

Znormalizowana liczba zmiennoprzecinkowa to taka, w której mantysa spełnia nierówność:

p > | m | e39970b2b198376aa90fff1b168e5196.gif 1

Według tej definicji z podanych na początku rozdziału zapisów zmiennoprzecinkowych postacią znormalizowaną jest jedynie zapis 3,25 99c4c1f6491e9fb0d2fe47790db0018d.gif 1022.

a2ef0daf1c9ad453820c16ac7b2bf7c2.gif
DLA
GENIUSZA

41f9e5777d7ca39e7e5f7d6eb04370bc.gif

Jeśli dokładnie przeczytaliście ze zrozumieniem poprzednie rozdziały naszego opracowania, to zadanie przeliczania liczb z systemu dziesiętnego na zapis zmiennoprzecinkowy w systemie o dowolnej podstawie jest dziecinnie łatwe. Jeśli nie, to proponuję to zrobić.

Algorytm przeliczania liczby dziesiętnej na liczbę zmiennoprzecinkową w innym systemie pozycyjnym
  1. Obliczamy mantysę przy cesze równej 0. W tym celu wystarczy przeliczyć daną liczbę dziesiętną, na liczbę w systemie docelowym.
  2. Normalizujemy mantysę modyfikując przy tym odpowiednio cechę liczby
  3. Koniec

92094525c038e62d2f6a3cdca75c1d57.gif

 

Dla przykładu zapiszmy liczbę dziesiętną 1275,125 jako zmiennoprzecinkową liczbę w systemie czwórkowym.

Najpierw przeliczamy liczbę 1275,125 na system czwórkowy. Robimy to osobno dla części całkowitej i ułamkowej:

1275 div 4 =  318  i reszta 3
318 div 4 =  79  i reszta 2
79 div 4 =  19  i reszta 3
19 div 4 =  4  i reszta 3
4 div 4 =  1  i reszta 0
1 div 4 =  0  i reszta 1, koniec

1275(10) = 103323(4)

Teraz przeliczamy na system czwórkowy część ułamkową liczby:

0,125 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  0,5  - cyfra 0
0,5 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  2,0  - cyfra 2 i kończymy, ponieważ część ułamkowa wynosi 0

0,125(10) = 0,02(4).

Łączymy ze sobą oba wyniki i otrzymujemy postać czwórkową przeliczanej liczby dziesiętnej:

1275,125(10) = 103323,02(4)

Liczbę tę zapisujemy z cechą równą 0, czyli

103323,02 99c4c1f6491e9fb0d2fe47790db0018d.gif 100(4)

Normalizujemy mantysę. W tym celu przecinek należy przesunąć o 5 pozycji w lewo, zatem cecha wzrośnie do wartości 5, co w systemie czwórkowym ma zapis 11(4) i ostatecznie:

1275,125(10) = 1,0332302 99c4c1f6491e9fb0d2fe47790db0018d.gif 1011(4)


Zadanie to można rozwiązać również w inny sposób. Mantysę i cechę docelowej liczby zmiennoprzecinkowej możemy wyznaczyć w systemie dziesiętnym, a następnie liczby te przeliczyć na system docelowy. Korzystamy tutaj z faktu, iż przesunięcie przecinka w systemie docelowym odpowiada pomnożeniu wartości liczby przez podstawę tego systemu (przesunięcie w prawo) lub podzieleniu jej przez podstawę (przesunięcie w lewo). Zatem:

1275,125 = 1275,125 99c4c1f6491e9fb0d2fe47790db0018d.gif 40
1275,125 = 318,78125 99c4c1f6491e9fb0d2fe47790db0018d.gif 41
1275,125 = 79,6953125 99c4c1f6491e9fb0d2fe47790db0018d.gif 42
1275,125 = 19,923828125 99c4c1f6491e9fb0d2fe47790db0018d.gif 43
1275,125 = 4,98095703125 99c4c1f6491e9fb0d2fe47790db0018d.gif 44
1275,125 = 1,2452392578125 99c4c1f6491e9fb0d2fe47790db0018d.gif
45

Teraz otrzymane liczby wystarczy zamienić na system czwórkowy i mamy gotową zmiennoprzecinkową postać znormalizowaną przeliczanej liczby.

m = 1,2452392578125

Część całkowita wynosi 1, obliczamy zatem część ułamkową mantysy:

0,2452392578125 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  0,98095703125  - cyfra 0
0,98095703125 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  3,923828125  - cyfra 3
0,923828125 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  3,6953125  - cyfra 3
0,6953125 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  2,78125  - cyfra 2
0,78125 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  3,125  - cyfra 3
0,125 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  0,5  - cyfra 0
0,5 99c4c1f6491e9fb0d2fe47790db0018d.gif 4 =  2,0  - cyfra 2 i koniec, gdyż część ułamkowa wynosi zero

m = 1,10332302(4)

p = 4(10) = 10(4)

c = 5(10) = 11(4)

Zatem ostatecznie:

1275,125(10) = 1,0332302 99c4c1f6491e9fb0d2fe47790db0018d.gif 1011(4).

81f1731ffbfa9faed92ec192beba9011.gif

21475e93ec1f9dc525b5be09ee093b45.gif    
   
   

31703013aee209c08dfa0c2678d434f4.gif

Poniższe, przykładowe programy są praktyczną realizacją omawianego w tym rozdziale algorytmu. Zapewne można je napisać bardziej efektywnie. To już twoje zadanie. Dokładny opis stosowanych środowisk programowania znajdziesz we wstępie. Programy przed opublikowaniem w serwisie edukacyjnym zostały dokładnie przetestowane. Jeśli jednak znajdziesz jakąś usterkę (co zawsze może się zdarzyć), to prześlij o niej informację do autora. Pozwoli to ulepszyć nasze artykuły. Będziemy Ci za to wdzięczni.

 
       

Program dokonuje przeliczenia liczby zmiennoprzecinkowej zapisanej w jednym systemie pozycyjnym na inny system pozycyjny. W programie wykorzystano prezentowane wcześniej algorytmy, dlatego nie opisujemy ich już tutaj.

Wydruk z uruchomionego programu
Przeliczanie liczb zmiennoprzecinkowych
---------------------------------------
(C)2005 mgr Jerzy Wałaszek I LO Tarnów

Podstawa źródłowa = 10

Mantysa = 23,56
Cecha = -2

Podstawa docelowa = 2

23,56x10^-2(10) = 1,111000101x10^-11(2)

KONIEC. Naciśnij dowolny klawisz...
Microsoft Visual Basic 2005 Express Edition

Program odczytuje podstawę źródłową systemu pozycyjnego, w którym zapisana jest wejściowa liczba zmiennoprzecinkowa. Następnie odczytywana jest mantysa (jako liczba stałoprzecinkowa) oraz cecha (jako liczba całkowita). Zarówno mantysa jak i cecha muszą być zapisane w systemie pozycyjnym o podanej wcześniej podstawie. Na koniec podajemy podstawę systemu docelowego, a program oblicza wartość wprowadzonej liczby i przekształca ją na znormalizowany zapis zmiennoprzecinkowy w systemie docelowym.

a2ef0daf1c9ad453820c16ac7b2bf7c2.gif
DLA
GENIUSZA

Zadanie dla ambitnych

Prezentowane algorytmy posiadają pewne ograniczenia. Czy potrafisz je znaleźć w tym programie? Zaproponuj sposoby ich uniknięcia.

 

Borland
Delphi 7.0
Personal
Edition
// Program przeliczający liczby zmiennoprzecinkowe.
//-------------------------------------------------
// (C)2005 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//-------------------------------------------------

program Systemy;

{$APPTYPE CONSOLE}


// Funkcja sprawdza poprawność zapisu liczby
// Wejście:
// s - zapis liczby w postaci stałoprzecinkowej
// p - podstawa systemu
// intg - true = liczba musi być całkowita
// Wyjście:
// true, jeśli zapis jest prawidłowy
//------------------------------------------------
function Test(s : string; p : cardinal; intg : boolean) : boolean;
var
i,c : integer;
pc,prz : boolean;
begin
Test := true;
pc := false; prz := false;
for i := 1 to length(s) do
case s[i] of
' ' : continue;
'-' : if pc or prz then
begin
Test := false; break;
end
else pc := true;
',' : if prz or intg then
begin
Test := false; break;
end
else prz := true;
else
begin
c := ord(UpCase(s[i])) - 48;
if c > 9 then dec(c,7);
if c >= p then
begin
Test := false; break;
end;
end;
end;
end;

// Funkcja oblicza wartość liczby
// Wejście:
// s - łańcuch znakowy z zapisem liczby
// p - podstawa systemu liczbowego zapisu liczby
// Wyjście:
// wartość liczby zapisanej w s
//------------------------------------------------
function Wartosc(s : string; p : cardinal) : real;
var
Lc,Lu,w : extended;
c,i : cardinal;
znak : integer;
u : boolean;
begin
Lc := 0; Lu := 0; w := 1; u := false; znak := 1;
for i := 1 to length(s) do
case s[i] of
'-' : znak := -1;
',' : u := true;
else
begin
c := ord(UpCase(s[i])) - 48;
if c > 9 then dec(c,7);
if u then
begin
Lu := p * Lu + c;
w := p * w;
end
else Lc := p * Lc + c;
end;
end;
Wartosc := znak * (Lc + Lu / w);
end;

// Funkcja oblicza wartość potęgi
// Wejście:
// a - liczba podnoszona do potęgi
// n - wartość wykładnika potęgowego
// Wyjście:
// a^n
//------------------------------------
function Potega(a,n : integer) : real;
var
p : extended;
begin
p := 1;
while n > 0 do
begin
p := p * a;
dec(n);
end;
while n < 0 do
begin
p := p / a;
inc(n);
end;
Potega := p;
end;

// Funkcja znajduje zapis stałoprzecinkowy podanej liczby
// Wejście:
// L - wartość liczby
// p - podstawa systemu liczbowego zapisu liczby
// Wyjście:
// zapis liczby w systemie o podstawie p
//-------------------------------------------------------
function Przelicz(L : real; p : cardinal) : string;
var
sc,su : string;
c : cardinal;
Lc,Lu : extended;
znak : boolean;
begin
znak := false; sc := ''; su := '';

// Algorytm obsługuje liczby nieujemne. Jeśli więc wartość liczby
// jest ujemna, to zapamiętujemy jej znak i zmieniamy ją na dodatnią

if L < 0 then
begin
L := -L;
znak := true;
end;

// Wyznaczamy część całkowitą Lc oraz część ułamkową Lu.
// Część ułamkowa zostaje zaokrąglona do około 10 cyfr po
// przecinku.

Lc := trunc(L);
Lu := frac(L);

// Wyznaczamy zapis części całkowitej w sc

repeat
c := trunc(Lc - trunc(Lc / p) * p);
if c < 10 then
sc := char(c + 48) + sc
else
sc := char(c + 55) + sc;
Lc := trunc(Lc / p);
until Lc = 0;

// Jeśli część ułamkowa jest niezerowa, to wyznaczamy jej
// zapis w su. Na końcu zapisu usuwamy zera nieznaczące

if Lu > 0 then
begin
repeat
Lu := Lu * p;
c := trunc(Lu);
Lu := Lu - c;
if c < 10 then
su := su + char(c + 48)
else
su := su + char(c + 55);
until (Lu = 0) or (length(su) = 10);
while (su <> '') and (su[length(su)] = '0') do
Delete(su,length(su),1);
su = "," + su
end;

// Jeśli konieczne, dodajemy znak liczby i całość łączymy
// w jeden zapis.

if znak then sc := '-' + sc;
Przelicz := sc + su;
end;

//**********************
//*** PROGRAM GŁÓWNY ***
//**********************

var
m : real;
c : integer;
p1,p2 : cardinal;
s1,s2 : string;
begin
writeln('Przeliczanie liczb zmiennoprzecinkowych');
writeln('---------------------------------------');
writeln('(C)2005 mgr Jerzy Walaszek I LO Tarnow');
writeln;
write('Podstawa zrodlowa = '); readln(p1);
if p1 in [2..36] then
begin
writeln;
write('Mantysa = '); readln(s1);
if Test(s1,p1,false) then
begin
write('Cecha = '); readln(s2);
if Test(s2,p1,true) then
begin
writeln;
write('Podstawa docelowa = '); readln(p2);
if p2 in [2..36] then
begin

// Obliczamy wartość liczby. Początkowo mantysa jest równa tej
// wartości, a cecha jest równa 0.

m := Wartosc(s1,p1) * Potega(p1,round(Wartosc(s2,p1)));
c := 0;

// Normalizujemy mantysę do przedziału <1,p>

if m <> 0 then
begin
while Abs(m) >= p2 do
begin
m := m / p2;
inc(c);
end;
while Abs(m) < 1 do
begin
m := m * p2;
dec(c);
end;
end;
writeln;
writeln(s1,'x10^',s2,'(',p1,') = ',
Przelicz(m,p2),'x10^',Przelicz(c,p2),'(',p2,')');
end
else
writeln('Nieprawidlowa podstawa docelowa');
end
else
writeln('Nieprawidlowa cecha');
end
else
writeln('Nieprawidlowa mantysa');
end
else
writeln('Nieprawidlowa podstawa zrodlowa');
writeln;
writeln('Nacisnij klawisz Enter...');
readln;
end.
Borland
C++ Builder
6.0
Personal
Edition
// Program przeliczający liczby zmiennoprzecinkowe.
//-------------------------------------------------
// (C)2005 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//-------------------------------------------------

#include <cmath>
#include <iostream>
#include <string>

using namespace std;

// Funkcja sprawdza poprawność zapisu liczby
// Wejście:
// s - zapis liczby w postaci stałoprzecinkowej
// p - podstawa systemu
// intg - true = liczba musi być całkowita
// Wyjście:
// true, jeśli zapis jest prawidłowy
//------------------------------------------------
bool Test(string s, unsigned p, bool intg)
{
int i,c;
bool pc,prz;

pc = prz = false;
for(i = 0; i < s.length(); i++)
switch(s[i])
{
case '-' : if(pc || prz) return(false); else pc = true;
case ' ' : break;
case ',' : if(prz || intg) return(false); else prz = true;
break;
default : c = (int)(toupper(s[i])) - 48;
if(c > 9) c -= 7;
if(c >= p) return false;
break;
}
return true;
}

// Funkcja oblicza wartość liczby
// Wejście:
// s - łańcuch znakowy z zapisem liczby
// p - podstawa systemu liczbowego zapisu liczby
// Wyjście:
// wartość liczby zapisanej w s
//------------------------------------------------
double Wartosc(string s, unsigned p)
{
unsigned c,i;
long double Lc,Lu,w;
int znak;
bool u;

Lc = Lu = 0; znak = 1; w = 1; u = false;
for(i = 0; i < s.length(); i++)
switch(s[i])
{
case '-' : znak = -1;
case ' ' : break;
case ',' : u = true; break;
default : c = (int)(toupper(s[i])) - 48;
if(c > 9) c -= 7;
if(u)
{
Lu = p * Lu + c; w *= p;
}
else Lc = p * Lc + c;
break;
}
return znak * (Lc + Lu / w);
}

// Funkcja oblicza wartość potęgi
// Wejście:
// a - liczba podnoszona do potęgi
// n - wartość wykładnika potęgowego
// Wyjście:
// a^n
//------------------------------------
double Potega(int a, int n)
{
long double p;

p = 1;
while(n > 0)
{
p *= a; n--;
}
while(n < 0)
{
p /= a; n++;
}
return(p);
}

// Funkcja znajduje zapis stałoprzecinkowy podanej liczby
// Wejście:
// L - wartość liczby
// p - podstawa systemu liczbowego zapisu liczby
// Wyjście:
// zapis liczby w systemie o podstawie p
//-------------------------------------------------------
string Przelicz(double L, unsigned p)
{
string sc,su;
unsigned c;
long double Lu,Lc;
bool znak;

znak = false; sc = su = "";

// Algorytm obsługuje liczby nieujemne. Jeśli więc wartość liczby
// jest ujemna, to zapamiętujemy jej znak i zmieniamy ją na dodatnią

if(L < 0)
{
L = -L; znak = true;
}

// Wyznaczamy część całkowitą Lc oraz część ułamkową Lu.
// Część ułamkowa zostaje zaokrąglona do około 10 cyfr po
// przecinku.

Lc = floor(L); Lu = L - Lc;

// Wyznaczamy zapis części całkowitej w sc

do
{
c = (int)floor(Lc - floor(Lc / p) * p);
if(c < 10)
sc = (char)(c + 48) + sc;
else
sc = (char)(c + 55) + sc;
Lc = floor(Lc / p);
} while(Lc);

// Jeśli część ułamkowa jest niezerowa, to wyznaczamy jej
// zapis w su. Na końcu zapisu usuwamy zera nieznaczące

if(Lu)
{
do
{
Lu = Lu * p;
c = (int)floor(Lu);
Lu = Lu - c;
if(c < 10) su += (char)(c + 48); else su += (char)(c + 55);
} while(Lu && su.length() < 10);
while((su != "") && (su[su.length()-1] == '0'))
su.erase(su.length()-1);
su = "," + su;
}

// Jeśli konieczne, dodajemy znak liczby i całość łączymy
// w jeden zapis.

if(znak) sc = "-" + sc;
return sc + su;
}

//**********************
//*** PROGRAM GŁÓWNY ***
//**********************

main()
{
double m;
int c;
unsigned p1,p2;
string s1,s2;
char z[1];

cout << "Przeliczanie liczb zmiennoprzecinkowych\n"
"---------------------------------------\n"
"(C)2005 mgr Jerzy Walaszek I LO Tarnow\n\n"
"Podstawa zrodlowa = "; cin >> p1;
if((p1 > 1) && (p1 < 37))
{
cout << "\nMantysa = "; cin >> s1;
if(Test(s1,p1,false))
{
cout << "Cecha = "; cin >> s2;
if(Test(s2,p1,true))
{
cout << "\nPodstawa docelowa = "; cin >> p2;
if((p2 > 1) && (p2 < 37))
{

// Obliczamy wartość liczby. Początkowo mantysa jest równa tej
// wartości, a cecha jest równa 0.

m = Wartosc(s1,p1) * Potega(p1,(int)Wartosc(s2,p1));
c = 0;

// Normalizujemy mantysę do przedziału <1,p)

if(m)
{
while(fabs(m) >= p2)
{
m /= p2; c++;
};
while(fabs(m) < 1 )
{
m *= p2; c--;
}
}
cout << endl << s1 << "x10^" << s2 << "(" << p1 << ") = "
<< Przelicz(m,p2) << "x10^" << Przelicz(c,p2)
<< "(" << p2 << ")";
}
else cout << "Nieprawidlowa podstawa docelowa";
}
else cout << "Nieprawidlowa cecha";
}
else cout << "Nieprawidlowa mantysa";
}
else cout << "Nieprawidlowa podstawa zrodlowa";
cout << "\n\nNacisnij ENTER...\n";
cin.getline(z,1);
cin.getline(z,1);
}
Microsoft
Visual
Basic 2005
Express
Edition
' Program przeliczający liczby zmiennoprzecinkowe.
'-------------------------------------------------
' (C)2005 mgr Jerzy Wałaszek
' I Liceum Ogólnokształcące
' im. K. Brodzińskiego
' w Tarnowie
'-------------------------------------------------

Option Explicit On

Module Module1

' Funkcja sprawdza poprawność zapisu liczby
' Wejście:
' s - zapis liczby w postaci stałoprzecinkowej
' p - podstawa systemu
' intg - True = liczba musi być całkowita
' Wyjście:
' True, jeśli zapis jest prawidłowy
'------------------------------------------------
Public Function Test(ByVal s As String, ByVal p As Integer, _
ByVal intg As Boolean) As Boolean
Dim i, c As Integer
Dim pc, prz As Boolean

s = s.ToUpper()
pc = False : prz = False
For i = 0 To s.Length() - 1
Select Case s.Chars(i)
Case " " : Continue For
Case "-" : If pc Or prz Then
Return False
Else
pc = True
End If
Case "," : If prz Or intg Then
Return False
Else
prz = True
End If
Case Else
c = Asc(s.Chars(i)) - 48
If c > 9 Then c -= 7
If c >= p Then Return False
End Select
Next
Return True
End Function

' Funkcja oblicza wartość liczby
' Wejście:
' s - łańcuch znakowy z zapisem liczby
' p - podstawa systemu liczbowego zapisu liczby
' Wyjście:
' wartość liczby zapisanej w s
'------------------------------------------------
Public Function Wartosc(ByVal s As String, ByVal p As Integer) As Double
Dim Lc, Lu, w As Double
Dim c, i As UInteger
Dim znak As Integer, u As Boolean

s = s.ToUpper()
Lc = 0 : Lu = 0 : w = 1 : u = False : znak = 1
For i = 0 To s.Length() - 1
Select Case s.Chars(i)
Case "-" : znak = -1
Case "," : u = True
Case Else : c = Asc(s.Chars(i)) - 48
If c > 9 Then c -= 7
If u Then
Lu = p * Lu + c : w *= p
Else
Lc = p * Lc + c
End If
End Select
Next
Return znak * (Lc + Lu / w)
End Function

' Funkcja oblicza wartość potęgi
' Wejście:
' a - liczba podnoszona do potęgi
' n - wartość wykładnika potęgowego
' Wyjście:
' a^n
'------------------------------------
Public Function Potega(ByVal a As Integer, ByVal n As Integer) As Double
Dim p As Double

p = 1
While n > 0
p *= a : n -= 1
End While
While n < 0
p /= a : n += 1
End While
Return p
End Function

' Funkcja znajduje zapis stałoprzecinkowy podanej liczby
' Wejście:
' L - wartość liczby
' p - podstawa systemu liczbowego zapisu liczby
' Wyjście:
' zapis liczby w systemie o podstawie p
'-------------------------------------------------------
Public Function Przelicz(ByVal L As Double, ByVal p As Integer) As String
Dim sc, su As String
Dim c As UInteger
Dim Lc, Lu As Double
Dim znak As Boolean

znak = False : sc = "" : su = ""

' Algorytm obsługuje liczby nieujemne. Jeśli więc wartość liczby
' jest ujemna, to zapamiętujemy jej znak i zmieniamy ją na dodatnią

If L < 0 Then
L = -L : znak = True
End If

' Wyznaczamy część całkowitą Lc oraz część ułamkową Lu.
' Część ułamkowa zostaje zaokrąglona do około 10 cyfr po
' przecinku.

Lc = Int(L) : Lu = L - Lc

' Wyznaczamy zapis części całkowitej w sc

Do
c = Int(Lc - Int(Lc / p) * p)
If c < 10 Then
sc = Chr(c + 48) + sc
Else
sc = Chr(c + 55) + sc
End If
Lc = Int(Lc / p)
Loop Until Lc = 0

' Jeśli część ułamkowa jest niezerowa, to wyznaczamy jej
' zapis w su. Na końcu zapisu usuwamy zera nieznaczące

If Lu > 0 Then
Do
Lu *= p
c = Int(Lu)
Lu -= c
If c < 10 Then
su += Chr(c + 48)
Else
su += Chr(c + 55)
End If
Loop Until (Lu = 0) Or (su.Length() = 10)
su = su.TrimEnd("0")
su = "," + su
End If

' Jeśli konieczne, dodajemy znak liczby i całość łączymy
' w jeden zapis.

If znak Then sc = "-" + sc
Return sc + su
End Function

Sub Main()

Dim m As Double
Dim c, p1, p2 As Integer
Dim s1, s2 As String

Console.WriteLine("Przeliczanie liczb zmiennoprzecinkowych")
Console.WriteLine("---------------------------------------")
Console.WriteLine("(C)2005 mgr Jerzy Wałaszek I LO Tarnów")
Console.WriteLine()
Console.Write("Podstawa źródłowa = ") : p1 = Val(Console.ReadLine)
If (p1 >= 2) And (p2 <= 36) Then
Console.WriteLine()
Console.Write("Mantysa = ") : s1 = Console.ReadLine
If Test(s1, p1, False) Then
Console.Write("Cecha = ") : s2 = Console.ReadLine
If Test(s2, p1, True) Then
Console.WriteLine()
Console.Write("Podstawa docelowa = ") : p2 = Val(Console.ReadLine)
If (p2 >= 2) And (p2 <= 36) Then

' Obliczamy wartość liczby. Początkowo mantysa jest równa tej
' wartości, a cecha jest równa 0.

m = Wartosc(s1, p1) * Potega(p1, Int(Wartosc(s2, p1)))
c = 0

' Normalizujemy mantysę do przedziału <1,p>

If m <> 0 Then
While Math.Abs(m) >= p2
m /= p2 : c += 1
End While
While Math.Abs(m) < 1
m *= p2 : c -= 1
End While
End If
Console.WriteLine()
Console.WriteLine("{0}x10^{1}({2}) = {3}x10^{4}({5})", _
s1, s2, p1, Przelicz(m, p2), Przelicz(c, p2), p2)
Else
Console.WriteLine("Nieprawidłowa podstawa docelowa")
End If
Else
Console.WriteLine("Nieprawidłowa cecha")
End If
Else
Console.WriteLine("Nieprawidłowa mantysa")
End If
Else
Console.WriteLine("Nieprawidłowa podstawa źródłowa")
End If
Console.WriteLine()
Console.WriteLine("KONIEC. Naciśnij dowolny klawisz...")
Console.ReadLine()

End Sub

End Module
Python
# -*- coding: cp1250 -*-
# Program przeliczający liczby zmiennoprzecinkowe.
#-------------------------------------------------
# (C)2005 mgr Jerzy Wałaszek
# I Liceum Ogólnokształcące
# im. K. Brodzińskiego
# w Tarnowie
#-------------------------------------------------

import string

# Funkcja sprawdza poprawność zapisu liczby
# Wejście:
# s - zapis liczby w postaci stałoprzecinkowej
# p - podstawa systemu
# intg - true = liczba musi być całkowita
# Wyjście:
# true, jeśli zapis jest prawidłowy
#------------------------------------------------
def Test(s, p, intg):
pc = prz = False
s = string.upper(s)
for i in range(len(s)):
x = s[i]
if x == " ": continue
elif x == "-":
if pc or prz: return False
else: pc = True
elif x == ",":
if prz or intg: return False
else: prz = True
else:
c = ord(x) - 48
if c > 9: c -= 7
if c >= p: return False
return True

# Funkcja oblicza wartość liczby
# Wejście:
# s - łańcuch znakowy z zapisem liczby
# p - podstawa systemu liczbowego zapisu liczby
# Wyjście:
# wartość liczby zapisanej w s
#------------------------------------------------
def Wartosc(s, p):
Lc = Lu = 0.0; w = 1.0; u = False; znak = 1
s = string.upper(s)
for i in range(len(s)):
x = s[i]
if x == "-": znak = -1
elif x == ",": u = True
else:
c = ord(x) - 48
if c > 9: c -= 7
if u:
Lu = p * Lu + c
w *= p
else: Lc = p * Lc + c
return znak * (Lc + Lu / w)

# Funkcja oblicza wartość potęgi
# Wejście:
# a - liczba podnoszona do potęgi
# n - wartość wykładnika potęgowego
# Wyjście:
# a^n
#------------------------------------
def Potega(a, n):
p = 1.0
while n > 0:
p *= a; n -= 1
while n < 0:
p /= a; n += 1
return p

# Funkcja znajduje zapis stałoprzecinkowy podanej liczby
# Wejście:
# L - wartość liczby
# p - podstawa systemu liczbowego zapisu liczby
# Wyjście:
# zapis liczby w systemie o podstawie p
#-------------------------------------------------------
def Przelicz(L, p):
znak = False; sc = su = ""

# Algorytm obsługuje liczby nieujemne. Jeśli więc wartość liczby
# jest ujemna, to zapamiętujemy jej znak i zmieniamy ją na dodatnią

if L < 0:
L = -L; znak = True

# Wyznaczamy część całkowitą Lc oraz część ułamkową Lu.
# Część ułamkowa zostaje zaokrąglona do około 10 cyfr po
# przecinku.

Lc = float(int(L)); Lu = L - Lc

# Wyznaczamy zapis części całkowitej w sc

while Lc:
c = int(Lc - int(Lc / p) * p)
if c < 10: sc = chr(c + 48) + sc
else: sc = chr(c + 55) + sc
Lc = float(int(Lc / p))
if sc == "": sc = "0"

# Jeśli część ułamkowa jest niezerowa, to wyznaczamy jej
# zapis w su. Na końcu zapisu usuwamy zera nieznaczące

if Lu:
while Lu and (len(su) < 10):
Lu *= p
c = int(Lu)
Lu -= c
if c < 10: su += chr(c + 48)
else: su += chr(c + 55)
while (su != "") and (su[-1] == "0"): su = su[:-1]
su = "," + su

# Jeśli konieczne, dodajemy znak liczby i całość łączymy
# w jeden zapis.

if znak: sc = "-" + sc
return sc + su

#**********************
#*** PROGRAM GŁÓWNY ***
#**********************

print "Przeliczanie liczb zmiennoprzecinkowych"
print "---------------------------------------"
print "(C)2005 mgr Jerzy Walaszek I LO Tarnow"
print
p1 = int(raw_input("Podstawa zrodlowa = "))
if (p1 >= 2) and (p1 <= 36):
print
s1 = raw_input("Mantysa = ")
if Test(s1, p1, False):
s2 = raw_input("Cecha = ")
if Test(s2, p1, True):
print
p2 = int(raw_input("Podstawa docelowa = "))
if (p2 >= 2) and (p2 <= 36):

# Obliczamy wartość liczby. Początkowo mantysa jest równa tej
# wartości, a cecha jest równa 0.

m = Wartosc(s1, p1) * Potega(p1, int(Wartosc(s2, p1)))
c = 0

# Normalizujemy mantysę do przedziału <1,p>

if m:
while abs(m) >= p2:
m /= p2; c += 1
while abs(m) < 1:
m *= p2; c -= 1
print
print "%sx10^%s(%d) = %sx10^%s(%d)" % \
(s1, s2, p1, Przelicz(m, p2), Przelicz(c, p2), p2)
else: print "Nieprawidlowa podstawa docelowa"
else: print "Nieprawidlowa cecha"
else: print "Nieprawidlowa mantysa"
else: print "Nieprawidlowa podstawa zrodlowa"
print
raw_input("Nacisnij klawisz Enter...")
JavaScript
<html>
<head>
</head>
<body>
<div align="center">
<form style="BORDER-RIGHT: #ff9933 1px outset;
PADDING-RIGHT: 4px;
BORDER-TOP: #ff9933 1px outset;
PADDING-LEFT: 4px;
PADDING-BOTTOM: 1px;
BORDER-LEFT: #ff9933 1px outset;
PADDING-TOP: 1px;
BORDER-BOTTOM: #ff9933 1px outset;
BACKGROUND-COLOR: #ffcc66"
name="frmprzelicz">
<h3 id="data_out" style="text-align: center">
Przeliczanie liczb zmiennoprzecinkowych<br>
w różnych systemach pozycyjnych
</h3>
<p style="TEXT-ALIGN: center">
(C)2005 mgr Jerzy Wałaszek&nbsp;&nbsp; I LO w Tarnowie
</p>
<hr>
<div align="center">
<table border="0" cellpadding="4" bgcolor="#FF9933">
<tr>
<td align="right">podstawa źródłowa =&nbsp;</td>
<td>
<input type="text" name="p1" size="20" value="10"
style="text-align: right; background-color: #FFFFCC">
&nbsp;dziesiętnie
</td>
</tr>
<tr>
<td align="right">mantysa źródłowa =&nbsp;</td>
<td>
<input type="text" name="s1" size="20" value="3,33333333"
style="text-align: right">
&nbsp;źródłowo
</td>
</tr>
<tr>
<td align="right">cecha źródłowa =&nbsp;</td>
<td>
<input type="text" name="s2" size="20" value="-1"
style="text-align: right">
&nbsp;źródłowo
</td>
</tr>
<tr>
<td align="right">podstawa docelowa =&nbsp;</td>
<td>
<input type="text" name="p2" size="20" value="3"
style="text-align: right; background-color: #FFFFCC">
&nbsp;dziesiętnie
</td>
</tr>
</table>
<p style="text-align: center">
<input type="button" value="Przelicz" name="B1" onclick="main();">
</p>
<p style="TEXT-ALIGN: center" id="out_t">...</p>
</div>
</form>

<script language=javascript>

// Program przeliczający liczby zmiennoprzecinkowe.
//-------------------------------------------------
// (C)2005 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// im. K. Brodzińskiego
// w Tarnowie
//-------------------------------------------------

// Funkcja sprawdza poprawność zapisu liczby
// Wejście:
// s - zapis liczby w postaci stałoprzecinkowej
// p - podstawa systemu
// intg - true = liczba musi być całkowita
// Wyjście:
// true, jeśli zapis jest prawidłowy
//------------------------------------------------
function Test(s,p,intg)
{
var i,c,pc,prz;

s = s.toUpperCase();
pc = prz = false;
for(i = 0; i < s.length; i++)
switch(s.charAt(i))
{
case '-' : if(pc || prz) return(false); else pc = true;
case ' ' : break;
case ',' : if(prz || intg) return(false); else prz = true;
break;
default : c = s.charCodeAt(i) - 48;
if(c > 9) c -= 7;
if(c >= p) return(false);
break;
};
return(true);
}

// Funkcja oblicza wartość liczby
// Wejście:
// s - łańcuch znakowy z zapisem liczby
// p - podstawa systemu liczbowego zapisu liczby
// Wyjście:
// wartość liczby zapisanej w s
//------------------------------------------------
function Wartosc(s,p)
{
var c,i,Lc,Lu,w,znak,u;

Lc = Lu = 0; znak = w = 1; u = false; s = s.toUpperCase();
for(i = 0; i < s.length; i++)
switch(s.charAt(i))
{
case '-' : znak = -1;
case ' ' : break;
case ',' : u = true; break;
default : c = s.charCodeAt(i) - 48;
if(c > 9) c -= 7;
if(u)
{
Lu = p * Lu + c; w *= p;
}
else Lc = p * Lc + c;
break;
};
return(znak * (Lc + Lu / w));
}

// Funkcja oblicza wartość potęgi
// Wejście:
// a - liczba podnoszona do potęgi
// n - wartość wykładnika potęgowego
// Wyjście:
// a^n
//------------------------------------
function Potega(a,n)
{
var p;

p = 1;
while(n > 0)
{
p *= a; n--;
};
while(n < 0)
{
p /= a; n++;
};
return(p);
}

// Funkcja znajduje zapis stałoprzecinkowy podanej liczby
// Wejście:
// L - wartość liczby
// p - podstawa systemu liczbowego zapisu liczby
// Wyjście:
// zapis liczby w systemie o podstawie p
//-------------------------------------------------------
function Przelicz(L,p)
{
var sc,su,Lu,Lc,c,znak;

znak = false; sc = su = "";

// Algorytm obsługuje liczby nieujemne. Jeśli więc wartość liczby
// jest ujemna, to zapamiętujemy jej znak i zmieniamy ją na dodatnią

if(L < 0)
{
L = -L; znak = true;
};

// Wyznaczamy część całkowitą Lc oraz część ułamkową Lu.
// Część ułamkowa zostaje zaokrąglona do około 10 cyfr po
// przecinku.

Lc = Math.floor(L); Lu = L - Lc;

// Wyznaczamy zapis części całkowitej w sc

do
{
c = Math.floor(Lc - Math.floor(Lc / p) * p);
if(c < 10)
sc = String.fromCharCode(c + 48) + sc;
else
sc = String.fromCharCode(c + 55) + sc;
Lc = Math.floor(Lc / p);
} while(Lc);

// Jeśli część ułamkowa jest niezerowa, to wyznaczamy jej
// zapis w su. Na końcu zapisu usuwamy zera nieznaczące

if(Lu)
{
do
{
Lu = Lu * p;
c = Math.floor(Lu);
Lu = Lu - c;
if(c < 10)
su += String.fromCharCode(c + 48);
else
su += String.fromCharCode(c + 55);
} while(Lu && su.length < 10);
while((su != "") && (su.charAt(su.length - 1) == '0'))
su = su.substring(0,su.length-1);
su = "," + su;
};

// Jeśli konieczne, dodajemy znak liczby i całość łączymy
// w jeden zapis.

if(znak) sc = "-" + sc;
return(sc + su);
}

//**********************
//*** PROGRAM GŁÓWNY ***
//**********************

function main()
{
var m,c,p1,p2,s1,s2,t;

p1 = parseInt(document.frmprzelicz.p1.value);
if(!isNaN(p1) && (p1 > 1) && (p1 < 37))
{
s1 = document.frmprzelicz.s1.value;
if(Test(s1,p1,false))
{
s2 = document.frmprzelicz.s2.value;
if(Test(s2,p1,true))
{
p2 = parseInt(document.frmprzelicz.p2.value);
if(!isNaN(p2) && (p2 > 1) && (p2 < 37))
{

// Obliczamy wartość liczby. Początkowo mantysa jest równa tej
// wartości, a cecha jest równa 0.

m = Wartosc(s1,p1) * Potega(p1,Wartosc(s2,p1));
c = 0;

// Normalizujemy mantysę do przedziału <1/p,1)

if(m)
{
while(Math.abs(m) >= p2)
{
m /= p2; c++;
};
while(Math.abs(m) < 1)
{
m *= p2; c--;
};
};
t = s1 + " x 10<sup>" + s2 + "</sup><sub>(" +
p1 + ")</sub> = " +
Przelicz(m,p2) + " x 10<sup>" +
Przelicz(c,p2) + "</sup><sub>(" + p2 + ")</sub>";
}
else t = "<font color=Red><b>Nieprawidlowa podstawa docelowa</b></font>";
}
else t = "<font color=Red><b>Nieprawidłowa cecha</b></font>";
}
else t = "<font color=Red><b>Nieprawidłowa mantysa</b></font>";
}
else t = "<font color=Red><b>Nieprawidłowa podstawa źródłowa</b></font>";
document.getElementById("out_t").innerHTML = t;
return 0;
}

</script>

</div>
</body>
</html>

cedf960c265333b64ac9be26a7d91751.gif

W rozdziale przedstawiliśmy podstawową wiedzę związaną z pozycyjnymi systemami liczenia, którą musi sobie przyswoić każdy informatyk. Chociaż nie ograniczaliśmy się do konkretnych systemów liczbowych (celowo!), w praktyce będziemy spotykać tylko systemy dwójkowy, ósemkowy, dziesiętny oraz szesnastkowy. Pozostałe mają znaczenie marginalne.

Ważne jest, abyście zrozumieli, iż pewne prawidłowości zachodzą we wszystkich systemach pozycyjnych i poznanie ich znacznie ułatwia wszelkie przeliczenia. Dla człowieka najbardziej zrozumiałym systemem jest system dziesiętny, dla komputera z kolei jest on niewygodny i stosuje się tutaj system dwójkowy, którym zajmiemy się dokładniej w dalszych rozdziałach naszego opracowania. Jednakże będziemy się ciągle odwoływać do materiału zawartego w tym rozdziale.

 

 

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

 

Źródło: mgr Jerzy Wałaszek