การแปลงแปลก ๆ สองเท่าเป็น int

ฉันเพิ่งพบปัญหาเล็ก ๆ ใน iOS Swift เมื่อแปลง Double เป็น Int

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

ที่นั่นฉันกำลังคูณ 10.2 ด้วย 100 และไม่ได้รับค่าที่คาดหวัง (1,020) และแทนที่จะเป็น 1,019...

แต่ใช้งานได้ถูกต้องในกรณีส่วนใหญ่ดังนี้

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

ฉันยังทดสอบเพิ่มเติมด้วย Java และปัญหาเดียวกันที่นั่นเช่นกัน ..

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

ฉันสามารถแก้ไขปัญหาได้โดยดำเนินการ 'ปัดเศษ' ก่อนแปลงเป็น Int ดังนี้...

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

แต่นี่เข้าเรื่องที่ผมไม่อยากได้ถ้าค่ามีทศนิยม 3 ตำแหน่งดังนี้ เพราะ ณ เวลานั้นปัดเศษ (10.206 ---> 1021)


person JibW    schedule 25.08.2015    source แหล่งที่มา
comment
ประการแรก ค่าที่แสดงเป็นเพียงค่าที่ไม่ใช่ค่าทั้งหมด ใช้การจัดรูปแบบเพื่อดูตัวเลขเพิ่มเติม ประการที่สอง 10.2 หรือ 10.3 ไม่สามารถแสดงเป็นเลขทศนิยมฐาน 2 ได้อย่างแน่นอน ดังนั้นผลลัพธ์จึงอาจแตกต่างไปจากที่คาดไว้เล็กน้อย ประการที่สาม อาจช่วยได้หากคุณใช้เวลาเรียนรู้เกี่ยวกับตัวเลขทศนิยม   -  person zaph    schedule 25.08.2015
comment
เกี่ยวข้องอย่างยิ่ง: คณิตศาสตร์จุดลอยตัวใช้งานไม่ได้หรือไม่   -  person Martin R    schedule 25.08.2015


คำตอบ (4)


ค่าที่แสดงเป็นเพียงค่าที่ไม่ใช่ค่าทั้งหมด ใช้การจัดรูปแบบเพื่อดูตัวเลขเพิ่มเติม 10.2 หรือ 10.3 ไม่สามารถแสดงเป็นเลขทศนิยมฐาน 2 ได้อย่างแน่นอน ดังนั้นผลลัพธ์จึงอาจแตกต่างไปจากที่คาดไว้เล็กน้อย

นี่คือตัวอย่างที่แสดงให้เห็นว่าเกิดอะไรขึ้น:

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

โปรดทราบว่า 10.2 แปลงเป็นจุดลอยตัวสองเท่าเป็น ต่ำกว่า 10.2 เล็กน้อย และค่าจะถูกตัดทอนลง

โปรดทราบว่า 10.3 แปลงเป็นจุดลอยตัวเป็นสองเท่าเป็น เหนือ 10.3 เล็กน้อย และค่า ไม่ จะถูกตัดทอนลง

หากจำเป็นต้องใช้การคำนวณทศนิยมที่แน่นอน เช่น ในเครื่องคิดเลขหรือเมื่อต้องจัดการกับเงิน ให้ใช้ NSDecimalNumber

person zaph    schedule 25.08.2015

นี่เป็นผลลัพธ์ของ ข้อผิดพลาดในการปัดเศษ/การตัดทอน จริงๆ แล้ว,

  myDoubleValue = 10.2 

เป็นสิ่งที่ต้องการ

  myDoubleValue = 10.1999999999999

so

 myDoubleValue * 100 = 1019.999999999

และหลังจาก ตัด เป็น int คุณจะได้ 1019 แนวทางปฏิบัติที่ดีกว่าคือ ปัดเศษขึ้น แทนที่จะ ตัดแต่ง:

 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

คำตอบของจาวา

เนื่องจากประเภท double และ float และ wrappers ไม่รับประกันค่าที่แม่นยำเมื่อดำเนินการ

ใน Java สำนวนที่แนะนำสำหรับสิ่งที่คุณกำลังมองหาคือ:

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

เอาต์พุต

1020
person Mena    schedule 25.08.2015
comment
ใน Swift และ Objective-C มีคลาส NSDecimalNumber ที่จัดการเลขทศนิยมทุกประการ - person zaph; 25.08.2015
comment
@zaph ขอบคุณสำหรับความคิดเห็น ฉันแทบไม่รู้อะไรเลยเกี่ยวกับ Objective-C / Swift ดังนั้นฉันจึงไม่สามารถตอบในส่วนนั้นได้ :) - person Mena; 25.08.2015

ดูเหมือนว่าคุณต้องการปัดเศษข้อผิดพลาดจำนวนเล็กน้อย แต่คุณต้องการปัดเศษอย่างอื่นลง

คุณสามารถทำเช่นนี้ได้

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