Công cụ bảo vệ mã nguồn .NET mạnh nhất, không thể unpack, miễn phí cho các khách hàng đầu tiên đăng ký.
Trang 2 trên tổng số 2 Đầu tiênĐầu tiên 12
Từ 11 tới 13 trên tổng số 13 kết quả

Đề tài: Mũ 2 nhưng không chia hết cho 2???

  1. #11
    Ngày gia nhập
    01 2008
    Nơi ở
    Rất đông người
    Bài viết
    582

    Mặc định Mũ 2 nhưng không chia hết cho 2???

    khoaph: nếu bạn tính 2^60 hay 2^63 thì nguyên nhân là do độ chính xác của pow(), như mình nói ở trên. Kiểu double chỉ chính xác được có 53 bit thôi.

    Còn ở đây tính 2^64 nên nguyên nhân là undefined behavior, như INTP nói, mới là đúng.
    Công cụ bảo vệ mã nguồn .NET mạnh nhất hiện tại, miễn phí cho các khách hàng đầu tiên đăng ký.
    -...- -.- .. .-.. .-.. - .... . -... . .- ... - .-.-.

  2. #12
    Ngày gia nhập
    07 2011
    Bài viết
    474

    kiểu double chính xác 53 bit nhưng nó lưu trữ được chính xác số có dạng 2^i với i có thể lên tới hình như 127 gì lận. Ở đây chỉ có mũ 2 nên nó chính xác tuyệt đối được mà.

    code #16 nào ở đâu @_@

    à code ở #6 à. Vì double lưu trữ chính xác được số có dạng 2^i với i từ -128 tới 127, nên (bit64)pow(2, i) convert sang ull chính xác với i từ 0 tới 63. Còn (bit64)(pow(2, i) - 1) thì vì có -1, nên số thực kia ko còn là dạng 2^i nữa, và vì kiểu double chỉ có 52 bit mantissa nên nó chỉ đúng tới 53 bit (thêm 1 bit 1 ở đầu) nên từ i = 54 trở đi, 2^i - 1 = 2^i, giống như kiểu với tỷ phú đô la thì 1 cent chả có nghĩa lý gì, có trừ 1 cent thì tỷ phú vẫn là tỷ phú vậy. Vì vậy (pow(2, i) - 1) với i = 53 trở xuống thì có giá trị 2^i - 1, còn i = 54 trở lên thì có giá trị 2^i.

    lạ ở chỗ i = 64 nó vẫn tuân thủ theo quy luật???
    edit: có lẽ là nó ra 1 số x nào đó khác 2^i, còn số kia nó ra x-1, x - (x-1) vẫn ra 1

    với i từ 0 tới 53:
    pow(2,i) - 1 = 2i - 1, (ull)(pow(2,i) - 1) = 2i - 1
    pow(2,i) = 2i, (ull)pow(2,i) = 2i, trừ 1 = 2i - 1
    vế trái = vế phải nên kết quả là 0

    với i từ 54 tới 63:
    pow(2,i) - 1 = 2i, (ull)(pow(2,i) - 1) = 2i
    pow(2,i) = 2i, (ull)pow(2,i) = 2i, trừ 1 = 2i - 1
    vế trái - vế phải = 1

    với i = 64:
    pow(2,i) - 1 = 264, (ull)(pow(2,i) - 1) = ???
    pow(2,i) = 264, (ull)pow(2,i) = ???, trừ 1 = ??? - 1
    ??? - (??? - 1) = 1
    Đã được chỉnh sửa lần cuối bởi INTP : 16-11-2019 lúc 01:34 AM.

  3. #13
    Ngày gia nhập
    12 2015
    Nơi ở
    Đà Nẵng
    Bài viết
    467

    Trích dẫn Nguyên bản được gửi bởi Ada Xem bài viết
    khoaph: nếu bạn tính 2^60 hay 2^63 thì nguyên nhân là do độ chính xác của pow(), như mình nói ở trên. Kiểu double chỉ chính xác được có 53 bit thôi.

    Còn ở đây tính 2^64 nên nguyên nhân là undefined behavior, như INTP nói, mới là đúng.
    Trích dẫn Nguyên bản được gửi bởi INTP Xem bài viết
    kiểu double chính xác 53 bit nhưng nó lưu trữ được chính xác số có dạng 2^i với i có thể lên tới hình như 127 gì lận. Ở đây chỉ có mũ 2 nên nó chính xác tuyệt đối được mà.

    code #16 nào ở đâu @_@

    à code ở #6 à. Vì double lưu trữ chính xác được số có dạng 2^i với i từ -128 tới 127, nên (bit64)pow(2, i) convert sang ull chính xác với i từ 0 tới 63. Còn (bit64)(pow(2, i) - 1) thì vì có -1, nên số thực kia ko còn là dạng 2^i nữa, và vì kiểu double chỉ có 52 bit mantissa nên nó chỉ đúng tới 53 bit (thêm 1 bit 1 ở đầu) nên từ i = 54 trở đi, 2^i - 1 = 2^i, giống như kiểu với tỷ phú đô la thì 1 cent chả có nghĩa lý gì, có trừ 1 cent thì tỷ phú vẫn là tỷ phú vậy. Vì vậy (pow(2, i) - 1) với i = 53 trở xuống thì có giá trị 2^i - 1, còn i = 54 trở lên thì có giá trị 2^i.

    lạ ở chỗ i = 64 nó vẫn tuân thủ theo quy luật???
    edit: có lẽ là nó ra 1 số x nào đó khác 2^i, còn số kia nó ra x-1, x - (x-1) vẫn ra 1

    với i từ 0 tới 53:
    pow(2,i) - 1 = 2i - 1, (ull)(pow(2,i) - 1) = 2i - 1
    pow(2,i) = 2i, (ull)pow(2,i) = 2i, trừ 1 = 2i - 1
    vế trái = vế phải nên kết quả là 0

    với i từ 54 tới 63:
    pow(2,i) - 1 = 2i, (ull)(pow(2,i) - 1) = 2i
    pow(2,i) = 2i, (ull)pow(2,i) = 2i, trừ 1 = 2i - 1
    vế trái - vế phải = 1

    với i = 64:
    pow(2,i) - 1 = 264, (ull)(pow(2,i) - 1) = ???
    pow(2,i) = 264, (ull)pow(2,i) = ???, trừ 1 = ??? - 1
    ??? - (??? - 1) = 1
    Mình hiểu rồi, cảm ơn các bạn
    Với i=64 hiệu trên cũng = 1 như i=54...63 hóa ra là ngẫu nhiên thôi
    Công cụ bảo vệ mã nguồn .NET mạnh nhất hiện tại, miễn phí cho các khách hàng đầu tiên đăng ký.

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