Konversi Aneh ganda menjadi int

Saya baru-baru ini mengalami masalah kecil di ios Swift saat mengonversi Double ke Int.

var myDoubleValue: Double = 10.2
var newInt = Int(myDoubleValue * 100) //1019

Di sana saya mengalikan 10,2 dengan 100 dan TIDAK mendapatkan nilai yang diharapkan (1020) dan malah 1019...

Namun berfungsi dengan benar di sebagian besar kasus sebagai berikut

var myDoubleValue: Double = 10.3
var newInt = Int(myDoubleValue * 100) //1030

Saya juga mengujinya lebih lanjut dengan Java dan masalah yang sama juga di sana..

double myDoubleValue = 10.2;
int myIntValue1 = (int)(myDoubleValue * 100); //1019

Saya dapat mengatasi masalah ini dengan melakukan 'putaran' sebelum mengonversi ke Int sebagai berikut...

var myDoubleValue: Double = 10.2
var newInt = Int(round(myDoubleValue * 100)) //1020

Tapi ini masuk ke hal yang tidak saya inginkan jika nilainya memiliki 3 desimal sebagai berikut, karena saat itu dibulatkan (10.206 ---> 1021)


person JibW    schedule 25.08.2015    source sumber
comment
Pertama, nilai yang ditampilkan hanya itu, bukan nilai keseluruhan, gunakan pemformatan untuk melihat lebih banyak digit. Kedua, 10.2 atau 10.3 tidak dapat direpresentasikan secara tepat dalam bilangan floating point basis2 sehingga hasilnya bisa sedikit berbeda dari yang diharapkan. Ketiga, mungkin membantu jika Anda meluangkan waktu untuk mempelajari bilangan floating point.   -  person zaph    schedule 25.08.2015
comment
Sangat terkait: Apakah matematika floating point rusak?   -  person Martin R    schedule 25.08.2015


Jawaban (4)


Nilai yang ditampilkan hanya itu, bukan nilai keseluruhan, gunakan pemformatan untuk melihat lebih banyak digit. 10.2 atau 10.3 tidak dapat direpresentasikan secara tepat dalam bilangan floating point basis2 sehingga hasilnya bisa sedikit berbeda dari yang diharapkan.

Berikut adalah contoh yang menunjukkan apa yang terjadi:

var myDoubleValue1: Double = 10.2
print(String(format: "myDoubleValue1: %.17f", myDoubleValue1))
// myDoubleValue1: 10.19999999999999929

var myDoubleValue2: Double = 10.3
print(String(format: "myDoubleValue2: %.17f", myDoubleValue2))
// myDoubleValue2: 10.30000000000000071

Perhatikan bahwa 10.2 dikonversi ke titik mengambang Gandakan sedikit di bawah 10.2 dan akan terpotong ke bawah.

Perhatikan bahwa 10.3 dikonversi ke titik mengambang Gandakan sedikit di atas 10.3 dan tidak akan terpotong.

Jika matematika desimal eksak, misalnya pada kalkulator atau saat menangani uang, diperlukan, gunakan NSDecimalNumber

person zaph    schedule 25.08.2015

Ini adalah hasil dari kesalahan pembulatan/pemotongan. Sebenarnya,

  myDoubleValue = 10.2 

adalah sesuatu seperti

  myDoubleValue = 10.1999999999999

so

 myDoubleValue * 100 = 1019.999999999

dan setelah dipangkas menjadi int Anda mendapatkan 1019. Praktik yang lebih baik adalah membulatkan daripada memangkas:

 double myDoubleValue = 10.2;
 int myIntValue1 = (int)(myDoubleValue * 100 + 0.5); // note "+ 0.5"
 System.out.println(myIntValue1);
person Dmitry Bychenko    schedule 25.08.2015

Jawaban Java

Hal ini karena tipe dan pembungkus double dan float tidak menjamin nilai yang tepat ketika dioperasikan.

Di Java, idiom yang direkomendasikan untuk apa yang Anda cari adalah:

BigDecimal myDoubleValue = new BigDecimal("10.2");
int myInt = myDoubleValue.multiply(new BigDecimal("100")).intValue();
System.out.println(myInt);

Keluaran

1020
person Mena    schedule 25.08.2015
comment
Di Swift dan Objective-C ada kelas NSDecimalNumber yang menangani angka desimal dengan tepat. - person zaph; 25.08.2015
comment
@zaph terima kasih atas komentarnya. Saya hampir tidak tahu apa-apa tentang Objective-C/Swift, jadi saya tidak bisa menjawab bagian itu :) - person Mena; 25.08.2015

Tampaknya Anda ingin mengumpulkan sejumlah kecil kesalahan tetapi Anda ingin membulatkan ke bawah.

Kamu bisa melakukan ini

double d = 10.199999;
long l = (long) (d * 100 + 0.01); // l = 10.20

double d = 10.206;
long l = (long) (d * 100 + 0.01); // l = 10.20
person Peter Lawrey    schedule 25.08.2015