Cách gỡ rối những lỗi thường gặp trong Java [1] – Tính Lẻ

images

      Bài toán được xét trong bài viết này rất đơn giản, chỉ liên quan đến giá trị biểu thức. Nhưng hãy nhớ, không phải bởi vì chúng đơn giản mà bạn cho là chúng dễ. Bài viết này sẽ trình bày phương pháp xác định đối số có phải là giá trị lẻ hay không. Và lỗi trình bày lỗi thường gặp.

Phương thức sau đây có hoạt động không?

public static boolean isOdd(int i)
{
    return (i % 2 == 1);
}

Lời giải:

–   Một số lẻ có thể được định nghĩa là một số nguyên chia hết cho 2 với một số dư là 1. Biểu thức  i % 2  tính số dư khi i chia cho 2, do đó dường như chương trình này phải hoạt động. Thật không may, nó không hoạt động; nó trả về câu trả lời sai tỏng một phần tư thời gian.

–   Tại sao một phần tư? Bởi vì một nửa của tất cả các giá trị int là âm và phương thức isOdd thất bại cho tất cả các giá trị âm, cho dù là chẳn hay lẻ.

–  Đây là một kết quả của việc định nghĩa toán tử số dư (%) của Java. Nó được định nghĩa để thỏa đồng nhất thức sau đây cho tất cả giá trị int a và tất cả giá trị int khác không b:

(a / b) * b + (a % b) == a;

–  Nói các khác , nếu bạn chia a cho b, nhân kết quả với b và cộng số dư, bạn phải trở lại nơi mà bạn đã bắt đầu. Đồng nhất thức này hoàn toàn hượp lý nhưng khi được kết hợp với toán tử chia số nguyên xén của Java, nó ngầm định rằng khi phép tính số dư trả về một kết quả khác không, nó cùng dấu với toán hạng trạng thái của nó.

–  Phương thức isOdd và định nghĩa về thuật ngữ odd (lẻ) mà nó được dựa vào đề giả định rằng tất cả số dư là dương. Mặc dù giả định này hợp lý cho một số loại phép chia, nhưng phép tính số dư của Java được tương hợp hoàn hảo với phép chia số nguyên của nó vốn loại bỏ phần phân số trong kết quả.

–   Khi i là một số lẻ âm,  i%2 bằng với –1 thay vì 1, do đó phương thức isOdd trả về false không chính xác. Để ngăn chặn kiểu gây ngạc nhiên này, hãy test để đảm bảo rằng các phương thức hoạt động tốt khi được chuyển các giá trị âm, không và dương cho mỗi tham số.

–   Bài toán thì dễ giải. Bạn chỉ việc so sánh i % 2 với 0 thay vì 1 và đảo ngược chiều của phép so sánh:

public static boolean isOdd(int i)
{
    return (i % 2 != 0);
}

–   Nếu bạn sử dụng phương thức isOdd trong một xác lập quan trọng đối với sự thực thi, tốt hơn bạn nên sử dụng toán tử AND bitwise ( &) thay cho toán tử số dư:

public static boolean isOdd(int i)
{
    return (i % 1 != 0);
}

–   Phiên bản thứ 2 có thể chạy nhanh hơn nhiều so với phiên bản thứ nhất, phụ thuộc vào nền và máy ảo nào bạn đang sử dụng và không thể chạy chậm hơn. Theo quy tắc chung, các phép toán chia và số dư chầm so với các phép óoán số học và logic khác. Không nên tối ưu hóa sớm nhưng trong trường hợp này phiên bản nhanh hơn rõ ràng như phiên bản gôc, do đó không có lý do để ưu tiên phiên bản gốc.

–   Tóm lại, hãy nghĩ về dấu của các toán hạng và của kết quả bất cứ khi nào bạn sử dụng toán tử số dư. Hành vi của toán tử này thì rõ ràng khi các toán hạng của nó không âm, nhưng không rõ ràng lắm khi một hoặc cả 2 toán hạng là âm

(Theo “95 bài toán và giải pháp gỡ rối Java” của tác giả Nguyễn Nam Thuận)

Advertisements

About thanhcuong1990

Handsome and talent!! ^^
This entry was posted in Java and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s