Khi chuyển đổi từ Số nguyên sang Đơn có thể mất độ chính xác


27

Tôi đã đọc một bài viết từ Microsoft về Mở rộng chuyển đổi và Tùy chọn Nghiêm cấm khi tôi đến phần

Các chuyển đổi sau có thể mất độ chính xác:

  • Số nguyên thành đơn
  • Dài đến đơn hoặc đôi
  • Số thập phân thành đơn hoặc đôi

Tuy nhiên, những chuyển đổi này không làm mất thông tin hoặc cường độ.

.. nhưng theo một bài viết khác liên quan đến các loại dữ liệu ,

  • Kiểu số nguyên có thể lưu trữ từ -2.147.483.648 đến 2.147.483.647 và

  • Loại duy nhất có thể lưu trữ từ

    • 1,401298E-45 đến 3,4028235E + 38 cho các số dương,
    • và -3,4028235E + 38 đến - 1,401298E-45 cho các số âm

.. vì vậy Single có thể lưu trữ số lượng nhiều hơn so với Integer. Tôi không thể hiểu trong trường hợp nào việc chuyển đổi như vậy từ Integer sang Single có thể mất độ chính xác. Ai đó có thể giải thích?

Câu trả lời:


87

Độc thân có thể lưu trữ số lượng nhiều hơn số nguyên

Không, nó không thể. Cả hai SingleIntegerlà 32 Bit, có nghĩa là cả hai đều có thể lưu trữ cùng một số lượng chính xác , cụ thể là 2 32 = 4294967296 các số riêng biệt.

Kể từ khi phạm vi của Singlerõ ràng là lớn hơn thế, đó là ngay lập tức rõ ràng (vì Nguyên tắc cửa chuồng bồ câu ) mà nó không thể nào đại diện cho tất cả các số trong phạm vi đó.

Và vì phạm vi Integercó cùng kích thước với số lượng tối đa mà cả hai IntegerSinglecó thể đại diện, nhưng Singlecũng có thể đại diện cho các số bên ngoài phạm vi đó, rõ ràng là nó không thể đại diện cho tất cả các số trong phạm vi Integer.

Nếu có một số con số Integerkhông thể được trình bày Single, chuyển đổi từ Integerthành Single phải có khả năng mất thông tin.


3
+1 cho lời giải thích tuyệt vời này về lý do tại sao phải như vậy, mặc dù câu hỏi thực sự là khi nào ("trong tình huống nào") nó xảy ra ...
doubleYou

21
@doubleYou: 4261412864 trong số 4294967296 Integers (99,2%) không thể được biểu diễn dưới dạng Single, vì vậy "khi" là "luôn luôn là khá nhiều".
Jörg W Mittag

2
Nếu bạn muốn chính xác hơn, Singlechỉ có thể đại diện cho 4.278.190.079 số khác nhau. Một Singlegiá trị đại diện cho một số khi và chỉ khi số mũ được lưu trữ không phải là 255, có nghĩa là có 255 * 2 ^ 24 Singles đại diện cho các số. Trong số này, hai trong số chúng đại diện cho cùng một số (cụ thể là số không) và những cái khác đều đại diện cho các số khác nhau.
Tanner Swett

10
vi.wikipedia.org/wiki/Single-precision_floating-point_format giải thích các giới hạn độc đáo cho nhị phân 3232 của IEEE754. Các số nguyên trong [-16777216,16777216](2 ^ 24 = chiều rộng có ý nghĩa) có thể được biểu diễn chính xác. Các số lớn hơn được làm tròn đến bội số gần nhất của 2, 4, 8, ... tùy thuộc vào độ lớn của chúng.
Peter Cordes

14
Có nghĩa là cả hai đều có thể lưu trữ cùng một số lượng chính xác - Điều đó không có nghĩa là như vậy. Điều đó chỉ có nghĩa là nếu cả hai loại có cùng số cách lưu trữ mỗi số. Và đây không phải là trường hợp; ví dụ, Singlecó hai cách lưu trữ số không. Vì vậy, Singlecó thể trên thực tế đại diện cho ít số khác biệt hơn Integer.
Konrad Rudolph

28

Các loại dấu phẩy động (như Đơn và Đôi) được biểu thị trong bộ nhớ bằng một dấu hiệu, một lớp phủ và số mũ. Hãy nghĩ về nó như một ký hiệu khoa học:

Sign*Mantissa*Base^Exponent

Họ - như bạn có thể mong đợi - sử dụng cơ sở 2. Có một số điều chỉnh khác cho phép biểu thị vô cực và NaN, và số mũ được bù (sẽ quay trở lại đó) và một tốc ký cho mantissa (cũng sẽ trở lại với điều đó) . Hãy tìm tiêu chuẩn IEEE 754 bao gồm các đại diện và hoạt động của nó để biết thêm chi tiết.

Đối với mục đích của chúng tôi, chúng tôi có thể tưởng tượng nó như là một số nhị phân "mantissa" và "số mũ" cho bạn biết nơi đặt dấu tách thập phân.


Trong trường hợp Độc thân, chúng tôi có 1 bit cho anh ta ký, 8 cho số mũ và 23 cho số mũ.

Bây giờ, điều là, chúng tôi sẽ lưu trữ bọ ngựa từ chữ số có ý nghĩa nhất. Hãy nhớ rằng tất cả các số 0 ở bên trái không liên quan. Và cho rằng chúng tôi đang làm việc trong hệ nhị phân, chúng tôi biết rằng chữ số có ý nghĩa nhất là 1 ※. Chà, vì chúng tôi biết điều đó, chúng tôi không phải lưu trữ nó. Nhờ tốc ký đó, phạm vi hiệu quả của lớp phủ là 24 bit.

※: Trừ khi số lượng chúng tôi đang lưu trữ bằng không. Cho rằng chúng ta sẽ có tất cả các bit được đặt thành không. Tuy nhiên, nếu chúng tôi cố gắng diễn giải rằng theo mô tả mà tôi đã đưa ra, bạn sẽ có 2 ^ 24 (ẩn 1) nhân với 1 (2 với sức mạnh của số mũ 0). Vì vậy, để khắc phục nó, số mũ là một giá trị đặc biệt. Ngoài ra còn có các giá trị đặc biệt để lưu trữ vô cực và NaN theo số mũ.

Theo phần bù lũy thừa - ngoài việc tránh các giá trị đặc biệt - có phần bù cho phép đặt dấu thập phân trước khi bắt đầu lớp phủ hoặc sau khi kết thúc, mà không cần phải có dấu cho số mũ.


Điều này có nghĩa là đối với số lượng lớn, loại dấu phẩy động sẽ đặt dấu thập phân vượt quá điểm cuối của lớp phủ.

Hãy nhớ rằng mantissa là một số 24 bit. Nó sẽ không bao giờ đại diện cho một số 25 bit ... nó không có thêm bit đó. Do đó, đơn không thể phân biệt giữa 2 ^ 24 và 2 ^ 24 + 1 (đây là các số 25 bit đầu tiên và chúng khác nhau ở bit cuối cùng, không được biểu thị trong đơn).

Do đó, đối với số nguyên, phạm vi của đơn là -2 ^ 24 đến 2 ^ 24. Và cố gắng thêm 1 đến 2 ^ 24 sẽ cho kết quả là 2 ^ 24 (vì theo như loại có liên quan, 2 ^ 24 và 2 ^ 24 + 1 là cùng một giá trị). Hãy thử trực tuyến . Đây là lý do tại sao có sự mất thông tin khi chuyển đổi từ số nguyên sang đơn. Và đây cũng là lý do tại sao một vòng lặp sử dụng một hoặc hai lần thực sự có thể là một vòng lặp vô hạn mà bạn không nhận ra.


Đây không phải là một lời giải thích hoàn hảo về 1bit dẫn đầu ngầm trong ý nghĩa. Nó được ngụ ý bởi trường số mũ thiên vị là khác không . Subnormals (còn gọi là biến thái) bao gồm+-0.0 có một 0chút ý nghĩa hàng đầu của chúng. Tôi đoán bạn có thể đơn giản hóa để chỉ xem xét 0.0một trường hợp hoàn toàn đặc biệt, nhưng 0.0thực sự tuân theo các quy tắc mã hóa giống như các chương trình con khác.
Peter Cordes

25

Đây là một ví dụ thực tế khi chuyển đổi từ Integersang Singlecó thể mất độ chính xác:

Các Singleloại có thể lưu trữ tất cả các số nguyên từ -16777216 đến 16777216 (bao gồm), nhưng nó không thể lưu trữ tất cả các số nguyên bên ngoài phạm vi này. Ví dụ: nó không thể lưu trữ số 16777217. Đối với vấn đề đó, nó không thể lưu trữ bất kỳ số lẻ nào lớn hơn 16777216.

Chúng tôi có thể sử dụng Windows PowerShell để xem điều gì sẽ xảy ra nếu chúng tôi chuyển đổi Integerthành một Singlevà trở lại:

PS C:\Users\tanne> [int][float]16777213
16777213
PS C:\Users\tanne> [int][float]16777214
16777214
PS C:\Users\tanne> [int][float]16777215
16777215
PS C:\Users\tanne> [int][float]16777216
16777216
PS C:\Users\tanne> [int][float]16777217
16777216
PS C:\Users\tanne> [int][float]16777218
16777218
PS C:\Users\tanne> [int][float]16777219
16777220

Lưu ý rằng 16777217 được làm tròn xuống 16777216 và 16777219 được làm tròn lên đến 16777220.


4
Và với cường độ ngày càng tăng, khoảng cách giữa floatcác s đại diện gần nhất tiếp tục tăng lên như sức mạnh của. vi.wikipedia.org/wiki/ từ
Peter Cordes

12

Các loại dấu phẩy động tương tự như "ký hiệu khoa học" trong vật lý. Số được chia thành một bit dấu, số mũ (số nhân) và mantissa (chữ số có nghĩa). Vì vậy, khi độ lớn của giá trị tăng kích thước bước cũng tăng.

Điểm nổi chính xác duy nhất có 23 bit mantissa, nhưng có "1 ẩn", vì vậy mantissa có hiệu quả 24 bit. Do đó, tất cả các số nguyên có cường độ lên tới 2 24 có thể được biểu diễn chính xác theo điểm nổi chính xác duy nhất.

Trên đó liên tiếp số lượng ít hơn có thể được đại diện.

  • Từ 2 24 đến 2 25 chỉ các số chẵn có thể được biểu diễn.
  • Từ 2 25 đến 2 26 chỉ có thể nhân bội số của 4.
  • Từ 2 26 đến 2 27 chỉ có thể nhân bội số của 8.
  • Từ 2 27 đến 2 28 chỉ có thể nhân bội số của 16
  • Từ 2 28 đến 2 29 chỉ có thể nhân bội số của 32
  • Từ 2 29 đến 2 30 chỉ có thể biểu diễn bội số của 64
  • Từ 2 30 đến 2 31 chỉ có thể biểu diễn bội số của 128

Vì vậy, trong 2 giá trị nguyên có thể ký 32 32 có thể chỉ có 2 * (2 24 + 7 * 2 23 ) = 9 * 2 24 có thể được biểu diễn trong một dấu phẩy động chính xác duy nhất. Đó là 3,515625% tổng số.


8

Phao chính xác đơn có 24 bit chính xác. Bất cứ thứ gì trên đó được làm tròn đến số 24 bit gần nhất. Có thể dễ hiểu hơn trong ký hiệu khoa học thập phân, nhưng hãy nhớ rằng phao thực tế sử dụng nhị phân.

Giả sử bạn có 5 chữ số thập phân của bộ nhớ. Bạn có thể chọn sử dụng những số như int không dấu thông thường, cho phép bạn có bất kỳ số nào trong khoảng từ 0 đến 99999. Nếu bạn muốn có thể biểu thị các số lớn hơn, bạn có thể sử dụng ký hiệu khoa học và chỉ cần phân bổ hai chữ số là số mũ, vì vậy bây giờ bạn có thể biểu thị bất cứ thứ gì trong khoảng từ 0 đến 9,99 x 10 99 .

Tuy nhiên, số lớn nhất bạn có thể đại diện chính xác bây giờ chỉ là 999. Nếu bạn cố gắng đại diện cho 12345, bạn có thể nhận được 1,23 x 10 4 hoặc 1,24 x 10 4 , nhưng bạn không thể đại diện cho bất kỳ số nào ở giữa, bởi vì bạn không có đủ chữ số có sẵn.


3
Sử dụng chữ số thập phân là một ý tưởng hay giúp dễ hiểu hơn, nhưng đoạn cuối hơi sai lệch: thực tế bạn có thể biểu thị các số cao hơn 999 và ví dụ của bạn cho thấy: 12300 sẽ là 1,23 x 10 <sup> 4 <sup >. Ý bạn là bắt đầu từ con số đó có những khoảng trống. Bạn có phiền khi đọc lại nó một chút không?
Fabio nói Phục hồi Monica
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.