Ketika konversi dari Integer ke Single dapat kehilangan presisi

27

Saya sedang membaca artikel dari Microsoft tentang Pelebaran Konversi dan Opsi Ketat Aktif ketika saya sampai di bagian tersebut

Konversi berikut mungkin kehilangan presisi:

  • Integer ke Tunggal
  • Panjang ke Tunggal atau Ganda
  • Desimal ke Satu atau Ganda

Namun, konversi ini tidak kehilangan informasi atau besarnya.

.. tetapi menurut artikel lain mengenai tipe data ,

  • Tipe integer dapat menyimpan dari -2.147.483.648 hingga 2.147.483.647 dan

  • Jenis tunggal dapat menyimpan dari

    • 1,401298E-45 hingga 3,4028235E + 38 untuk angka positif,
    • dan -3,4028235E + 38 hingga - 1,401298E-45 untuk angka negatif

.. jadi Single dapat menyimpan lebih banyak angka daripada Integer. Saya tidak dapat memahami dalam situasi apa konversi seperti itu dari Integer ke Single dapat kehilangan presisi. Bisakah seseorang menjelaskannya?

Vinicius V
sumber

Jawaban:

87

Single dapat menyimpan angka lebih banyak daripada Integer

Tidak, tidak bisa. Keduanya Singledan Integer32 Bit, yang berarti keduanya dapat menyimpan jumlah angka yang sama persis , yaitu 2 32 = 4294967296 angka yang berbeda.

Karena rentang dari Singlejelas lebih besar dari itu, itu adalah segera jelas (karena Prinsip Pigeonhole ) bahwa itu tidak mungkin mewakili semua nomor dalam kisaran tersebut.

Dan karena rentang Integerpersis ukuran yang sama dengan jumlah maksimum angka yang dapat mewakili Integerdan sekaligus Single, tetapi Singlejuga dapat mewakili angka di luar rentang itu, jelas bahwa itu tidak mungkin mewakili semua angka di dalam rentang Integer.

Jika ada beberapa angka Integeryang tidak dapat direpresentasikan Single, konversi dari Integermenjadi Single harus mampu kehilangan informasi.

Jörg W Mittag
sumber
3
Beri +1 untuk penjelasan hebat mengapa itu harus terjadi, meskipun pertanyaan sebenarnya adalah kapan ("dalam situasi apa") itu terjadi ...
gandakan Anda
21
@doubleYou: 4261412864 dari 4294967296 Integers (99,2%) tidak dapat direpresentasikan sebagai Single, jadi "ketika" adalah "hampir selalu".
Jörg W Mittag
2
Jika Anda ingin lebih tepat, Singlehanya dapat mewakili 4.278.190.079 angka berbeda. Sebuah Singlenilai mewakili nomor jika dan hanya jika eksponen disimpan tidak 255, yang berarti bahwa ada 255 * 2 ^ 24 Singles yang mewakili angka. Dari ini, dua dari mereka mewakili angka yang sama (yaitu, nol), dan yang lainnya semuanya mewakili angka yang berbeda.
Tanner Swett
10
en.wikipedia.org/wiki/Single-precision_floating-point_format menjelaskan batasan dengan baik untuk IEEE754 binary32. Integer dalam [-16777216,16777216](2 ^ 24 = lebar signifikan dan) dapat direpresentasikan dengan tepat. Angka yang lebih besar dibulatkan ke kelipatan terdekat 2, 4, 8, ... tergantung pada seberapa besar mereka.
Peter Cordes
14
“Yang berarti keduanya dapat menyimpan jumlah angka yang persis sama” - Itu tidak berarti itu. Itu hanya berarti bahwa jika kedua jenis memiliki jumlah cara penyimpanan yang sama persis. Dan ini bukan masalahnya; misalnya, Singlememiliki dua cara menyimpan nol. Jadi Singlesebenarnya bisa mewakili angka yang berbeda lebih sedikit daripada Integer.
Konrad Rudolph
28

Tipe floating point (seperti Single dan Double) diwakili dalam memori oleh tanda, mantissa dan eksponen. Anggap saja sebagai notasi ilmiah:

Sign*Mantissa*Base^Exponent

Mereka - seperti yang Anda duga - menggunakan basis 2. Ada tweak lain yang memungkinkan untuk merepresentasikan infinity dan NaN, dan eksponen diimbangi (akan kembali ke sana), dan sebuah singkatan untuk mantissa (akan kembali ke sana juga) . Cari IEEE 754 standar yang mencakup perwakilan dan operasinya untuk detail lebih lanjut.

Untuk keperluan kita, kita dapat membayangkannya sebagai angka biner "mantissa", dan "eksponen" yang memberi tahu Anda di mana harus meletakkan pemisah desimal.


Dalam kasus Single, kita memiliki 1 bit untuk dia tanda tangani, 8 untuk eksponen dan 23 untuk mantissa.

Sekarang, masalahnya, kita akan menyimpan mantissa dari angka paling signifikan. Ingatlah bahwa semua nol di sebelah kiri tidak relevan. Dan memberi bahwa kita bekerja dalam biner, kita tahu bahwa digit paling signifikan adalah 1 ※. Yah, karena kita tahu itu, kita tidak harus menyimpannya. Berkat steno itu, jangkauan efektif mantra adalah 24 bit.

※: Kecuali jika nomor yang kita simpan adalah nol. Untuk itu kita akan mengatur semua bit ke nol. Namun, jika kita mencoba menafsirkan bahwa di bawah deskripsi yang saya berikan, Anda akan memiliki 2 ^ 24 (yang implisit 1) dikalikan dengan 1 (2 pangkat eksponen 0). Jadi, untuk memperbaikinya, nol eksponen adalah nilai khusus. Ada juga nilai-nilai khusus untuk menyimpan infinity dan NaN dalam eksponen.

Sesuai offset eksponen - selain menghindari nilai-nilai khusus - memiliki offset itu memungkinkan untuk menempatkan titik desimal sebelum dimulainya mantissa atau setelah akhirnya, tanpa perlu memiliki tanda untuk eksponen.


Ini berarti bahwa untuk jumlah besar, tipe floating point akan menempatkan titik desimal di luar akhir mantissa.

Ingat bahwa mantissa adalah angka 24 bit. Itu tidak akan pernah mewakili nomor 25 bit ... tidak memiliki bit ekstra itu. Dengan demikian, tunggal tidak dapat membedakan antara 2 ^ 24 dan 2 ^ 24 + 1 (ini adalah angka bit 25 pertama, dan mereka berbeda pada bit terakhir, yang tidak terwakili dalam single).

Jadi, untuk bilangan bulat kisaran tunggal adalah -2 ^ 24 hingga 2 ^ 24. Dan mencoba menambahkan 1 ke 2 ^ 24 akan menghasilkan 2 ^ 24 (karena sejauh menyangkut jenisnya, 2 ^ 24 dan 2 ^ 24 + 1 adalah nilai yang sama). Cobalah secara Online . Inilah sebabnya mengapa ada kehilangan informasi ketika mengkonversi dari integer ke single. Dan ini juga mengapa loop yang menggunakan satu atau ganda sebenarnya bisa menjadi loop tanpa batas tanpa Anda sadari.

Theraot
sumber
Ini bukan penjelasan sempurna tentang 1bit terkemuka implisit dalam signifikansi. Ini tersirat oleh bidang bias-eksponen menjadi nol . Subnormal (alias denormals) termasuk+-0.0 memiliki 0sedikit terkemuka signifikansinya. Saya kira Anda dapat menyederhanakan untuk hanya mempertimbangkan 0.0kasus yang benar-benar istimewa, tetapi 0.0sebenarnya mengikuti aturan penyandian yang sama seperti subnormal lainnya.
Peter Cordes
25

Berikut ini adalah contoh aktual saat mengkonversi dari Integermenjadi Singlemungkin kehilangan presisi:

The Singlejenis dapat menyimpan semua bilangan bulat dari -16777216 ke 16777216 (inklusif), tetapi tidak dapat menyimpan semua bilangan bulat di luar kisaran ini. Sebagai contoh, tidak dapat menyimpan jumlah 16777217. Untuk itu, tidak dapat menyimpan setiap nomor lebih besar yang aneh dari 16.777.216.

Kita dapat menggunakan Windows PowerShell untuk melihat apa yang terjadi jika kita mengonversikan Integerke Singledan kembali:

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

Perhatikan bahwa 16777217 dibulatkan ke 16777216, dan 16777219 dibulatkan ke 16777220.

Tanner Swett
sumber
4
Dan dengan semakin besarnya, jarak antara perwakilan terdekat floatterus tumbuh sebagai kekuatan. en.wikipedia.org/wiki/…
Peter Cordes
12

Jenis titik apung mirip dengan "notasi ilmiah" dalam fisika. Angka tersebut dibagi menjadi bit tanda, eksponen (pengali) dan mantissa (angka signifikan). Jadi karena besarnya nilai meningkat ukuran langkah juga meningkat.

Floating point presisi tunggal memiliki 23 bit mantissa, tetapi ada "implisit 1", sehingga mantissa efektif 24 bit. Oleh karena itu semua bilangan bulat dengan magnitudo hingga 24 dapat diwakili secara tepat dalam floating point presisi tunggal.

Di atas angka yang lebih sedikit berturut-turut dapat diwakili.

  • Dari 2 24 hingga 2 25 hanya angka genap yang dapat diwakili.
  • Dari 2 25 hingga 2 26 hanya kelipatan 4 yang dapat diwakili.
  • Dari 2 26 hingga 2 27 hanya kelipatan 8 yang dapat diwakili.
  • Dari 2 27 hingga 2 28 hanya kelipatan 16 yang dapat diwakili
  • Dari 2 28 hingga 2 29 hanya kelipatan 32 yang dapat diwakili
  • Dari 2 29 hingga 2 30 hanya kelipatan 64 yang dapat diwakili
  • Dari 2 30 hingga 2 31 hanya kelipatan 128 yang dapat diwakili

Jadi dari 2 32 kemungkinan nilai integer bertanda 32 bit hanya 2 * (2 24 + 7 * 2 23 ) = 9 * 2 24 dapat direpresentasikan dalam floating point presisi tunggal. Itu adalah 3,515625% dari total.

Peter Green
sumber
8

Pelampung presisi tunggal memiliki 24 bit presisi. Apa pun yang dibulatkan ke angka 24-bit terdekat. Mungkin lebih mudah dipahami dalam notasi ilmiah desimal, tetapi perlu diingat float aktual menggunakan biner.

Katakanlah Anda memiliki 5 digit desimal memori. Anda dapat memilih untuk menggunakan yang seperti int unsigned biasa, memungkinkan Anda untuk memiliki angka antara 0 dan 99999. Jika Anda ingin dapat mewakili angka yang lebih besar, Anda dapat menggunakan notasi ilmiah dan hanya mengalokasikan dua digit sebagai eksponen, jadi Anda sekarang dapat mewakili apa pun antara 0 dan 9,99 x 10 99 .

Namun, angka terbesar yang Anda dapat wakili dengan tepat sekarang hanya 999. Jika Anda mencoba mewakili 12345, Anda bisa mendapatkan 1,23 x 10 4 , atau 1,24 x 10 4 , tetapi Anda tidak dapat mewakili angka apa pun di antaranya, karena Anda tidak memiliki cukup angka.

Karl Bielefeldt
sumber
3
Menggunakan angka desimal adalah ide bagus yang membuatnya lebih mudah dipahami, tetapi paragraf terakhir agak menyesatkan: sebenarnya Anda dapat mewakili angka yang lebih tinggi dari 999, dan contoh Anda menunjukkannya: 12300 akan menjadi 1,23 x 10 <sup> 4 <sup >. Maksud Anda adalah bahwa mulai dari angka itu ada kesenjangan. Maukah Anda mengulanginya sedikit?
Fabio mengatakan Reinstate Monica