Trong các ngôn ngữ lập trình, muốn thực hiện thao tác tính toán thì luôn cần phải có toán tử. Trong bài viết này tôi sẽ chia sẻ về kinh nghiệm mà mình có được khi sử dụng toán tử, về những lỗi trả về kết quả không như ý muốn, và đây là một vấn đề quan trọng nhưng lại ít được để ý tới.
C/C++ Nguyễn Đăng Khánh 2016-03-03 07:51:51

Giới thiệu

Trong các ngôn ngữ lập trình, muốn thực hiện thao tác tính toán thì luôn cần phải có toán tử. Trong bài viết này tôi sẽ chia sẻ về kinh nghiệm mà mình có được khi sử dụng toán tử, về những lỗi trả về kết quả không như ý muốn, và đây là một vấn đề quan trọng nhưng lại ít được để ý tới.

Toán tử "/"

Những điều lưu ý khi sử dụng toán tử "/"

Trong quá trình biên dịch, nếu phát hiện một lệnh gán giá trị khác loại cho một biến, trình biên dịch sẽ tự động chuyển kiểu, gọi là cơ chế chuyển kiểu ngầm định, tránh nhầm lẫn giữa phép chia các số nguyên trong toán học và phép chia các số nguyên trong lập trình, dẫn đến kết quả lập trình không được như mong muốn.

double d = 13;	// tự động chuyển giá trị của d thành 13.0
int n = 16.95;	// tự động chuyển giá trị của n thành 16

Khi cả 2 toán tử thuộc dạng nguyên (int - short - long) thì nó là phép chia lấy phần nguyên, ví dụ 8/7 được 1, 14/6 được 2.

//số nguyên
int a = 8; 
short b = 7;
printf("%d", a / b); // kết quả = 1

long c = 14;
long d = 6;
printf("%d", c / d); // kết quả = 2

Khi 1 trong 2 toán tử thuộc dạng số thực (float - double) thì nó sẽ là phép chia thập phân bình thường.

float a = 5;
float b = 4;
printf("%f", a / b);

Những sai lầm khi sử dụng toán tử "/"

Khi sử dụng toán tử "/", nguyên nhân kết quả không như mong muốn đó là do chưa áp dụng được những lưu ý trước khi sử dụng toán tử.

Ta xét ví dụ sau cho ra kết quả sai:

//vd1:
float a = 3/4;	
printf("%f", a); //a = 0

//vd2:
int b = 2;
a = 1 / b; 
printf("%f", a); // a = 0

Như vậy ở 2 lần int ra kết quả a = 0, đều là kết quả không như mong muốn.

  • Ví dụ 1: trong tư duy toán học, khi nhìn thấy a = 3/4 chúng ta đều tự nghĩ a = 0.75 và mặc định trong đầu float a = 0.75, nhưng đối với trình biên dịch, khi hai số nguyên chia nhau thì kết quả lấy phần nguyên do đó float a = (int)3/(int)4 và ra kết quả float a = 0.
  • Ví dụ 2: tương tự như ở trên, trình biên dịch sẽ hiểu theo nghĩa a = (int) 1 / (int) b và ra kết quả float a = 0.

Giải pháp chuyển kiểu

Là việc chuyển một dữ liệu sang kiểu dữ liệu khác theo ý muốn, cú pháp chuyển kiểu như sau:

(<kiểu dữ liệu>)<dữ liệu cần chuyển>

Sửa code trên để ra kết quả đúng:

float a = ((float)3) / 4;
printf("%f", a);

int b = 2;
a = 1 / (float)b;
printf("%f", a);

Lưu ý: ở đoạn code trên, tôi chuyển kiểu ((float)3) nhưng 4 thì không cần phải chuyển, vì các hạng tử không cùng kiểu, sẽ xảy ra chuyển kiểu ngầm định, kiểu nhỏ hơn sẽ chuyển sang kiểu lớn hơn, do đó 4 sẽ tự động chuyển thành ((float)4), ta có dãy cấp độ như sau:

  • long double // (highest).
  • double.
  • float.
  • unsigned long int.
  • long int.
  • unsigned int.
  • int // (lowest).

Toán tử "==" trong C++

Ta xét ví dụ sau:

//vd1
float a = 2.512;
if (a == 2.512)	
	printf("true");	
else	
	printf("false");
	
//vd2
int a = 2, b = 2, c = 2;
if (a == b == c)	
	printf("true");	
else	
	printf("false");

//vd3
int a = 5;
int b = 4;
if (a = b)
	printf("true");
else
	printf("false");
  • Ví dụ 1: kết quả trả về "false", việc so sánh số có kiểu dữ liệu là float với 1 hằng số, và kiểu dữ liệu của hằng số này là double, do đó dẫn đến sai số. Do đó để tránh ra kết quả sai, ta sửa lại đoạn code thành: if(a == 2.512f).
  • Ví dụ 2: kết quả trả về "false", ta hiểu như sau. Đầu tiên so sánh từ trái qua phải, do đó a == b => "true", tiếp theo true == c ==> false vậy kết quả là false. Sửa lại đoạn code if( a == b && b == c) hoặc if( a == b && a == c).
  • Ví dụ 3: kết quả trả về "true", đây là lỗi thường gặp do gõ code, giữa "=" (phép gán) và "==" (phép so sánh) là 2 thế giới khác nhau, tuy nhiên chúng ta vẫn thường lầm tưởng về điều đó.

Toán tử "==" trong PHP

Tránh những lỗi khi sử dụng toán tử trong php vì các kiểu dữ liệu trong php tự động chuyển các biến sang các kiểu thích hợp để thực hiện phép tính. Như ví dụ đoạn code dưới đây, cho ra kết quả "true" vì php đã chuyển cùng kiểu dữ liệu rồi so sánh.

$a = 5;
$b ='5';
if($a == $b)
{
	echo "true";
}
else
{
	echo "false";
}

Sau đây là bảng trả về những kết quả đúng nhưng thường dễ bị hiểu lầm.

Ví dụ Kết quả Nguyên nhân
NULL == '' true NULL được chuyển về chuỗi rỗng
NULL == FALSE true NULL được chuyển về FALSE
NULL == 0 true NULL sẽ bằng với bất kỳ giá trị nào tương ứng với FALSE như 0, "0", 0.00
FALSE = '0' true Chuỗi rỗng và 0 sẽ bị ép kiểu về FALSE.
TRUE =  'false' true Bất kỳ chuỗi nào khác rỗng đều bị ép kiểu về TRUE.
3.5 == '3.5 km' true Chuỗi sẽ được chuyển về số và so sánh
0 == '' true Chuỗi rỗng bị ép về 0.
0 == 'STDIO' true Chuỗi không chứa số bị ép về 0.

Toán tử "==="

Đoạn code dưới đây, khi in kết quả true = 1 và chữ yes

// VÍ DỤ 1
<?php	

echo true; // kết quả = 1	

if(true == 1)	
	echo "yes";	
else
	echo "no";	
	
?>

Tuy nhiên trong php còn có toán tử "===", khi in kết quả sẽ ra chữ "no" tại đoạn code thứ 2

// VÍ DỤ 2
<?php
	
if(true === 1)
	echo "yes";
else
	echo "no";
?>

Như vậy sự khác biệt giữa "==" (so sánh) và "===" (so sánh đồng nhất), toán tử đồng nhất hoàn toàn không sử dụng ép kiểu, do đó nếu hai giá trị khác kiểu được so sánh ("true" kiểu boolean và "1" kiểu integer) thì kết quả luôn trả về chữ "no" như ví dụ 2.