2010-03-11 29 views
18

(int)(33.46639 * 1000000) trả về 33466389Tại sao (int) (33.46639 * 1000000) trả lại 33466389?

Tại sao điều này xảy ra?

+0

Bạn mong đợi điều gì sẽ xảy ra? – SLaks

+0

@Slaks: 3346639, còn được gọi là câu trả lời đúng. –

+0

Nơi tốt để bắt đầu: http://docs.sun.com/source/806-3568/ncg_goldberg.html (Mọi nhà khoa học máy tính nên biết gì về Số học Floating-Point) – mjv

Trả lời

31

Toán học dấu chấm động không hoàn hảo. What every programmer should know về nó.

Số học dấu chấm động được coi là chủ đề bí truyền của nhiều người. Điều này khá đáng ngạc nhiên vì dấu phẩy động là phổ biến trong các hệ thống máy tính. Hầu như mọi ngôn ngữ đều có kiểu dữ liệu dấu phẩy động; máy tính từ máy tính đến siêu máy tính có máy gia tốc điểm nổi; hầu hết các trình biên dịch sẽ được gọi để biên dịch các thuật toán dấu phẩy động theo thời gian; và hầu như mọi hệ điều hành đều phải trả lời các ngoại lệ dấu phẩy động như tràn. Bài báo này trình bày một hướng dẫn về các khía cạnh của dấu phẩy động có ảnh hưởng trực tiếp đến các nhà thiết kế hệ thống máy tính. Nó bắt đầu với nền tảng trên biểu diễn dấu chấm động và lỗi làm tròn, tiếp tục với một cuộc thảo luận về tiêu chuẩn điểm nổi IEEE, và kết luận với nhiều ví dụ về cách các nhà xây dựng máy tính có thể hỗ trợ tốt hơn dấu phẩy động.

...

Nặn vô cùng nhiều số thực thành một số hữu hạn các bit yêu cầu một đại diện tương đối. Mặc dù có vô số số nguyên, trong hầu hết các chương trình, kết quả của phép tính nguyên có thể được lưu trữ trong 32 bit. Ngược lại, với bất kỳ số bit cố định nào, hầu hết các phép tính với số thực sẽ tạo ra các đại lượng không thể được biểu diễn chính xác bằng cách sử dụng nhiều bit đó. Do đó, kết quả của phép tính dấu chấm động thường phải được làm tròn để phù hợp với biểu diễn hữu hạn của nó. Lỗi làm tròn này là tính năng đặc trưng của tính toán dấu phẩy động.

+1

Đúng là số học dấu phẩy động là phổ biến và phức tạp, nhưng điều này không trả lời câu hỏi (trừ khi bạn đếm liên kết tới một trang giấy 80 trang có câu trả lời ở đâu đó). –

+2

@Henry - điểm nằm trong tiêu đề của bài viết được liên kết. ** Mỗi lập trình viên ** nên biết về điều này, và nếu họ không họ nên đọc bài viết. (OK, có thể không phải tất cả 80 trang ...) –

+9

+1: liên kết tới một trang giấy 80 trang có câu trả lời ở đâu đó là một tiêu chuẩn anwser. Câu hỏi này - ở dạng này hay dạng khác - được hỏi quá thường xuyên. Bài báo này là * câu trả lời *. Các câu hỏi là tất cả các bản sao.Chúng tôi không cần lặp lại thông tin này nữa. –

5

độ chính xác kép không phải là chính xác, vì vậy nội 33,46639 là thực sự được lưu trữ như 33,466389

Edit: Theo Richard nói, nó nổi dữ liệu điểm, (được lưu trữ trong hệ nhị phân trong một tập hữu hạn các bit) vì vậy nó không chính xác điều đó) ....

+1

hoặc 33.4668885 hoặc một cái gì đó khác 'đủ gần' làm tròn nó, tùy thuộc vào phần cứng. – DaveE

+1

Um, không có điều nào ở trên. Nó nằm trong cơ sở 2. Hầu hết các con số như vậy KHÔNG THỂ được thể hiện chính xác trong cơ sở 10. (Dù không sử dụng chuỗi ký tự lặp lại vô hạn, tương tự như cách 1/3 được biểu diễn bằng 0.33333 [inf] trong cơ sở 10.) –

+0

, không chính xác ... nhưng một cái gì đó gần gũi hơn so với bản gốc. –

-1

Lý do bạn nhận được một kết quả khác nhau là một thực tế mà bạn sử dụng một 'đúc'

 
(int)(33.46639 * 1000000) returns 33466389 
^^^^^ 

bỏ kết quả vào một loại 'int' ... mà một trong hai làm tròn lên hoặc xuống các loại tích phân khi nhân với nhau và sau đó chuyển đổi thành 'int' .... không dựa vào điểm nổi đủ chính xác .... Skeet đăng một giới thiệu tuyệt vời trên trang web của mình herehere ...

+0

Không có gì mất mát về dàn diễn viên. Thư viện chính xác tùy ý tồn tại. –

+0

Tôi tưởng tượng anh ta hỏi "8 người đến từ đâu trong kết quả của tôi?" Nhân với 1000000 giống như di chuyển 6 chữ số thập phân sang phải, phải là "33466390", nhưng đó không phải là những gì anh ta nhận được. Câu trả lời của bạn là những gì tôi nghĩ ban đầu mặc dù, cho đến khi tôi đọc câu hỏi một lần nữa. – Pwninstein

+0

@Richard - cố định giá trị 'float' hoặc' double' thành 'int' loại bỏ phần phân số, vì vậy bạn sẽ mất thông tin. – Seth

1

Nếu bạn hỏi tại sao nó không trở thành 33466390, bởi vì double s không có độ chính xác vô hạn và số không thể được biểu thị chính xác theo dạng nhị phân.

Nếu bạn thay thế double với một decimal ((int)(33.46639m * 1000000)), nó được tính bằng 33466390, vì decimal s được tính theo cơ sở 10

+0

Các vấn đề như thế này là cố hữu trong dấu phẩy động, không chỉ là dấu phẩy động nhị phân. Chắc chắn, thập phân được 33.46639 * 1000000 ngay, nhưng vẫn có 1/3 * 3! = 1 và pow (sqrt (2), 2)! = 2. – dan04

+0

Có, nhưng vấn đề cụ thể của anh là do nhị phân. – SLaks

2

Lý do là 33,46639 sẽ được biểu diễn như một cái gì đó hơi ít hơn con số đó .

Nhân với 1000000 sẽ cung cấp cho bạn 33466389.99999999.

Nhập-đúc bằng (int) sau đó sẽ chỉ trả về phần nguyên (33466389).

Nếu bạn muốn số "đúng", hãy thử làm tròn() trước khi nhập.

+4

Whoa! ..... không không không không không. Nếu bạn muốn câu trả lời "đúng", bạn không thể sử dụng số học dấu chấm động. –

+4

Không. Nếu bạn muốn câu trả lời "đúng", bạn không thể sử dụng số học dấu chấm động * nhị phân *. Sử dụng kiểu 'thập phân' sử dụng số học dấu phẩy động thập phân và nó sẽ hoạt động như bạn mong đợi. – Gabe

+1

33.46639 là câu trả lời "đúng". Vấn đề là người hỏi không hỏi câu hỏi đúng. –

1

Vì không thể diễn tả chính xác 33.46639 trong một số hữu hạn số nhị phân. Kết quả thực tế của 33.46639 * 1000000 là 33466389.9999999962747097015380859375. Các diễn viên cắt ngắn nó để 33466389.

+0

Hãy thử "không thể được thể hiện chính xác trong một số hữu hạn các số nhị phân phân số" –

3

Đó là đêm giao thừa năm mới vào cuối năm 1994. Andy Grove, Giám đốc điều hành của Intel, đã ra một năm tuyệt vời, những gì với bộ vi xử lý Pentium sắp ra và là một hit lớn. Vì vậy, anh bước vào một quán bar và yêu cầu một cú đúp của Johnnie Walker Green Label.

Người phục vụ phục vụ và nói, "đó sẽ là $ 20, thưa ngài."

Grove đặt một hóa đơn hai mươi đô la trên quầy, nhìn vào nó một lúc, và nói, "giữ sự thay đổi."

http://en.wikipedia.org/wiki/Pentium_FDIV_bug

+0

Nhưng ... đó là một số nguyên ... – Rawling

Các vấn đề liên quan