C#
memiliki decimal
tipe yang digunakan untuk angka-angka yang membutuhkan representasi tepat dalam basis 10. Misalnya, 0.1
tidak dapat direpresentasikan dalam basis 2 (misalnya float
dan double
) dan akan selalu menjadi perkiraan ketika disimpan dalam variabel yang merupakan tipe ini.
Saya bertanya-tanya apakah fakta yang terbalik juga mungkin terjadi. Apakah ada angka yang tidak dapat diwakili dalam basis 10 tetapi dapat diwakili dalam basis 2 (dalam hal ini saya ingin menggunakan float
bukan decimal
untuk menangani mereka)?
c#
numbers
floating-point
Maks
sumber
sumber
0.11_b2
, tuliskan sebagai0.5 + 0.5 * 0.5
. Apakah ada langkah yang mungkin gagal atau menghasilkan desimal berulang? Secara pribadi, saya menemukan bahwa latihan ini melakukan pekerjaan yang baik untuk menemukan intuisi tentang angka-angka dasar 2. Saya kira seseorang bisa melangkah lebih jauh dan mengubah latihan ini menjadi bukti dengan konstruksi.0.0999999....998..
tepat, tetapi bukan angka penuh0.1
- perkiraan seperti pembulatan ke hundreth terdekat dengan0.100
adalah masalah implementasi yang melibatkan tidak menunjukkan semua digit dan membulatkannya.Jawaban:
Inilah kunci untuk kesulitan Anda:
10
adalah produk dari2
dan5
. Anda dapat mewakili angka apa pun persis di basis 10 desimal yaitu k * 1/2 n * 1/5 m di manak
,n
danm
bilangan bulat.Alternatif lain - jika angka
n
dalam 1 / n berisi faktor yang bukan bagian dari faktor basis, angka tersebut tidak akan dapat direpresentasikan secara tepat dalam jumlah digit tetap dalam biner / desimal / ekspansi apa pun dari itu nomor - itu akan memiliki bagian yang berulang. Misalnya 1/15 = 0,0666666666 .... karena 3 (15 = 3 * 5) bukan merupakan faktor 10.Dengan demikian, apa pun yang dapat direpresentasikan dalam basis 2 dengan tepat (k * 1/2 n ) dapat direpresentasikan dalam basis 10 dengan tepat.
Di luar itu, ada masalah tentang berapa digit / bit yang Anda gunakan untuk mewakili angka. Ada beberapa angka yang dapat direpresentasikan dengan tepat di beberapa basis, tetapi dibutuhkan lebih dari beberapa angka / bit untuk melakukannya.
Dalam biner, angka 1/10 yang dengan mudah 0,1 dalam desimal tidak dapat direpresentasikan sebagai angka yang dapat direpresentasikan dalam jumlah bit tetap dalam biner. Sebaliknya, angkanya adalah 0,00011001100110011 ... 2 (dengan bagian 0011 berulang selamanya).
Mari lihat nomor 1 2 /1010 2 sedikit lebih dekat.
Ini adalah jenis yang persis sama dengan yang Anda dapatkan ketika Anda mencoba melakukan pembagian panjang untuk 1/3.
1/10, ketika diperhitungkan adalah 1 / (2 1 * 5 1 ). Untuk basis 10 (atau kelipatan 10), angka ini berakhir dan dikenal sebagai angka biasa . Ekspansi desimal yang berulang dikenal sebagai desimal berulang , dan angka-angka yang berlangsung selamanya tanpa berulang adalah angka yang tidak rasional.
The matematika di balik ini menggali teorema kecil Fermat ... dan setelah Anda mulai mengatakan Fermat atau teorema, itu menjadi pertanyaan Math.SE .
Jawabannya adalah tidak'.
Jadi, pada titik ini kita semua harus jelas bahwa setiap ekspansi biner panjang tetap dari bilangan rasional dapat direpresentasikan sebagai ekspansi desimal panjang tetap.
Mari kita melihat lebih dekat pada desimal dalam C # yang membawa kita ke desimal floating point di .NET dan memberi penulis, saya akan menerima bahwa itulah cara kerjanya.
Saya akan segera menunjukkan bahwa karena implementasi ini ada angka dalam
double
jenis yang tidak dapat diwakilidecimal
- mereka yang berada di luar jangkauan.Double.Epsilon
adalah4.94065645841247e-324
yang tidak dapat direpresentasikan dalamdecimal
, tetapi dapat dalamdouble
.Namun, dalam rentang yang dapat mewakili desimal, ia memiliki lebih banyak bit presisi daripada jenis asli lainnya dan dapat mewakili mereka tanpa kesalahan.
Ada beberapa jenis lain yang beredar. Ada BigInteger di C # yang dapat mewakili integer besar yang sewenang-wenang. Tidak ada yang setara dengan BigDecimal Java (yang dapat mewakili angka dengan angka desimal hingga 2 32 digit - yang merupakan rentang yang cukup besar) tepatnya . Namun, jika Anda melihat sedikit, Anda bisa menemukan implementasi linting tangan.
Ada beberapa bahasa yang juga memiliki tipe data rasional yang memungkinkan Anda untuk secara tepat mewakili rasional (sehingga 1/3 sebenarnya 1/3).
Khusus untuk C # dan pilihan float atau rasional, saya akan tunduk kepada Jon Skeet dari desimal floating pint di .NET :
sumber
n = 15
danb = 10
tidak relatif prima ("berbagi tidak ada faktor positif umum (pembagi) kecuali 1") karena mereka berbagi 5 sebagai faktor. Kuncinya adalah bahwa tidak semua faktor 15 (5 dan 3) juga bukan faktor 10. (Selain itu: apakah ada kata untuk menunjukkan angka yang memiliki atau tidak berbagi semua faktor umum?) Saya pikir itu rapi terbungkus dalamk, n, m
persamaan Anda , tetapi untuk benar-benar membungkus kepala saya di sekitarnya, saya perlu melihat plot 3d. Apapun, +1 layak untuk Anda.Setelah Anda keluar dari rentang nilai yang dapat diterima, jawabannya adalah ya. Yang mengatakan, hampir semua yang ada dalam jangkauan akan memiliki representasi. C # Referensi desimal Meskipun tidak dinyatakan dalam spesifikasi, bilangan irasional tidak dapat direpresentasikan secara tepat (misalnya, e 1 , pi, akar kuadrat 2, dll.).
1 Terima kasih kepada MichaelT karena telah mengingatkan saya pada nomor irasional lainnya.
sumber
e
(2,71 ...). Log natural - ln (x) adalah log base e. Dengan demikian, basis irasional memang ada dan bermanfaat. Kegunaan khusus dari pi dasar, saya tidak yakin - tetapi itu tidak berarti tidak digunakan di suatu tempat.Tipe floating-point basis-dua akan dapat secara tepat mewakili banyak nilai yang tidak bisa dimiliki oleh tipe-basis-sepuluh dengan ukuran yang sama . Nilai apa pun yang secara tepat dapat diwakili oleh tipe basis-2 dari beberapa ukuran akan persis mewakili dalam tipe basis-sepuluh dengan ukuran yang cukup. Ukuran yang diperlukan untuk tipe sepuluh basis-murni untuk mewakili semua nilai angka titik-mengambang biner akan tergantung pada kisaran eksponen dari tipe biner; ratusan bit untuk a
float
, atau ribuan untuk adouble
.Yang telah dikatakan,
Decimal
tipe ini cukup besar sehingga memungkinkan untuk digunakan sebagai tipe "universal" yang mampu menahan nilai primitif numerik lainnya dan menyediakan beberapa fitur tambahan lainnya selain (jika tidak ada yang lain, gunakan satu bit untuk menunjukkan apakah nilai yang disimpan adalah hasil dari konversi adouble
, dan jika bit itu disetel, gunakan 64 bit untuk menyimpan nilai yang dipermasalahkan). Microsoft memilih untuk tidak melakukan itu. Akibatnya, konversi adouble
keDecimal
gagal total untuk nilai besar, akan menyebabkan nilai kecil dibulatkan ke 1E-28 terdekat. Selanjutnya, bahkan dalam rentang dinamisdecimal
, metode konversi tidak akan "pulang pergi". Misalnya, mengevaluasi 1.0 / 3.0 sebagai gandakan akan menghasilkan 0.3333333333333333148, tetapi mengonversinya menjadi desimal akan menghasilkan 0.333333333333333m dan mengonversi itu kembali menjadi gandakan akan menghasilkan 0.3333333333333329818.sumber