Làm thế nào để tăng giá trị của biến kiểu float lên trên 16777216 trong vòng lặp?

Chào các anh chị, hiện tại thì thầy đang giao cho em làm bài tập in ra tất cả các giá trị kiểu nguyên ko thể dc biểu diễn chính xác bằng kiểu float (vì float có sai số, mấy số nhỏ sai số nhỏ ko cần in, chỉ in mấy số có sai số lớn, ví dụ như em nhập vào float x = 33554433 thì printf lại in ra 33554432, in số đó ra)

em cho biến float và biến double cùng chạy, nếu khác nhau thì in số đó ra (vì double chính xác hơn float)
em cũng có sài một đoạn code test thử giả thuyết đó

#include <stdio.h>
#include <conio.h>

int main()
{
	float  x = 1;
	double y = 1;
	if (x!=y)
		printf("khac nhau %.0f\n", x);
	else
		printf("giong nhau %.0f\n", x);

	x = 33554433;
	y = 33554433;
	if (x != y)
		printf("khac nhau %.0f\n", x);
	else
		printf("giong nhau %.0f\n", x);
	_getch();
}

còn code bài làm của em hiện tại nó như thế này

#include <stdio.h>
#include <conio.h>

int main()
{
	float  x = 1;
	double y = 1;
	while (1)
	{
	if (x != y)
		printf(" %.0f\n%.0f\n", x,-x);
		x++;
		y++;
	}
	_getch();
}

vấn đề em đang gặp phải là biến float của em chỉ chạy được tới số 16777216 là ngưng, ko tăng tiếp dc nữa trong khi biến double vẫn tăng bình thường
em test thử trên một đoạn code khác thì nó cũng tương tự, biến float ko tăng được tới 16777217

#include <stdio.h>
#include <conio.h>

int main()
{
	float  x = 16777216;
		printf("%.0f", x+1);
	_getch();
}

kết quả in ra vẫn là 16777216

mấy anh chị giúp em với tại bài này là để nhóm em làm đồ án cho thầy thi giữa kỳ quan trọng lắm

Chắc lại lấy int gán vào rồi đổi ngược ra ấy mà.

2 Likes

Vì nó đã đạt giới hạn mantissa của float rồi :smiley:

Theo chuẩn IEEE 754
Một số thực biển diễn ở dạng nhị phân 32bit có
1 bit dấu
8 bit expornent
23 bit mantissa

Để hiểu được bạn phải hiểu được Scientific Notation
Vd
10 thì Scientific Notation của nó là 1 * 101
2300 = 2.3 * 103
0.1 = 1 * 10-1
0.0345 = 3.45 * 10-2

Thì ở tren là hệ 10. Ở hệ 2 thì sao
Thì cũng tương tự ta có
4 = 1 * 22
5 = 1.25 * 22
0.25 = 1 * 2-2
0.625 = 5/8 = 1.25 * 25* 2-3 = 1.25 * 2-1

Vậy 16777216 ở dạng hệ 2 biểu diễn ntn?
Thì ta có 16777216 = 1 * 224

Tại sao lại ra được mấy cái 2xyz trên?
Thì đó là công thức của IEEE 754 đã định nghĩa (mình lười đọc nên lấy công thức nhớ thôi =)) )
Bạn đọc ở đây: https://en.wikipedia.org/wiki/Single-precision_floating-point_format

Tới đây coi như bạn hiểu công thức nhé :smiley:

Thì tới vấn đề của bạn. Tại sao lại tăng lên 16777217 không được.

Ta biết 16777217 = 16777216 + 1 = 224 + 1 = 224 + 224 *2-24 = 224(1 + 2-24)
Áp dụng công thức ở link wiki thì ta thấy
2-24 là phần mantissa.
Tuy nhiên mantissa chỉ có 23 bit thôi. Thì làm sao mà tính đến -24 được. Vậy là phần matissa bị tràn -> nó lại thành 0 -> Lúc này ráp công thức là ta lại có 224(1 + 0) = 224

Vậy còn 16777218?
Phân tích như trên 16777216 + 2 = 224 + 224*2-23 = 224(1 + 2-23)

Mantissa có 23 bit vậy là có thể tính toán được :smiley:
-> 16777218 Sẽ không bị tràn và lưu trữ đúng.

P/s: Chắc là sẽ hơi khó hiểu chút :sweat_smile:
Float to Binary: https://www.h-schmidt.net/FloatConverter/IEEE754.html

Còn về cách tìm các số bị lỗi này thì anh rogp10 gợi ý rồi nhé.
Và hint là từ 16777216 trở đi mới bị lỗi

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