Tính biểu thức: (n!+m!)/(m+n)!. Kết quả bị sai

#include<stdio.h>
#include<conio.h>
void nhap(int *n,int *m){
	do{
		printf("Nhap n: ");
		scanf("%d",n);
		printf("Nhap m: ");
		scanf("%d",m);
	}while(*n<1 && *m<1);
}
long gt1(int n){
	long t=1;
	int i;
	for(i=2; i<=n; i++){
		t*=i;
	}
	return t;
}
long gt2(int m){
	long t=1;
	int i;
	for(i=2; i<=m; i++){
		t*=i;
	}
	return t;
}

double bt(int n,int m){
	int i,gt=1;
	float t;
	for(i=2; i<=(m+n); i++){
		gt*=i;
	}
	t=(gt1(n)+gt2(m))/gt;
	return t;
}
int main(){
	int n,m;
	double s;
	nhap(&n,&m);
	s=bt(n,m);
	printf("=>%d!+%d!/(%d+%d)!=%lf",n,m,n,m,s);
	getch();
}

Mình hướng dẫn như thế này nhé, vì mình không rành C lắm.

x!=1*2*...*x

=> viết 1 function (giả sử là multi) có vòng for lặp từ 1 -> x. Tạo 1 biến để lưu giá trị nhân được, sau đó trả về giá trị biến đó.

trong hàm main, nhập được 2 giá trị m, n. Tạo 1 giá trị s = m+n

(m+n)!=s!

tạo 1 biến giá trị số thực t = (multi(n)+multi(m))/multi(s). In ra t.

Còn có một side case là m, n âm, thì trong func multi, ta sẽ có 1 vài lệnh if…else, nếu x != int, loại. Nếu x < 0. Lấy giá trị tuyệt đối của x (nhân trừ 1) rồi làm như trên.

6 Likes

@Trung_Hieu1: trước khi nói về kết quả đúng/sai, tôi có một vài góp ý cho bài tập của bạn như sau:

  1. Về cách đặt tên biến/hàm: bạn nên chọn cách đặt tên rõ ràng và đầy đủ, thay vì viết tắt. Ví dụ như bieuThuc thay vì bt (bt = bó tay?), giaiThua thay vì gt. Làm như vậy, khi ai khác (hoặc kể cả bạn sau một vài tháng nữa) sẽ biết rõ các biến/hàm của bạn được viết cho mục đích gì mà không cần phải giải thích nhiều. Và nếu cần, để thêm nhiều chú thích vào để làm rõ chỗ nào bạn thấy khó nhớ. Người lập trình giỏi là người khác có thể nhìn vào mã của họ và hiểu ngay mà không cần tài liệu kèm theo(self-explanatory).
  2. Tránh việc trùng lặp trong mã: cụ thể bạn có các hàm gt1, gt2 và một phần trong bt để làm công việc tính giai thừa (thông qua việc chạy vòng lặp for). Thay vì vậy, bạn chỉ cần định nghĩa một hàm giaiThua(int soCanTinhGiaiThua) duy nhất và mỗi khi cần tính giai thừa thì bạn gọi hàm đó. Ví dụ như giaiThua(m) để tính giai thừa của m, giaiThua(n) để tính giai thừa của n, và giaiThua(m+n) để tính giai thừa của m+n.
  3. Đọc kỹ đầu bài: biểu thức trong đầu bài của bạn là n! + m!/(m+n)!. Nếu theo thứ tự tính toán thì bạn phải tính m!/(m+n)! rồi mới cộng với n! (nhân chia trước, cộng trừ sau). Nhưng trong mã của bạn, bạn lại viết là (gt1(n)+gt2(m))/gt. Theo mã của bạn, thì điều này tương đương với (n! + m!)/(m+n)!. Bạn đã thấy khác nhau chưa?
  4. Điều kiện trong hàm nhap: vòng lặp nhập của bạn kết thúc với điều kiện một trong nm lớn hơn hoặc bằng 1 (phủ định của điều kiện *n < 1 && *m <1). Tuy nhiên, điều này chưa tính đến khả năng một trong hai số m hoặc n là số âm (ví dụ như n = -2 và m = 2, trong điều kiện này vòng lặp của bạn sẽ kết thúc nhưng giá trị của n không thể được dùng để tính giai thừa). Trong trường hợp này, m! hoặc n! không tồn tại khi m hoặc n là số nguyên, và vì vậy, cả biểu thức đều không tính được. Do vậy, điều kiện kết thúc vòng lặp của bạn nên là khi một trong hai số n hoặc m nhỏ hơn 0.

Bạn nên xem lại các vấn đề tôi vừa nhắc và tìm cách sửa lại biểu thức tính toán cho đúng. Nếu sau khi bạn đã thực hiện hết những điều này mà vẫn còn chạy sai thì chúng ta sẽ bàn tiếp.

Ngoài ra, bạn cũng nên có một phần mô tả chi tiết và rõ ràng vấn đề mà bạn gặp khó thay vì để tất cả vào tiêu đề của topic này. Tiêu đề chỉ mang tính tóm tắt vấn đề và nên ngắn gọn, mọi thứ còn lại nên được viết trong phần description. Đó cũng là quy tắc ứng xử cần thiết của một người muốn học hỏi.

@vtrnnhlinh: Chúng ta có thể gọi thẳng t= multi(n) + multi(m)/multi(m+n) chứ không cần phải đặt thêm biến s. Ngoài ra biểu thức của bạn cũng không đúng với đề bài như tôi đã nói trong phần 3 ở trên. Và cuối cùng, điều kiện x < 0 nên xét là điều kiện nhập chứ không thể dùng để tính x! (x! với x < 0 và x là số nguyên không tồn tại theo định nghĩa của giai thừa).

7 Likes

Cảm ơn anh đã chia sẻ và lần sau em sẽ rút kinh nghiệm ạ.
Nhưng khi em sửa lại vẫn không thấy đúng ạ. Chính xác đề là (n!+m!)/(m+n)! do em thiếu dấu ngoặc cho đề bài ở trên ạ.Em đã cố gắng tìm lỗi nhưng vẫn không tìm thấy.Anh có thể giúp em được không ạ ? Em chân thành cảm ơn ạ.

//Tinh bieu thuc: (n!+m!)/(m+n)!
#include<stdio.h>
#include<conio.h>
void nhap(int *n,int *m){
	do{
		printf("Nhap n: ");
		scanf("%d",n);
		printf("Nhap m: ");
		scanf("%d",m);
	}while(*n<0 || *m<0);
}
long giaiThua(int SoCanTinhGiaiThua){
	long t=1;
	int i;
	for(i=2; i<= SoCanTinhGiaiThua; i++){
		t*=i;
	}
	return t;
}
double BieuThuc(int n,int m){
	double t;
	t=(giaiThua(n)+giaiThua(m))/giaiThua(m+n);
	return t;
}
int main(){
	int n,m;
	double s;
	nhap(&n,&m);
	s=BieuThuc(n,m);
	printf("Gia tri cua bieu thuc bang %lf",s);
	getch();
}
1 Like

Bạn không nói sai cái gì, nhưng nếu về kết quả thì bạn có thể sai ở một chỗ sau:

...
double t;
t=(giaiThua(n)+giaiThua(m))/giaiThua(m+n);

Ở đây các biểu thức giai thừa của bạn đều là kiểu nguyên long nên chia nhau sẽ ra kiểu nguyên (long), do đó sẽ làm mất phần thập phân trong kết quả (ra kết quả ko mong muốn).

Vì thế, biên pháp ở đây là bạn thêm: (giaiThua(n)+giaiThua(m))/double(giaiThua(m+n)) là sẽ ra kiểu thực cho bạn.

4 Likes

@Trung_Hieu1: bạn @Giu_Mata đã trả lời cho bạn rồi đấy. Đây là vấn đề do các kiểu biến khác nhau. Vế phải của biểu thức t=(giaiThua(n)+giaiThua(m))/giaiThua(m+n); hoàn toàn chỉ có các biến số nguyên nên sẽ trả về kết quả kiểu nguyên. Khi chương trình thực hiện, vế phải sẽ có kết quả là 0 (hoàn toàn là 0 kiểu int và lúc nào cũng là 0 - đơn giản là vì m! + n! < (m+n)!), nhưng bởi vì bạn gán kết quả này cho t là biến kiểu double, nên 0 sẽ được chuyển thành 0.000000 và dẫn đến kết quả sai.

Phương pháp giải quyết là thông báo cho C compiler kết quả ở vế phải trả về kiểu double thay vì kiểu int trước khi gán cho biến t. Để làm điều này, bạn phải thực hiện typecast (hay ép kiểu) theo như gợi ý của bạn Giu Mata, hoặc như sau cũng được: t=(double)(giaiThua(n)+giaiThua(m))/giaiThua(m+n);

3 Likes

Cam on ban rat nhieu !!!

Cam on anh rat nhieu a.E hieu va lam duoc roi a.

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