ฉันกำลังเขียนรหัสนี้:
public static void main(String[] args) {
double g = 1 / 3;
System.out.printf("%.2f", g);
}
ผลลัพธ์คือ 0 เหตุใดจึงเป็นเช่นนี้และฉันจะแก้ปัญหานี้ได้อย่างไร
ฉันกำลังเขียนรหัสนี้:
public static void main(String[] args) {
double g = 1 / 3;
System.out.printf("%.2f", g);
}
ผลลัพธ์คือ 0 เหตุใดจึงเป็นเช่นนี้และฉันจะแก้ปัญหานี้ได้อย่างไร
คำตอบ:
ตัวถูกดำเนินการสองตัว (1 และ 3) เป็นจำนวนเต็มดังนั้นจึงใช้เลขคณิตจำนวนเต็ม (หารที่นี่) ประกาศตัวแปรผลเป็นเพียงแค่ดับเบิลทำให้เกิดการแปลงโดยปริยายที่จะเกิดขึ้นหลังจากการแบ่ง
การหารจำนวนเต็มของหลักสูตรจะส่งกลับผลลัพธ์ที่แท้จริงของการหารที่ปัดเศษเป็นศูนย์ ผลลัพธ์ของ0.333...
จึงถูกปัดลงเป็น 0 ที่นี่ (โปรดทราบว่าโปรเซสเซอร์ไม่ได้ทำการปัดเศษใด ๆ แต่คุณสามารถคิดแบบนั้นได้)
นอกจากนี้โปรดทราบว่าถ้าตัวถูกดำเนินการ (ตัวเลข) ทั้งสองถูกกำหนดให้เป็นลอย 3.0 และ 1.0 หรือแม้แต่เลขคณิตจุดลอยตัวแรกก็ถูกใช้เพื่อให้คุณ0.333...
ได้
DOWN
เป็นศูนย์ การปัดเศษFLOOR
เป็นไปทางลบอินฟินิตี้
1/3
ใช้การหารจำนวนเต็มเนื่องจากทั้งสองด้านเป็นจำนวนเต็ม
คุณจำเป็นต้องมีอย่างน้อยหนึ่งของพวกเขาจะเป็นหรือfloat
double
หากคุณกำลังป้อนค่าในรหัสที่มาเช่นคำถามของคุณคุณสามารถทำ1.0/3
; 1.0
เป็นคู่
หากคุณได้รับค่าจากที่อื่นคุณสามารถใช้(double)
เพื่อเปลี่ยนint
เป็นไฟล์double
.
int x = ...;
int y = ...;
double value = ((double) x) / y;
แสดงเป็นไฟล์ double
double g = 1.0/3.0
สิ่งนี้เกิดขึ้นเนื่องจาก Java ใช้การดำเนินการหารจำนวนเต็มสำหรับ1
และ3
เนื่องจากคุณป้อนเป็นค่าคงที่จำนวนเต็ม
คุณควรใช้
double g=1.0/3;
หรือ
double g=1/3.0;
การหารจำนวนเต็มจะส่งกลับจำนวนเต็ม
เนื่องจากคุณกำลังทำการหารจำนวนเต็ม
ดังที่ @Noldorin กล่าวว่าถ้าตัวดำเนินการทั้งสองเป็นจำนวนเต็มระบบจะใช้การหารจำนวนเต็ม
ผลลัพธ์ 0.33333333 ไม่สามารถแสดงเป็นจำนวนเต็มได้ดังนั้นจึงกำหนดเฉพาะส่วนจำนวนเต็ม (0) ให้กับผลลัพธ์
ถ้าตัวดำเนินการตัวใดตัวหนึ่งเป็นdouble
/ float
เลขคณิตทศนิยมจะเกิดขึ้น แต่คุณจะมีปัญหาเดียวกันหากคุณทำเช่นนั้น:
int n = 1.0 / 3.0;
เนื่องจากถือว่า 1 และ 3 เป็นจำนวนเต็มดังนั้นจึงปัดเศษผลลัพธ์ให้เป็น 0 เพื่อให้เป็นจำนวนเต็ม
เพื่อให้ได้ผลลัพธ์ที่คุณต้องการให้บอก java อย่างชัดเจนว่าตัวเลขเป็นสองเท่าดังนี้:
double g = 1.0/3.0;
ทำให้ 1 เป็นลอยและหารลอยจะถูกนำมาใช้
public static void main(String d[]){
double g=1f/3;
System.out.printf("%.2f",g);
}
การแปลงใน JAVA นั้นค่อนข้างง่าย แต่ต้องมีความเข้าใจ ตามที่อธิบายไว้ใน JLS สำหรับการดำเนินการจำนวนเต็ม :
หากตัวดำเนินการจำนวนเต็มนอกเหนือจากตัวดำเนินการ shift มีตัวถูกดำเนินการประเภทยาวอย่างน้อยหนึ่งตัวการดำเนินการจะดำเนินการโดยใช้ความแม่นยำ 64 บิตและผลลัพธ์ของตัวดำเนินการตัวเลขเป็นประเภทที่ยาว หากตัวถูกดำเนินการอื่นไม่ยาวตัวดำเนินการจะถูกขยายก่อน (§5.1.5) เพื่อพิมพ์แบบยาวตามการเลื่อนตำแหน่งตัวเลข (§5.6)
และตัวอย่างเป็นวิธีที่ดีที่สุดในการแปล JLS เสมอ;)
int + long -> long
int(1) + long(2) + int(3) -> long(1+2) + long(3)
มิฉะนั้นการดำเนินการจะดำเนินการโดยใช้ความแม่นยำ 32 บิตและผลลัพธ์ของตัวดำเนินการตัวเลขเป็นประเภท int หากโอเปอแรนด์ตัวใดตัวหนึ่งไม่ใช่ int จะถูกขยายให้กว้างขึ้นก่อนเพื่อพิมพ์ int ตามการเลื่อนตำแหน่งตัวเลข
short + int -> int + int -> int
ตัวอย่างเล็ก ๆ ที่ใช้ Eclipse เพื่อแสดงให้เห็นว่าแม้แต่การเพิ่มสองshort
วินาทีก็ไม่ง่ายอย่างนั้น:
short s = 1;
s = s + s; <- Compiling error
//possible loss of precision
// required: short
// found: int
สิ่งนี้จะต้องใช้การหล่อโดยสูญเสียความแม่นยำที่เป็นไปได้
เช่นเดียวกับตัวดำเนินการจุดลอยตัว
หากตัวถูกดำเนินการอย่างน้อยหนึ่งตัวดำเนินการกับตัวดำเนินการตัวเลขเป็นประเภท double การดำเนินการจะดำเนินการโดยใช้เลขคณิตทศนิยม 64 บิตและผลลัพธ์ของตัวดำเนินการตัวเลขเป็นค่าประเภท double ถ้าตัวถูกดำเนินการอีกตัวไม่ใช่ double จะถูกขยายก่อน (§5.1.5) เพื่อพิมพ์ double by numeric promotion (§5.6)
ดังนั้นการส่งเสริมการขายจะทำในการลอยเป็นสองเท่า
และการผสมของทั้งจำนวนเต็มและค่าลอยทำให้เกิดค่าลอยตามที่กล่าว
หากตัวถูกดำเนินการอย่างน้อยหนึ่งตัวดำเนินการกับตัวดำเนินการไบนารีเป็นประเภทจุดลอยตัวการดำเนินการนั้นจะเป็นการดำเนินการแบบทศนิยมแม้ว่าอีกตัวจะเป็นอินทิกรัล
สิ่งนี้เป็นจริงสำหรับตัวดำเนินการไบนารี แต่ไม่ใช่สำหรับ "ตัวดำเนินการมอบหมาย" เช่น +=
ตัวอย่างการทำงานง่ายๆก็เพียงพอที่จะพิสูจน์สิ่งนี้
int i = 1;
i += 1.5f;
เหตุผลก็คือมีการโยนโดยปริยายที่นี่ซึ่งจะถูกดำเนินการเช่น
i = (int) i + 1.5f
i = (int) 2.5f
i = 2
1 และ 3 เป็นจำนวนเต็ม contants และ Java ไม่ส่วนจำนวนเต็มซึ่งเป็นผลเป็น 0 หากคุณต้องการที่จะเขียนค่าคงที่คู่คุณต้องเขียนและ1.0
3.0
วิธีแก้ที่ง่ายที่สุดก็แค่ทำสิ่งนี้
double g = ((double) 1 / 3);
สิ่งนี้ทำอย่างไรเนื่องจากคุณไม่ได้ป้อน 1.0 / 3.0 ช่วยให้คุณสามารถแปลงเป็นชนิดข้อมูลสองเท่าด้วยตนเองเนื่องจาก Java ถือว่าเป็นการหารจำนวนเต็มและจะทำได้แม้ว่าจะหมายถึงการ จำกัด การแปลงให้แคบลงก็ตาม นี่คือสิ่งที่เรียกว่าตัวดำเนินการโยน
ฉันทำอย่างนี้.
double g = 1.0/3.0;
System.out.printf("%gf", g);
ใช้. 0 ขณะทำการคำนวณสองครั้งมิฉะนั้น Java จะถือว่าคุณใช้จำนวนเต็ม หากการคำนวณใช้จำนวนค่าสองค่าผลลัพธ์จะเป็นค่าสองเท่า หากเป็นจำนวนเต็มทั้งหมดผลลัพธ์จะเป็นจำนวนเต็ม
(1/3) หมายถึงการหารจำนวนเต็มนั่นคือสาเหตุที่คุณไม่สามารถรับค่าทศนิยมจากการหารนี้ได้ ในการแก้ปัญหานี้ให้ใช้:
public static void main(String[] args) {
double g = 1.0 / 3;
System.out.printf("%.2f", g);
}
public static void main(String[] args) {
double g = 1 / 3;
System.out.printf("%.2f", g);
}
เนื่องจากทั้ง 1 และ 3 เป็น ints ผลลัพธ์จึงไม่ถูกปัดเศษ แต่จะถูกตัดทอน คุณจึงไม่สนใจเศษส่วนและใช้เฉพาะ wholes
เพื่อหลีกเลี่ยงปัญหานี้ให้มีอย่างน้อยหนึ่งในตัวเลข 1 หรือ 3 ของคุณเป็นรูปแบบทศนิยม 1.0 และ / หรือ 3.0
ลองสิ่งนี้:
public static void main(String[] args) {
double a = 1.0;
double b = 3.0;
double g = a / b;
System.out.printf(""+ g);
}
ทำ "double g = 1.0 / 3.0;" แทน.
อีกหลายคนไม่สามารถชี้ให้เห็นปัญหาที่แท้จริง:
การดำเนินการกับจำนวนเต็มเท่านั้นที่จะโยนผลลัพธ์ของการดำเนินการเป็นจำนวนเต็ม
หมายความว่าผลลัพธ์ทศนิยมที่สามารถแสดงเป็นจำนวนเต็มจะถูกตัดทอน (ตัดส่วนทศนิยมออก)
คุณถามอะไรการหล่อ (การพิมพ์ / การแปลงประเภท)?
มันแตกต่างกันไปตามการนำภาษาไปใช้ แต่ Wikipedia มีมุมมองที่ค่อนข้างครอบคลุมและพูดถึงการบีบบังคับด้วยเช่นกันซึ่งเป็นข้อมูลสำคัญในการตอบคำถามของคุณ
1/2
ไม่ใช่ในภาษาเป้าหมาย (java) คุณเพียงแค่เรียกใช้การหารจำนวนเต็มซึ่งจะทำให้ได้ผลลัพธ์เป็นจำนวนเต็ม การแคสต์ประเภทเป็นเพียงเพราะการแปลงขึ้นจากint
ไปเป็นdouble
ระหว่างการมอบหมายงาน
0.5
. เพียงแค่ใน Java 1/2
คือการหารจำนวนเต็มซึ่งทำให้เกิดจำนวนเต็มศูนย์ คุณสามารถกำหนดศูนย์ให้เป็นสองเท่าได้ แต่จะยังคงเป็นศูนย์แม้ว่าจะเป็น0.0
สองเท่า
int i = .99999999
ตั้งค่า int เป็น 0 โดยเฉพาะอย่างยิ่งมันใช้ส่วนจำนวนเต็มและทิ้งส่วนที่เหลือ