Tại sao số 0 âm lại quan trọng?


64

Tôi bối rối về lý do tại sao chúng tôi quan tâm đến các đại diện khác nhau cho số không dương và âm.

Tôi mơ hồ nhớ lại việc đọc các tuyên bố rằng có một đại diện số 0 âm là cực kỳ quan trọng trong lập trình liên quan đến các số phức. Tôi chưa bao giờ có cơ hội viết mã liên quan đến các số phức, vì vậy tôi hơi bối rối về lý do tại sao điều này lại xảy ra.

Bài viết của Wikipedia về khái niệm này không đặc biệt hữu ích; nó chỉ làm cho những tuyên bố mơ hồ về việc ký số 0 làm cho các phép toán nhất định trở nên đơn giản hơn trong dấu phẩy động, nếu tôi hiểu chính xác. Câu trả lời này liệt kê một vài hàm hoạt động khác nhau và có lẽ một số thứ có thể được suy ra từ các ví dụ nếu bạn quen với cách chúng có thể được sử dụng. (Mặc dù, ví dụ cụ thể của căn bậc hai phức tạp trông không đúng, vì hai số này tương đương nhau về mặt toán học, trừ khi tôi có sự hiểu lầm.) Nhưng tôi đã không thể tìm thấy một tuyên bố rõ ràng về loại rắc rối mà bạn sẽ gặp phải nếu nó không có ở đó. Càng nhiều tài nguyên toán học tôi đã có thể tìm thấy trạng thái không có sự phân biệt giữa hai khía cạnh toán học và bài viết Wikipedia dường như cho thấy rằng điều này hiếm khi được nhìn thấy bên ngoài máy tính ngoài việc mô tả các giới hạn.

Vậy tại sao một số 0 âm có giá trị trong điện toán? Tôi chắc chắn tôi chỉ thiếu một cái gì đó.


6
Số 0 âm có thể báo hiệu dòng chảy trong số dấu phẩy động của IEEE, nhưng ngoài ra, việc sử dụng nó có vẻ gây tranh cãi và tối nghĩa. Nếu tôi đoán, tôi sẽ nói rằng số 0 âm được biểu thị trong dấu phẩy động của IEEE bởi vì ... tốt, bạn có thể. Đối với một chuyến đi thậm chí thú vị hơn, hãy tìm kiếm thông tin về dấu hiệu nổi NaN.
Robert Harvey

1
Nếu ví dụ cụ thể là "1 / 0,0" / "1 / -0.0", 0 là một nhánh bị cắt cho 1 / x và giới hạn phụ thuộc vào việc bạn tiếp cận nó từ bên dưới hay bên trên.
Vatine

@Vatine Không, ví dụ cụ thể là sqrt(-1+0i) = isqrt(-1-0i) = -i, mặc dù mặc quần áo với cú pháp thích hợp cho một số ngôn ngữ lập trình, tôi tin. Tôi sẽ chỉnh sửa để rõ ràng hơn.
jpmc26

3
Tôi đã tìm kiếm Lập trình viên , Stack Overflow , Khoa học Máy tính , Toán họcKỹ thuật . Câu hỏi duy nhất tôi có thể tìm thấy là Sử dụng cho giá trị dấu phẩy động âm 0? . Đây không thể chỉ là lần thứ hai xuất hiện!

Tôi thực sự ngạc nhiên khi các số phức không xuất hiện trong tất cả các câu trả lời, đặc biệt là với ví dụ căn bậc hai mà tôi đã chỉ ra.
jpmc26

Câu trả lời:


69

Bạn cần lưu ý rằng trong các số liệu của FPU, 0 không nhất thiết phải có nghĩa chính xác bằng 0, nhưng cũng có giá trị quá nhỏ để được biểu diễn bằng kiểu dữ liệu đã cho, ví dụ:

a = -1 / 1000000000000000000.0

a quá nhỏ để được biểu diễn chính xác bằng float (32 bit), do đó, nó được "làm tròn" thành -0.

Bây giờ, hãy nói rằng tính toán của chúng tôi tiếp tục:

b = 1 / a

Bởi vì a là float, nó sẽ dẫn đến -infality khá xa so với câu trả lời đúng của -1000000000000000000.0

Bây giờ hãy tính b nếu không có -0 (vì vậy a được làm tròn thành +0):

b = 1 / +0
b = +infinity

Kết quả là sai một lần nữa vì làm tròn, nhưng bây giờ nó "sai nhiều hơn" - không chỉ bằng số, mà quan trọng hơn là do dấu hiệu khác nhau (kết quả tính toán là + vô cực, kết quả đúng là -1000000000000000000.0).

Bạn vẫn có thể nói rằng nó không thực sự quan trọng vì cả hai đều sai. Điều quan trọng là có rất nhiều ứng dụng số trong đó kết quả quan trọng nhất của tính toán là dấu hiệu - ví dụ: khi quyết định nên rẽ trái hay phải ở ngã tư bằng thuật toán học máy, bạn có thể diễn giải giá trị dương => rẽ trái, giá trị âm => rẽ phải, "độ lớn" thực của giá trị chỉ là "hệ số tin cậy".


Bạn có ý tưởng nào về việc liệu dấu hiệu của dòng chảy có thể đặc biệt quan trọng trong tính toán số ảo / số phức không?
jpmc26

@qbd: Bạn có biết những ứng dụng số đó là gì không? Tôi muốn nói rằng các chương trình kích hoạt và sử dụng +inf-inftrong hoạt động bình thường đã bị lỗi.
Bjorn Lindqvist

@ BjornLindqvist Nếu bạn muốn các ứng dụng cụ thể, có thể tải xuống - thì tôi không biết gì cả. Tôi không nghĩ rằng nó nhất thiết là lỗi - thay vì nổi / gấp đôi, bạn có thể sử dụng thứ gì đó như BigDecimal với độ chính xác không giới hạn. Nhưng nó có đáng không khi chương trình sẽ cho kết quả chính xác như kết quả với float / double, nhưng với hiệu suất kém hơn nhiều?
qbd

Bạn đã viết "các ứng dụng số trong đó kết quả quan trọng nhất của tính toán là dấu hiệu" Tôi có thể tin điều đó, nhưng tôi không thể tin rằng có bất kỳ ứng dụng nào được viết tốt dựa trên -0 và dựa trên các giá trị +inf-inf. Nếu chương trình của bạn gây ra dấu phẩy động, đó là lỗi và những gì xảy ra sau đó không thú vị lắm, imho. Chúng ta vẫn còn thiếu các ví dụ thực tế trong đó -0 là hữu ích.
Bjorn Lindqvist

1
@ BjornLindqvist Phần lớn của x265 được thực hiện trong quá trình lắp ráp, dựa vào các chi tiết tối nghĩa của nó (phụ thuộc vào kiến ​​trúc CPU) mà ít người biết về tên hiệu năng. Có sai không? Dựa vào tiêu chuẩn 30 năm được triển khai rộng rãi (sẽ tồn tại) cho một tính năng đơn giản, được hiểu rõ trong tên của hiệu suất đột nhiên dường như không quá tệ.
qbd

8

Đầu tiên, làm thế nào để bạn tạo -0? Có hai cách: (1) thực hiện một phép toán dấu phẩy động trong đó kết quả toán học là âm, nhưng gần bằng 0 đến mức nó được làm tròn thành 0 và không phải là một số khác không. Tính toán đó sẽ cho -0. (b) Một số thao tác nhất định liên quan đến số 0: Nhân số 0 dương với số âm hoặc chia số 0 dương cho số âm hoặc phủ định số 0 dương.

Có số 0 âm đơn giản hóa phép nhân và chia một chút, dấu của x * y hoặc x / y luôn là dấu của x, độc quyền hoặc dấu của y. Nếu không có số 0 âm, sẽ phải có thêm một số kiểm tra để thay thế -0 bằng +0.

Có một số tình huống rất hiếm khi nó hữu ích. Bạn có thể kiểm tra xem kết quả của phép nhân hoặc phép chia có lớn hơn hoặc nhỏ hơn 0 hay không, ngay cả khi có một dòng chảy (miễn là bạn biết kết quả không phải là số 0 toán học). Tôi không thể nhớ mình đã từng viết mã khi nó tạo ra sự khác biệt.

Tối ưu hóa trình biên dịch ghét -0. Ví dụ: bạn không thể thay thế x + 0,0 bằng x, vì kết quả không nên là x nếu x là -0.0. Bạn không thể thay thế x * 0,0 bằng 0,0, vì kết quả sẽ là -0.0 nếu x <0 hoặc x là -0.0.


7
Tôi ước rằng IEEE-754 đã bao gồm bốn số 0: "chính xác", vô cực dương, vô cực âm và không dấu (cái sau là sự khác biệt giữa các giá trị không thể phân biệt). Làm điều đó sẽ làm cho rất nhiều tiên đề dấu phẩy động hoạt động - trong số đó, x + 0,0 Equiv x-0,0 Equiv x, xy Equiv x + (- 1.0) * y và 1.0 / x Equiv -1.0 / (- 1.0 * x) [nếu x là số 0 dương, cả hai sẽ là pos-inf; nếu neg-zero, cả neg-inf; nếu chính xác hoặc không dấu, cả NaN].
supercat

Tôi đã có thể có được một số 0 âm bằng cách chuyển qua -55vào fmod(). Nó khá khó chịu cho trường hợp sử dụng của tôi.
Aaron Franke

6

C # Double phù hợp với IEEE 754

    double a = 3.0;
    double b = 0.0;
    double c = -0.0;

    Console.WriteLine(a / b);
    Console.WriteLine(a / c);

in:

Infinity
-Infinity

thực sự để giải thích một chút ...

Double d = -0.0; 

Điều này có nghĩa là một cái gì đó rất gần với d = The Limit of x as x approaches 0-hoặc The Limit of x as x approaches 0 from the negatives.


Để giải quyết bình luận của Philipp ...

Về cơ bản âm 0 có nghĩa là tràn.

Có rất ít sử dụng thực tế cho số 0 âm nếu có ...

ví dụ: mã này (lại là C #):

double a = -0.0;
double b = 0.0;

Console.WriteLine(a.Equals(b));
Console.WriteLine(a==b);
Console.WriteLine(Math.Sign(a));

mang lại kết quả này:

True
True
0

Để giải thích một cách không chính thức, Tất cả các giá trị đặc biệt mà một điểm nổi IEEE 754 có thể có (vô cực dương, vô cực âm, NAN, -0.0) không có ý nghĩa gì trong ý nghĩa thực tế. Chúng không thể biểu thị bất kỳ giá trị vật lý hoặc bất kỳ giá trị nào có ý nghĩa trong tính toán "thế giới thực". Những gì họ có nghĩa là về cơ bản này:

  • vô cực dương có nghĩa là một tràn ở đầu dương mà một điểm nổi có thể biểu thị
  • vô cực âm có nghĩa là một tràn ở đầu dương mà một điểm nổi có thể biểu thị
  • số 0 âm có nghĩa là một dòng chảy và toán hạng có dấu hiệu ngược lại
  • số 0 dương có thể có nghĩa là một dòng chảy và toán hạng có cùng dấu
  • NAN có nghĩa là tính toán của bạn không được xác định rõ ràng, như sqrt(-7), hoặc nó không có giới hạn thích 0/0hoặc thíchPositiveInfinity/PositiveInfinity

7
Có, nhưng tại sao điều này lại quan trọng? Bạn có thể cung cấp một ví dụ thực tế, thực tế trong đó sự khác biệt quan trọng không?
Philipp

5

Câu hỏi về cách điều này liên quan đến các phép tính số phức thực sự là cốt lõi của lý do tại sao cả +0 và -0 tồn tại trong dấu phẩy động. Nếu bạn nghiên cứu Phân tích phức tạp, bạn sẽ nhanh chóng phát hiện ra rằng các hàm liên tục từ Phức tạp đến Phức tạp thường không thể được coi là 'giá trị đơn' trừ khi người ta chấp nhận 'tiểu thuyết lịch sự' rằng các kết quả đầu ra hình thành 'bề mặt Riemann'. Ví dụ, logarit phức tạp gán cho mỗi đầu vào vô hạn nhiều đầu ra; khi bạn 'kết nối chúng' để tạo thành một đầu ra liên tục, bạn sẽ kết thúc với tất cả các bộ phận thực sự tạo thành một bề mặt 'vô hạn nút chai' xung quanh gốc. Một đường cong liên tục đi qua trục thực 'hướng xuống từ phía tưởng tượng dương' và một đường cong khác 'quấn quanh cực' và vượt qua trục thực '

Bây giờ áp dụng điều đó cho một chương trình số tính toán bằng cách sử dụng dấu phẩy động phức tạp. Hành động được thực hiện sau khi tính toán nhất định có thể rất khác nhau tùy thuộc vào 'tờ' nào chương trình hiện đang 'bật' và dấu hiệu của kết quả tính toán cuối cùng có thể cho bạn biết 'tờ nào'. Bây giờ giả sử kết quả đó bằng không? Hãy nhớ rằng, ở đây 'zero' thực sự có nghĩa là 'quá nhỏ để thể hiện chính xác'. Nhưng nếu phép tính có thể sắp xếp để bảo vệ dấu hiệu- (nghĩa là nhớ 'tờ') khi kết quả bằng 0, thì mã có thể kiểm tra dấu hiệu và thực hiện hành động đúng ngay cả trong tình huống này.


1

Lý do đơn giản hơn bình thường

Tất nhiên, có rất nhiều hack trông rất đẹp và chúng rất hữu ích (như làm tròn đến -0.0hoặc +0.0giả sử chúng ta có một đại diện của int đã ký với dấu trừ / dấu cộng lúc đầu (tôi biết điều đó được giải quyết bằng mã nhị phân U2 trong các số nguyên thường nhưng giả sử một biểu diễn ít phức tạp hơn gấp đôi):

0 111 = 7
^ sign

Nếu có số âm thì sao?

1 111 = -7

Được rồi, đơn giản thôi. Vì vậy, hãy đại diện cho 0:

0 000 = 0

Điều đó cũng tốt. Nhưng còn cái gì 1 000? Có phải là một số bị cấm? Tốt hơn không.

Vì vậy, hãy giả sử có hai loại số không:

0 000 = +0
1 000 = -0

Chà, điều đó sẽ đơn giản hóa các tính toán của chúng tôi và may mắn đưa ra một số tính năng bổ sung. Vì vậy, +0-0đến từ chỉ các vấn đề đại diện nhị phân.


6
Nếu tôi đọc chính xác điều này, về cơ bản, bạn chỉ nói rằng mọi người xác định hoặc thực hiện các tiêu chuẩn đã không muốn gặp rắc rối trong việc cấm nó. Tôi không nghĩ lý do này phù hợp với thực tế là phần bù 2 sử dụng đại diện "số 0 âm" cho một số hoàn toàn khác và không có đại diện cho số 0 âm. Xem bài viết Wikipedia tôi liên kết.
jpmc26

1
@ jpmc26 Tôi nghĩ rằng thực sự có một số sự thật về điều đó, trong đó không cấm nó có nghĩa là không yêu cầu triển khai phải có một trường hợp đặc biệt. Như vậy, mỗi số có một bit dấu và có thể được phủ định bằng cách chuyển đổi bit dấu. Ngay cả NaN cũng được ký và việc triển khai có thể (nhưng không bắt buộc) phải chọn một dấu hiệu phù hợp khi sản xuất NaN. Nếu số 0 âm không tồn tại, mọi phép tính dẫn đến 0 sẽ cần thực hiện thêm công việc để sửa bit dấu, v.v.
hobbs

4
@ jpmc26 (tức là trong mọi phép nhân khác của hai số, dấu của kết quả là xor của dấu của bội số và độ lớn là tích của hai độ lớn. Trong cuộc sống thực, nó hoạt động với -1 * 0 = - 0. Nhưng nếu số 0 với bit dấu được lật là một giá trị khác không đặc biệt, mọi sản phẩm có thể tạo ra 0 sẽ phải kiểm tra và đảm bảo rằng nó không tạo ra giá trị đặc biệt đó do nhầm lẫn.)
hobbs
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.