Tôi có một chương trình cố gắng thu nhỏ double
xuống một con số mong muốn. Đầu ra tôi nhận được là NaN
.
Không gì NaN
có nghĩa là trong Java?
Tôi có một chương trình cố gắng thu nhỏ double
xuống một con số mong muốn. Đầu ra tôi nhận được là NaN
.
Không gì NaN
có nghĩa là trong Java?
Câu trả lời:
Lấy từ trang này :
"NaN" là viết tắt của "not a number". "Nan" được tạo ra nếu một phép toán dấu chấm động có một số tham số đầu vào khiến hoạt động tạo ra một số kết quả không xác định. Ví dụ, 0,0 chia cho 0,0 là không xác định về mặt số học. Lấy căn bậc hai của một số âm cũng không xác định.
NaN
có tính chất thú vị là "số" duy nhất không giống với chính nó khi so sánh. Do đó, một thử nghiệm phổ biến (và trong nhiều ngôn ngữ là duy nhất) nếu một số x
là NaN
như sau:boolean isNaN(x){return x != x;}
i
và một số ngôn ngữ như python đối phó rất tốt với nó ... Nó có thể không phải là trường hợp của java
bạn
NaN
có nghĩa là “Không phải số” và về cơ bản là đại diện của một giá trị dấu phẩy động đặc biệt trong tiêu chuẩn dấu chấm động IEE 754 . NaN thường có nghĩa là giá trị là thứ không thể được biểu thị bằng một số dấu phẩy động hợp lệ.
Một chuyển đổi sẽ dẫn đến giá trị này, khi giá trị được chuyển đổi là giá trị khác, ví dụ: khi chuyển đổi một chuỗi không đại diện cho một số.
parseFloat()
hoặc parseDouble
? Hay cái gì khác?
NaN
có nghĩa là "Không phải là Số" và là kết quả của các phép toán không xác định trên các số dấu phẩy động, chẳng hạn như chia 0 cho 0. (Lưu ý rằng trong khi phép chia một số khác 0 cho không cũng thường không được xác định trong toán học, nó không dẫn đến NaN mà là dương hoặc âm vô cùng).
NaN
có nghĩa là "Không phải số". Đó là một giá trị dấu phẩy động đặc biệt có nghĩa là kết quả của một phép toán không được xác định hoặc không thể biểu diễn dưới dạng số thực.
Xem ở đây để giải thích thêm về giá trị này.
NaN là viết tắt của Not a Number. Nó được sử dụng để biểu thị bất kỳ giá trị nào không được xác định về mặt toán học. Như chia 0,0 cho 0,0. Bạn có thể xem tại đây để biết thêm thông tin: https://web.archive.org/web/20120819091816/http://www.concentric.net/~ttwang/tech/javafloat.htm
Đăng chương trình của bạn ở đây nếu bạn cần thêm trợ giúp.
NaN = Không phải là số.
Ví dụ tối thiểu có thể chạy được
Điều đầu tiên bạn phải biết, đó là khái niệm NaN được thực hiện trực tiếp trên phần cứng CPU.
Tất cả các CPU hiện đại chính dường như tuân theo IEEE 754 chỉ định các định dạng dấu chấm động và NaN, chỉ là các giá trị float đặc biệt, là một phần của tiêu chuẩn đó.
Do đó, khái niệm này sẽ rất giống nhau trên bất kỳ ngôn ngữ nào, bao gồm cả Java chỉ phát ra mã dấu phẩy động trực tiếp đến CPU.
Trước khi tiếp tục, trước tiên bạn có thể muốn đọc các câu trả lời tôi đã viết sau đây:
Bây giờ cho một số hành động Java. Hầu hết các chức năng quan tâm không có trong ngôn ngữ cốt lõi đều nằm bên trong java.lang.Float
.
Nan.java
import java.lang.Float;
import java.lang.Math;
public class Nan {
public static void main(String[] args) {
// Generate some NaNs.
float nan = Float.NaN;
float zero_div_zero = 0.0f / 0.0f;
float sqrt_negative = (float)Math.sqrt(-1.0);
float log_negative = (float)Math.log(-1.0);
float inf_minus_inf = Float.POSITIVE_INFINITY - Float.POSITIVE_INFINITY;
float inf_times_zero = Float.POSITIVE_INFINITY * 0.0f;
float quiet_nan1 = Float.intBitsToFloat(0x7fc00001);
float quiet_nan2 = Float.intBitsToFloat(0x7fc00002);
float signaling_nan1 = Float.intBitsToFloat(0x7fa00001);
float signaling_nan2 = Float.intBitsToFloat(0x7fa00002);
float nan_minus = -nan;
// Generate some infinities.
float positive_inf = Float.POSITIVE_INFINITY;
float negative_inf = Float.NEGATIVE_INFINITY;
float one_div_zero = 1.0f / 0.0f;
float log_zero = (float)Math.log(0.0);
// Double check that they are actually NaNs.
assert Float.isNaN(nan);
assert Float.isNaN(zero_div_zero);
assert Float.isNaN(sqrt_negative);
assert Float.isNaN(inf_minus_inf);
assert Float.isNaN(inf_times_zero);
assert Float.isNaN(quiet_nan1);
assert Float.isNaN(quiet_nan2);
assert Float.isNaN(signaling_nan1);
assert Float.isNaN(signaling_nan2);
assert Float.isNaN(nan_minus);
assert Float.isNaN(log_negative);
// Double check that they are infinities.
assert Float.isInfinite(positive_inf);
assert Float.isInfinite(negative_inf);
assert !Float.isNaN(positive_inf);
assert !Float.isNaN(negative_inf);
assert one_div_zero == positive_inf;
assert log_zero == negative_inf;
// Double check infinities.
// See what they look like.
System.out.printf("nan 0x%08x %f\n", Float.floatToRawIntBits(nan ), nan );
System.out.printf("zero_div_zero 0x%08x %f\n", Float.floatToRawIntBits(zero_div_zero ), zero_div_zero );
System.out.printf("sqrt_negative 0x%08x %f\n", Float.floatToRawIntBits(sqrt_negative ), sqrt_negative );
System.out.printf("log_negative 0x%08x %f\n", Float.floatToRawIntBits(log_negative ), log_negative );
System.out.printf("inf_minus_inf 0x%08x %f\n", Float.floatToRawIntBits(inf_minus_inf ), inf_minus_inf );
System.out.printf("inf_times_zero 0x%08x %f\n", Float.floatToRawIntBits(inf_times_zero), inf_times_zero);
System.out.printf("quiet_nan1 0x%08x %f\n", Float.floatToRawIntBits(quiet_nan1 ), quiet_nan1 );
System.out.printf("quiet_nan2 0x%08x %f\n", Float.floatToRawIntBits(quiet_nan2 ), quiet_nan2 );
System.out.printf("signaling_nan1 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan1), signaling_nan1);
System.out.printf("signaling_nan2 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan2), signaling_nan2);
System.out.printf("nan_minus 0x%08x %f\n", Float.floatToRawIntBits(nan_minus ), nan_minus );
System.out.printf("positive_inf 0x%08x %f\n", Float.floatToRawIntBits(positive_inf ), positive_inf );
System.out.printf("negative_inf 0x%08x %f\n", Float.floatToRawIntBits(negative_inf ), negative_inf );
System.out.printf("one_div_zero 0x%08x %f\n", Float.floatToRawIntBits(one_div_zero ), one_div_zero );
System.out.printf("log_zero 0x%08x %f\n", Float.floatToRawIntBits(log_zero ), log_zero );
// NaN comparisons always fail.
// Therefore, all tests that we will do afterwards will be just isNaN.
assert !(1.0f < nan);
assert !(1.0f == nan);
assert !(1.0f > nan);
assert !(nan == nan);
// NaN propagate through most operations.
assert Float.isNaN(nan + 1.0f);
assert Float.isNaN(1.0f + nan);
assert Float.isNaN(nan + nan);
assert Float.isNaN(nan / 1.0f);
assert Float.isNaN(1.0f / nan);
assert Float.isNaN((float)Math.sqrt((double)nan));
}
}
Chạy với:
javac Nan.java && java -ea Nan
Đầu ra:
nan 0x7fc00000 NaN
zero_div_zero 0x7fc00000 NaN
sqrt_negative 0xffc00000 NaN
log_negative 0xffc00000 NaN
inf_minus_inf 0x7fc00000 NaN
inf_times_zero 0x7fc00000 NaN
quiet_nan1 0x7fc00001 NaN
quiet_nan2 0x7fc00002 NaN
signaling_nan1 0x7fa00001 NaN
signaling_nan2 0x7fa00002 NaN
nan_minus 0xffc00000 NaN
positive_inf 0x7f800000 Infinity
negative_inf 0xff800000 -Infinity
one_div_zero 0x7f800000 Infinity
log_zero 0xff800000 -Infinity
Vì vậy, từ điều này, chúng tôi học được một số điều:
Các phép toán trôi nổi kỳ lạ không có bất kỳ kết quả hợp lý nào cho NaN:
0.0f / 0.0f
sqrt(-1.0f)
log(-1.0f)
tạo ra một NaN
.
Trong C, thực sự có thể yêu cầu các tín hiệu được nâng lên trên các hoạt động như vậy feenableexcept
để phát hiện chúng, nhưng tôi không nghĩ rằng nó được hiển thị trong Java: Tại sao phép chia số nguyên cho 0 1/0 lại cho lỗi nhưng dấu phẩy động 1 / 0,0 trả về "Inf"?
các phép toán kỳ lạ nằm trong giới hạn của cộng hoặc trừ vô cùng tuy nhiên lại cho + - vô cực thay vì NaN
1.0f / 0.0f
log(0.0f)
0.0
gần như thuộc loại này, nhưng có thể vấn đề là nó có thể đi đến cộng hoặc trừ vô cùng, vì vậy nó được để là NaN.
nếu NaN là đầu vào của một hoạt động thả nổi, thì đầu ra cũng có xu hướng là NaN
có một số giá trị có thể cho NaN 0x7fc00000
, 0x7fc00001
, 0x7fc00002
, mặc dù x86_64 dường như chỉ tạo ra 0x7fc00000
.
NaN và vô cùng có biểu diễn nhị phân tương tự.
Hãy chia nhỏ một vài trong số chúng:
nan = 0x7fc00000 = 0 11111111 10000000000000000000000
positive_inf = 0x7f800000 = 0 11111111 00000000000000000000000
negative_inf = 0xff800000 = 1 11111111 00000000000000000000000
| | |
| | mantissa
| exponent
|
sign
Từ đó, chúng tôi xác nhận những gì IEEE754 chỉ định:
NaN có thể là tích cực hoặc tiêu cực (bit trên cùng), mặc dù nó không ảnh hưởng đến hoạt động bình thường
Đã thử nghiệm trong Ubuntu 18.10 amd64, OpenJDK 1.8.0_191.
Không phải là một người chơi Java, nhưng trong JS và các ngôn ngữ khác, tôi sử dụng nó là "Not a Number", có nghĩa là một số hoạt động đã khiến nó trở thành một số không hợp lệ.
Nghĩa đen của nó là "Không phải là số". Tôi nghi ngờ có điều gì đó không ổn với quá trình chuyển đổi của bạn.
Kiểm tra phần Not A Number tại tài liệu tham khảo này
Không phải là giá trị dấu phẩy động hợp lệ (ví dụ: kết quả của phép chia cho 0)