Số thực âm có thể chuyển qua hệ nhị phân được không?

Mình chào các bạn, cho mình hỏi là số thực âm có thể chuyển qua hệ nhị phân được không ạ?

Tất nhiên là được bạn. Tại sao không nhỉ. :slight_smile:

Bạn đọc qua bài này để hiểu thêm về cách biểu diễn số thực trong ngôn ngữ máy.

4 Likes

Cách chuyển làm sao bạn?

Mình đã edit post r đó bạn. :wink:

3 Likes

Trong này nó chỉ bày mình chuyển từ nhị phân sang thập phân, còn ngược lại nó đâu có nói tới.

À, hiểu rồi, mà bạn ơi, mấy hệ cơ số khác mình cũng dựa theo nguyên lý này để chuyển ak bạn?

Đúng r, do máy tính có cái gọi là carry out nên có thể biểu diễn số âm qua số bù hai. :slight_smile:

4 Likes

Bạn ơi, hệ nhị phân mình viết số thực âm như -1001.0010 có được không bạn?

Nếu câu hỏi của em chỉ đơn giản về Toán thì được.
Không chỉ nhị phân, mà bất cứ cơ số b nào, với b lớn hơn 1. (b = 10, b = 2, b = 8, b = 16).

Còn nếu biểu diễn trên computer thì phải dùng biểu diễn bù 2 thay thế.

4 Likes

Yêu cầu của em là chuyển số n hệ thập phân ra hệ cơ số c, nếu dùng bù 2 vậy các hệ cơ số khác thì sao ạ?

em tách làm 2 phần: phần nguyên n và phần thập phân f

phần nguyên chuyển sang hệ cơ số c thì em tạo 1 cái stack, lặp tới khi n = 0: đẩy vào stack số dư trong phép chia n chia c (đẩy n%c vào stack), rồi gán n = phần nguyên của n/c. Khi in ra phần nguyên em pop stack rồi in ra là được

phần thập phân chuyển sang hệ cơ số c thì em in ra thẳng tới khi nào f = 0 hoặc tới ví dụ 10 số thập phân thì dừng: in ra phần nguyên của f * c, rồi gán f = phần thập phân của f * c

ví dụ: số Tau 6.283185 chuyển về hệ cơ số 3 là:
phần nguyên n = 6. Đẩy vào stack 6%3=0, gán n=phần nguyên của 6/3=2, đẩy tiếp vào stack 2%3=2, gán n=phần nguyên của 2/3=0, n=0, dừng. Pop stack ra lần lượt ta có: 20
phần thập phân f = 0.283185: in phần nguyên của f*3 = 0, gán f = phần thập phân của f*3 = 0.849555. In tiếp phần nguyên của f*3=2, gán f=0.548665. Tiếp tục như thế ta có phần thập phân là 02112210222101…
vậy ta có 6.283185 = 20.02112210222101…
số âm thì em thêm dấu - đằng trước là được :V :V chuyển sang cách viết của người thôi mà có phải cách viết của máy đâu mà bù 2 gì ở đây :V

cách chứng minh cũng đơn giản lắm :V
số x được viết dưới dạng hệ cơ số c sẽ có dạng là
x = … + a-mc-m + … + a-2c-2 + a-1c-1 + a0c0 + a1c1 + a2c2 + … + akck + …
trong đó 0 <= ai < c
ta tách n thành 2 phần:
phần nguyên n = a0c0 + a1c1 + a2c2 + … + akck + …
phần thập phân f = a-1c-1 + a-2c-2 + … + a-mc-m + …
với phần nguyên: vì c0 = 1 :face_with_raised_eyebrow: nên ta có thể viết lại là
n = a0 + a1c1 + a2c2 + … + akck + …
dễ dàng thấy rằng phần (a1c1 + a2c2 + … + akck + …) chia hết cho c, còn phần a0 vì 0 <= ai < c nên a0 chính là phần dư của phép chia n cho c.
Vậy ta lấy ra a0 bằng cách đẩy vào stack n%c (để lát nữa in ra ngược chiều). Sau đó ta gán n = (n - n%c) / c, hay n = a1c0 + a2c1 + … + akck-1 + …
tới đây ta lại lấy tiếp ra a1 tương tự như a0, và cứ thế tiếp tục tới khi n = 0 thì dừng vì có làm tiếp cũng chỉ in ra 0 mà thôi

phần thập phân thì vì f = a-1c-1 + a-2c-2 + … + a-mc-m + …, nếu ta lấy f*c sẽ ra a-1c0 + a-2c-1 + … + a-mc-m+1 + … lại trở thành giống như cái dạng trên: tách ra được a-1, nhưng thay vì lấy a-1 = n%c ta lấy a-1 = phần nguyên của f*c, vì những phần nhân với c-… đều < 1, vì ai < c nên ajc-j+1 < c-j+2, mà j ở đây >= 2 (bắt đầu từ a-2) nên nó < c0 hay < 1 hay phần thừa ra chính là phần thập phân.

5 Likes

Dạ, em cảm ơn anh nhiều :grinning:

em viết chương trình xong vô đây kiểm thử coi có giống ko :V https://jalu.ch/coding/base_converter.php

3 Likes

Tất cả mọi loại dữ liệu số đều chuyển ra được nhị phân. Sự thật là hệ 2, 10, 16 chỉ là cách viết khác dễ hiểu hơn cho con người của dữ liệu nhị phân.

3 Likes

Dạ, em cảm ơn tất cả mọi người ạ :smile:

#include<conio.h>
#include<math.h>
#include<string.h>

char *doinguyen(int nguyen,int c)
{
	char *n;
	int i=0;
	if(nguyen==0) n[0]='0';
	else
	{
		while(nguyen!=0)
		{
			n[i]=(nguyen%c)["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"];
			nguyen=nguyen/c;
			i++;
		}
	}
	return strrev(n);
}
char *doithapphan(float thapphan,int c)
{
	char *f;
	int i=0,nguyen;
	while(thapphan!=0&&i<=10)
	{
		nguyen=(int)(thapphan*c);
		f[i]=(nguyen)["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"];
		thapphan=thapphan-(int)thapphan;
		i++;
	}
	return f;
}
int xuat(float n)
{
	if((n-(int)n)==0&&n>=0) return 1;
	if((n-(int)n)==0&&n<0) return 2;
	if((n-(int)n)!=0&&n>0) return 3;
	if((n-(int)n)!=0&&n<0) return 4;
}
main()
{
	char tru[]="-",cham[]=".";
	int c,nguyen;
	float n,thapphan;
	printf("Nhap so n can chuyen doi:");
	scanf("%f",&n);
	printf("Nhap co so c=");
	scanf("%d",&c);
	while(c<2||c>62)
	{
		printf("Nhap lai sao cho 2<=c<=62.");
		printf("Nhap co so c=");
		scanf("%d",&c);
	}
	nguyen=abs((int)n);
	thapphan=fabs(n-int(n));
	switch(xuat(n))
	{
		case 1: printf("%6.2f chuyen qua he co so %d la: %s",n,c,doinguyen(nguyen,c));break;
		case 2: printf("%6.2f chuyen qua he co so %d la: %s",n,c,strcat(tru,doinguyen(nguyen,c)));break;
		case 3: printf("%6.2f chuyen qua he co so %d la: %s",n,c,strcat(strcat(doinguyen(nguyen,c),cham),doithapphan(thapphan,c)));break;
		case 4: printf("%6.2f chuyen qua he co so %d la: %s",n,c,strcat(strcat(strcat(tru,doinguyen(nguyen,c)),cham),doithapphan(thapphan,c)));break;
	}
	getch();
}

Đây là chương trình mình viết đổi số n ở hệ thập phân sang hệ cơ số c, mấy bạn giúp mình sửa lại cái phần xuất ra màn hình với, mình viết hơi bị lủng củng với lại khi nhập n=0 để đổi sang hệ cơ số c thì làm sao để trả lại về chuỗi cho hàm doinguyen(int nguyen,int c) ạ?

phải malloc cho char* nchar* f nữa chứ :V
trong main() xài xong doinguyen và doithapphan phải free chuỗi trả về nữa :V

3 Likes

Dạ, em chỉnh được rồi nhưng mà khi em nhập n=7.2019 chuyển qua cơ số 40 thì nó lại ra 7.831O0LZ trong khi đó kết quả phải ra là 7.831O mới đúng, cái này chỉnh sao vậy anh?

cái trong trang web kia in thiếu chứ sao :V Em bấm máy ra thử là biết
edit: cái trang web kia đúng :V :V cái này chắc do sai số của float, em chuyển kiểu số thực về double thử xem

Find & Replace --> float --> double :V

edit: nó vẫn in ra sai số :V Vậy em define thêm 1 hằng số TOLERANT ví dụ 1e-9, rồi so sánh thay vì thapphan != 0 thì so sánh thapphan > TOLERANT

#define TOLERANT 1e-9

...
while (thapphan > TOLERANT && ...)

nếu em muốn chính xác tuyệt đối thì đổi phần thập phân sang số nguyên 64-bit, lấy tối đa ví dụ 16 chữ số thôi, để khi nhân cmax = 62 thì số nguyên 64-bit chứa được kết quả, rồi cứ thế mà fang :V

edit: em có thể tạo 1 struct Fraction hay PhanSo có tử và mẫu rồi từ đó tính giá trị chính xác tuyệt đối được :V

struct PhanSo {
    long long tu;
    long long mau; //luôn luôn là 10^k
};

// 7.2019 --> tu = 2019, mau = 10000 (10^4)
// 7.0002019 --> tu = 2019, mau = 10^7
// đọc số nguyên phần nguyên trước
// bỏ qua 1 dấu chấm
// đọc phần thập phân vào dưới dạng chuỗi: fs = "2019" hay "0002019"
// chuyển chuỗi thành PhanSo: tu = atoll(fs), mau = 10 mũ strlen(fs)
// nhân PhanSo cho base c rất đơn giản: tu *= c
// lấy phần nguyên của PhanSo cũng rất đơn giản: tu / mau
// bỏ phần nguyên của PhanSo: tu %= mau

4 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?