Trang 1 trên tổng số 3 123 Cuối cùngCuối cùng
Từ 1 tới 10 trên tổng số 28 kết quả

Đề tài: Liệu có phải compiler bị lỗi về so sánh ???

  1. #1
    Ngày gia nhập
    05 2017
    Bài viết
    5

    Cool Liệu có phải compiler bị lỗi về so sánh ???

    Mình viết đoạn code sau trên CodeBlock( đã thử cả trên Dev C++)
    #include<iostream>
    using namespace std;
    int main(){
    float a;
    cin>>a;
    if(a<3.6) cout<< "NHO HON ";
    else cout<< "LON HON BANG ";
    return 0;
    }
    CHO NÓ RUN -> NHẬP 3.6 ->>> màn hình hiển thị: NHO HON ----> cái gì đang diễn ra vậy ????
    <nếu thay 3.6 ở đoạn code trên thành 3.7 và cho chạy, nhập 3.7 thì lại ra LON HON BANG >
    Thực sự thì là ntn vầy @@@ Con số 3.6 thần thánh quá à

  2. #2
    Ngày gia nhập
    01 2013
    Bài viết
    1,476

    Vì 3.6 != 3.6f. Bạn hãy xem ở đây:
    https://ideone.com/9iIOxW

  3. #3
    Ngày gia nhập
    01 2008
    Nơi ở
    Rất nhiều sóng gió
    Bài viết
    391

    Trong máy tính, số được biểu diễn dưới dạng nhị phân. Đối với số thực dấu chấm động (float, double) chỉ có các số là lũy thừa của 2, chẳng hạn 0.125, 0.25, 0.5, 1.0, 2.0, 4.0 mới được biểu diễn hoàn toàn chính xác mà thôi. Số 3.6 không phải là lũy thừa của 2 nên chỉ có thể biểu diễn gần đúng. Số 3.6 trong mã nguồn của bạn chỉ gần bằng 3.6 (nhưng khác 3.6) và số 3.6 mà bạn nhập vào khi chạy chương trình cũng thế. Hai số này xấp xỉ bằng 3.6 nhưng khác nhau bởi vì chúng có kiểu khác nhau.
    Đã được chỉnh sửa lần cuối bởi Ada : 14-09-2017 lúc 10:04 AM. Lý do: Chính xác hóa
    -...- -.- .. .-.. .-.. - .... . -... . .- ... - .-.-.

  4. #4
    Ngày gia nhập
    05 2017
    Bài viết
    5

    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    Trong máy tính, số được biểu diễn dưới dạng nhị phân. Đối với số thực dấu chấm động (float, double) chỉ có các số là lũy thừa của 2, chẳng hạn 0.125, 0.25, 0.5, 1.0, 2.0, 4.0 mới được biểu diễn hoàn toàn chính xác mà thôi. Số 3.6 không phải là lũy thừa của 2 nên chỉ có thể biểu diễn gần đúng. Số 3.6 trong mã nguồn của bạn chỉ gần bằng 3.6 (nhưng khác 3.6) và số 3.6 mà bạn nhập vào khi chạy chương trình cũng thế. Hai số này xấp xỉ bằng 3.6 nhưng khác nhau bởi vì chúng có kiểu khác nhau.
    Vậy tại sao khi mình khai báo trong code của mình, sửa float a; thành double a -> thì compiler lại chạy đúng như bình thường thế nhỉ????

    - - - Nội dung đã được cập nhật ngày 14-09-2017 lúc 11:39 AM - - -

    Trích dẫn Nguyên bản được gửi bởi prog10 Xem bài viết
    Vì 3.6 != 3.6f. Bạn hãy xem ở đây:
    https://ideone.com/9iIOxW
    Sao lại không bằng vậy ạ ?? Liệu có phải như bạn @Ada giải thích ??

    - - - Nội dung đã được cập nhật ngày 14-09-2017 lúc 11:52 AM - - -

    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    Trong máy tính, số được biểu diễn dưới dạng nhị phân. Đối với số thực dấu chấm động (float, double) chỉ có các số là lũy thừa của 2, chẳng hạn 0.125, 0.25, 0.5, 1.0, 2.0, 4.0 mới được biểu diễn hoàn toàn chính xác mà thôi. Số 3.6 không phải là lũy thừa của 2 nên chỉ có thể biểu diễn gần đúng. Số 3.6 trong mã nguồn của bạn chỉ gần bằng 3.6 (nhưng khác 3.6) và số 3.6 mà bạn nhập vào khi chạy chương trình cũng thế. Hai số này xấp xỉ bằng 3.6 nhưng khác nhau bởi vì chúng có kiểu khác nhau.
    à mà thay 3.6 bởi 3.7 (vẫn khai báo kiểu float) compiler vẫn cho kq đúng nhé !!! Mà hẳn là 3.7 cũng ko phải lũy thừa nguyên của 2.

  5. #5
    Ngày gia nhập
    01 2008
    Nơi ở
    Rất nhiều sóng gió
    Bài viết
    391

    Trích dẫn Nguyên bản được gửi bởi Hangdtth Xem bài viết
    Vậy tại sao khi mình khai báo trong code của mình, sửa float a; thành double a -> thì compiler lại chạy đúng như bình thường thế nhỉ????

    - - - Nội dung đã được cập nhật ngày 14-09-2017 lúc 11:39 AM - - -



    Sao lại không bằng vậy ạ ?? Liệu có phải như bạn @Ada giải thích ??
    Khai báo lại biến a thành kiểu double thì chương trình chạy đúng, chứng tỏ số 3.6 trong mã nguồn của bạn được biểu diễn như một double.

    Và giải thích của mình cơ bản là giống như của bạn prog10: 3.6f là float, 3.6 là double.

    EDIT: dẫn chứng: http://en.cppreference.com/w/cpp/language/floating_literal
    -...- -.- .. .-.. .-.. - .... . -... . .- ... - .-.-.

  6. #6
    Ngày gia nhập
    05 2017
    Bài viết
    5

    Mặc định Liệu có phải compiler bị lỗi về so sánh ???

    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    Khai báo lại biến a thành kiểu double thì chương trình chạy đúng, chứng tỏ số 3.6 trong mã nguồn của bạn được biểu diễn như một double.

    Và giải thích của mình cơ bản là giống như của bạn prog10: 3.6f là float, 3.6 là double.

    EDIT: dẫn chứng: http://en.cppreference.com/w/cpp/language/floating_literal
    Vậy sao khai báo float a; thì khi nhập 3.7 compiler vẫn cho kq đúng ??

    - - - Nội dung đã được cập nhật ngày 14-09-2017 lúc 12:02 PM - - -

    Vậy khi nào mình biết số mình nhập là trùng với compiler "hiểu" ??? Có cách gì để tối ưu việc này ?
    Đã được chỉnh sửa lần cuối bởi Hangdtth : 14-09-2017 lúc 12:06 PM. Lý do: viết nhầm

  7. #7
    Ngày gia nhập
    01 2013
    Bài viết
    1,476

    Trích dẫn Nguyên bản được gửi bởi Hangdtth Xem bài viết
    Vậy sao khai báo float a; thì khi nhập 3.7 compiler vẫn cho kq đúng ??
    Vì sai-số-tuyệt-đối nhỏ hơn 0.1 nhiều.
    Trích dẫn Nguyên bản được gửi bởi Hangdtth Xem bài viết
    Vậy khi nào mình biết số mình nhập là trùng với compiler "hiểu" ??? Có cách gì để tối ưu việc này ?
    Đây là lúc để nói về "Kiểu của một con số (floating/integer literal)" trong C.

    Con số mặc định có kiểu (signed) int (nguyên) hoặc double (thực). Nhưng sẽ có trường hợp chúng không đáp ứng được nhu cầu của ta.
    - Không dấu (unsigned).
    - Long long (lớn hơn int).
    - Số float.
    - Số long double.

    Vậy phải thêm chữ ở cuối con số để báo kiểu.
    Đã được chỉnh sửa lần cuối bởi prog10 : 14-09-2017 lúc 01:42 PM.

  8. #8
    Ngày gia nhập
    01 2008
    Nơi ở
    Rất nhiều sóng gió
    Bài viết
    391

    Trích dẫn Nguyên bản được gửi bởi Hangdtth Xem bài viết
    Vậy sao khai báo float a; thì khi nhập 3.7 compiler vẫn cho kq đúng ??

    - - - Nội dung đã được cập nhật ngày 14-09-2017 lúc 12:02 PM - - -

    Vậy khi nào mình biết số mình nhập là trùng với compiler "hiểu" ??? Có cách gì để tối ưu việc này ?
    "Compiler cho kết quả đúng" ý bạn là khi chạy và nhập số 3.7, chương trình trả lời LON HON BANG?

    Như vậy thì có gì lạ đâu. Trước đây, 3.6f < 3.6 (double). Còn bây giờ, 3.7f >= 3.7 (double). Tùy theo trị số, cả ba khả năng nhỏ hơn, lớn hơn và bằng nhau đều có thể xảy ra. Bạn có thể thu được 3.8f == 3.8 (double) (chú ý, ví dụ này hoàn toàn chỉ là giả định) nhưng cho dù như thế thì cả hai vế này vẫn khác 3.8 (tuyệt đối) khi 3.8 (tuyệt đối) không phải là một lũy thừa của 2, và như thế nghĩa là ngay cả trong trường hợp thứ ba này thì cách "hiểu" của compiler có thể vẫn khác với điều bạn muốn.

    Cách giải quyết "tối ưu", để lập trình tính toán với các số thực một cách tin cậy, là bạn phải hiểu như compiler hiểu, như mình đã nói:

    -- Trị số của trực kiện số dấu chấm động (floating-point literal) chỉ chính xác khi là lũy thừa của 2.

    -- Khi bạn muốn biểu diễn điều kiện a == n, hãy cân nhắc viết là n - e/2 < a && a < n + e/2, trong đó e là một sai số nào đó mà bạn chấp nhận được, ví dụ, 1E-6.

    EDIT: Nói thật đúng, các số dấu chấm động là bội nguyên của 2**n (** là lũy thừa) nhưng bản thân n lại được chọn tùy theo độ lớn của số được biểu diễn, nên nói chung khó biết khi nào thì một số được biểu diễn hoàn toàn chính xác. Ví dụ, mình nghĩ rằng 0.75 là chính xác, dù không phải là một lũy thừa của 2.
    Đã được chỉnh sửa lần cuối bởi Ada : 14-09-2017 lúc 04:41 PM. Lý do: Chính xác hóa thuật ngữ
    -...- -.- .. .-.. .-.. - .... . -... . .- ... - .-.-.

  9. #9
    Ngày gia nhập
    01 2013
    Bài viết
    1,476

    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    -- Khi bạn muốn biểu diễn điều kiện a == n, hãy cân nhắc viết là n - e/2 < a && a < n + e/2, trong đó e là một sai số nào đó mà bạn chấp nhận được, ví dụ, 1E-6.
    Chỗ này phải tìm hiểu kĩ, nếu không chỉ là bắt chước thôi. Quan trọng nhất là sai số ở đâu ra & epsilon phải lấy bao nhiêu để không bị false positive thì không ai nhắc đến.

    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    EDIT: Nói thật đúng, các số dấu chấm động là bội nguyên của 2**n (** là lũy thừa) nhưng bản thân n lại được chọn tùy theo độ lớn của số được biểu diễn, nên nói chung khó biết khi nào thì một số được biểu diễn hoàn toàn chính xác. Ví dụ, mình nghĩ rằng 0.75 là chính xác, dù không phải là một lũy thừa của 2.
    Điều kiện đúng là: mẫu số phải là lũy thừa của 2 0.75 = 3/4 rồi.

    Để biết sơ sơ thì ít nhất là 1 tiết học về IEEE-754 https://sites.ualberta.ca/~kbeach/phys420_580/docs/ACM-Goldberg.pdf
    Đã được chỉnh sửa lần cuối bởi prog10 : 14-09-2017 lúc 05:37 PM.

  10. #10
    Ngày gia nhập
    05 2017
    Bài viết
    5

    Thực sự thì mình vẫn chẳng hiểu gì sất, thôi kệ mình đi, tuần sau đi học gặp thầy hỏi đến tận chân răng :V
    Cám ơn các bạn nhiều nhé )

    - - - Nội dung đã được cập nhật ngày 14-09-2017 lúc 05:57 PM - - -

    À mà hôm qua đi học giờ thực hành hỏi cô giáo ( thấy ghi hẳn là hàm tiến sĩ) mà mình hỏi tại sao lại như vậy, cô cũng chẳng biết, cô bảo để về cô xem lại cho

    - - - Nội dung đã được cập nhật ngày 14-09-2017 lúc 07:18 PM - - -

    Trích dẫn Nguyên bản được gửi bởi prog10 Xem bài viết
    Vì sai-số-tuyệt-đối nhỏ hơn 0.1 nhiều.

    Đây là lúc để nói về "Kiểu của một con số (floating/integer literal)" trong C.

    Con số mặc định có kiểu (signed) int (nguyên) hoặc double (thực). Nhưng sẽ có trường hợp chúng không đáp ứng được nhu cầu của ta.
    - Không dấu (unsigned).
    - Long long (lớn hơn int).
    - Số float.
    - Số long double.

    Vậy phải thêm chữ ở cuối con số để báo kiểu.
    Mình thay cả 3.7 ở cả trên code nữa cơ, tức là code sẽ thành:
    float a;
    cin>>a;
    if(a<3.7) cout<< "NHO HON ";
    else cout<< "LON HON BANG ";
    Và rồi khi cho RUN-> nhập 3.7 thì compiler cho ra : LON HON BANG (đúng).

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn