Câu hỏi thứ hai bạn đặt ra mối quan tâm về số lượng lớn ulp bằng Java.
Nếu ulp vượt quá 1/(n)
, thì làm tròn phép nhân sẽ không khôi phục được số nguyên gốc được chia. Thông thường, các ulps lớn hơn được kết hợp với các giá trị tăng gấp đôi lớn hơn. Một ulp kết hợp với một đôi bắt đầu vượt quá 1 vào khoảng 9E15; nếu bạn tăng gấp đôi phục hồi được xung quanh đó, sau đó bạn có thể tìm thấy vấn đề với vòng() không nhận được câu trả lời mong đợi. Vì bạn đang làm việc với các giá trị int, mặc dù, giá trị lớn nhất của tử số của bộ phận của bạn sẽ là Integer.MAX_VALUE
.
Các thử nghiệm chương trình sau tất cả các giá trị nguyên dương của n
để xem cái nào làm cho tiềm năng lớn nhất để làm tròn lỗi khi cố gắng khôi phục lại int chia:
public static void main(String[] args)
{
// start with large number
int m = Integer.MAX_VALUE;
double d = 0;
double largestError = 0;
int bigErrorCause = -1;
for (int n = 1; n < Integer.MAX_VALUE; n++)
{
d = (double) m/n;
double possibleError = Math.ulp(d) * n;
if (possibleError > largestError)
{
largestError = possibleError;
bigErrorCause = n;
}
}
System.out.println("int " + bigErrorCause + " causes at most "
+ largestError + " error");
}
Kết quả là:
int 1073741823 gây ra tối đa 4.768371577590358E-7 lỗi
Làm tròn bằng cách sử dụng Math.round, sau đó truyền tới int sẽ khôi phục int ban đầu.
Không phải là một câu hỏi ngớ ngẩn; câu hỏi đặt ra một số vấn đề tinh tế về số học dấu phẩy động và "khả năng phục hồi" của các số nguyên. – Nayuki
rất nhiều câu hỏi nổi trên trang web này gần đây - hmm ... –