Tại sao Math.floor trả về giá trị nhân đôi?


104

Javadoc chính thức nói rằng Math.floor()trả về một double"bằng một số nguyên toán học", nhưng sau đó tại sao nó không trả về một int?

Câu trả lời:


80

Theo Javadoc cùng:

Nếu đối số là NaNhoặc vô cực hoặc số 0 dương hoặc số 0 âm, thì kết quả giống với đối số. Không thể làm điều đó với một int.

doubleGiá trị lớn nhất cũng lớn hơn giá trị lớn nhất int, vì vậy nó sẽ phải là a long.


40
có vẻ không nhất quán với các hàm Math.Round, hàm này trả về int / long và xử lý các trường hợp đặc biệt theo một cách khác.
zod

1
Lưu ý rằng Javadoc cho biết nó trả về " giá trị dấu phẩy động * lớn nhất (gần nhất với vô cực dương) * nhỏ hơn hoặc bằng đối số và bằng một số nguyên toán học" . Cho một giá trị x> 2 ^ 53 sẽ không giống với giá trị bị cắt bớt phần phân số của nó. Nó cũng có thể nhỏ hơn thế một chút.
Jim Garrison

16

Nó cho độ chính xác. Kiểu dữ liệu kép có phần định trị 53 bit. Trong số những điều khác có nghĩa là một đôi có thể đại diện cho tất cả tổng thể lên đến 2 ^ 53 mà không bị mất độ chính xác.

Nếu bạn lưu trữ một số lớn như vậy trong một số nguyên, bạn sẽ bị tràn. Số nguyên chỉ có 32 bit.

Trả lại số nguyên dưới dạng kép là điều đúng đắn cần làm ở đây vì nó cung cấp phạm vi số hữu ích rộng hơn nhiều so với số nguyên có thể.


Tất nhiên, nó có thể trở lại một thời gian dài để đối phó với những giá trị như vậy. Tuy nhiên, bạn vẫn phải tìm ra những việc cần làm với số nhân đôi> 2 ^ 63.
Jon Skeet

1
@Jon, đúng, nhưng điều đó sẽ dẫn đến tác động đến hiệu suất (không có hướng dẫn chuyển đổi từ dài sang kép trong bất kỳ tập lệnh nào mà tôi biết). Tôi tự hỏi Math.floor làm gì với nhân đôi> 2 ^ 53 ở vị trí đầu tiên. Một số kết quả không thể đại diện được.
Nils Pipenbrinck

Nhưng sau đó, dạng giả thành ngữ (int) Math.floor (foo), cũng xuất hiện trong javadoc chính thức là không an toàn vì kết quả có thể không khớp với một int, đúng không? Và một lần nữa, đây là một hình thức an toàn để sử dụng Math.floor, vì kết quả có thể không vừa với một thời gian dài?
Raibaz

10

Những người khác đã cho bạn biết lý do tại sao, tôi sẽ cho bạn biết cách làm tròn một cách chính xác nếu bạn muốn làm điều này. Nếu bạn chỉ sử dụng các số dương, thì bạn có thể sử dụng câu lệnh sau:

int a=(int) 1.5;

Tuy nhiên, (int) luôn làm tròn về phía 0. Vì vậy, nếu bạn muốn thực hiện một số âm:

int a=(int) -1.5; //Equal to -1

Trong trường hợp của tôi, tôi không muốn làm điều này. Tôi đã sử dụng mã sau để làm tròn và có vẻ như nó xử lý tốt tất cả các trường hợp cạnh:

private static long floor(double a)
{
    return (int) Math.floor(a);
}

7
Tại sao không sử dụng (int) Math.floor(a)? Nó có lẽ hiệu quả hơn và nó ngắn hơn.
Solomon Ucko

@Solomon Ucko thay vì (int) Math.floor(a)bạn có thể chỉ cần viết (int) a, nếu a là dương.
Leo Leontev

3

Bạn muốn nó trả về bao nhiêu nếu bạn cho nó lớn hơn gấp đôi so với giá trị int lớn nhất hoặc long?

(Phải thừa nhận rằng nếu nó lớn hơn độ dài lớn nhất thì độ chính xác sẽ thấp hơn - nó có thể không phải là số nguyên lý thuyết gần nhất - nhưng thậm chí như vậy ...)


0

Cũng giống như cách phân chia số nguyên và dấu phẩy động trong Java, có những cách phân chia số nguyên và dấu phẩy động để thực hiện tầng:

double f = Math.floor(x);

hoặc là

int k = (int) x; 

nhưng bạn luôn cần phải cẩn thận với việc sử dụng sàn với số học chính xác hữu hạn: phép tính x của bạn có thể mang lại kết quả như 1.99999999 sẽ được xếp thành 1, không phải 2 bởi cả hai dạng. Có nhiều thuật toán cần giải quyết hạn chế này để tránh tạo ra kết quả sai cho một số giá trị đầu vào.


0

Vì vậy, lỗi đó và các giá trị không phải số nguyên khác có thể phân tầng chính xác thông qua một loạt các phép tính.

Ví dụ: nếu bạn cung cấp Không phải số (NaN) vào Math.floor, nó sẽ chuyển nó theo.

Nếu nó trả về số nguyên, nó không thể vượt qua những trạng thái hoặc lỗi này và bạn có thể nhận được kết quả xấu từ một phép tính trước đó trông tốt nhưng lại sai sau khi xử lý thêm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.