เหตุใด Math.Floor (Double) จึงส่งคืนค่าประเภท Double


103

ฉันต้องการรับค่าจำนวนเต็มด้านซ้ายมือจากทศนิยมหรือสองเท่า สำหรับ Ex: ฉันต้องได้ค่า 4 จาก 4.6 ฉันลองใช้ฟังก์ชัน Math.Floor แต่มันส่งคืนค่าสองเท่าเช่น: มันกลับ 4.0 จาก 4.6 เอกสาร MSDN ระบุว่าส่งคืนค่าจำนวนเต็ม ฉันขาดอะไรที่นี่? หรือมีวิธีอื่นในการบรรลุสิ่งที่ฉันกำลังมองหา?


2
เอกสาร MSDN บอกว่าจะส่งกลับค่าจำนวนเต็ม เอกสาร MSDNระบุว่า Math.Floor ส่งคืน System.Double ไม่ใช่จำนวนเต็ม
บรอดแบนด์

จำเป็นต้องใช้ค่าจำนวนเต็มอย่างมีประสิทธิภาพ แต่ไม่ได้หมายความว่าสามารถจัดเก็บเป็น "int" หรือ "long" ได้ "double" เก็บค่าจำนวนเต็มทั้งหมดในช่วงที่กว้างกว่า "int" ได้สำเร็จโปรดทราบว่าค่าจำนวนเต็มบางค่าอาจถูกปัดเศษเมื่อส่วนแมนทิสซามีบิตไม่เพียงพอที่จะเก็บค่าจำนวนเต็มหลักทั้งหมดเมื่อเลขชี้กำลังฐาน 2 สูงกว่า 52: การปัดเศษของค่าจำนวนเต็มใน "double" นี้อาจเกิดขึ้นสำหรับจำนวนเต็มที่สูงกว่า 2 ^ 52 หรือต่ำกว่า -2 ^ 52 แต่ผลลัพธ์จะยังคงเป็นจำนวนเต็มที่ใกล้เคียงที่สุด หากคุณใช้ "(long) Floor (x)" การแปลงอาจผิดพลาดอย่างมาก
verdy_p

อย่างไรก็ตามโปรดทราบว่าช่วงที่ถูกต้องของค่าจำนวนเต็มซึ่งอาจแสดงเป็น "คู่" นั้นมีขนาดใหญ่มากโดยมีค่าสัมบูรณ์สูงถึง: (1 + (1 - 2 ^ −52)) × 2 ^ 1023 ≈ 1.7976931348623157E308; มันมากกว่า 2 ^ 63-1 ที่มี "long" มาก อย่างไรก็ตามช่วงของจำนวนเต็มที่สามารถจัดเก็บได้อย่างชัดเจนจะถูก จำกัด มากกว่าเนื่องจาก "double" มีเพียง 52 บิตสำหรับ mantissa (บวก 1 บิตโดยนัยสำหรับบิตที่สำคัญที่สุดไม่ได้จัดเก็บ) ซึ่งหมายความว่า "double" สามารถจัดเก็บได้เฉพาะ จำนวนเต็มเท่านั้นเมื่อค่าสัมบูรณ์ต่ำกว่า 2 ^ 53
verdy_p

น่าเสียดายที่ Math.Floor () ไม่ส่งคืนตัวแปรประเภท "Number" ภายในโดยใช้ "Long" ถ้าเป็นไปได้หรือ "Double" สำหรับจำนวนเต็มกลมขนาดใหญ่เท่านั้น และไลบรารีคณิตศาสตร์มาตรฐานไม่รองรับประเภทตัวเลขตัวแปรแบบรวมดังกล่าว มีไลบรารีทางคณิตศาสตร์อื่น ๆ ที่ใช้ประเภทตัวเลขรวมซึ่งรวมถึง Long, Double หรือจำนวนเต็มขนาดใหญ่ที่เข้ารหัสในทศนิยมหรือไบนารีแบบบรรจุโดยไม่สูญเสียช่วงหรือความแม่นยำที่รองรับ
verdy_p

คำตอบ:


146

ช่วงของdoubleมากกว้างกว่าช่วงของหรือint longพิจารณารหัสนี้:

double d = 100000000000000000000d;
long x = Math.Floor(d); // Invalid in reality

จำนวนเต็มอยู่นอกช่วงlong- แล้วจะเกิดอะไรขึ้น?

โดยปกติแล้วคุณรู้ไหมว่าค่าจะจริงจะอยู่ในช่วงของintหรือlongเพื่อให้คุณโยนมันทิ้ง:

double d = 1000.1234d;
int x = (int) Math.Floor(d);

แต่ความรับผิดชอบของนักแสดงนั้นอยู่ที่นักพัฒนาไม่ใช่Math.Floorตัวมันเอง มันจะมีข้อ จำกัด โดยไม่จำเป็นที่จะทำให้ล้มเหลวโดยมีข้อยกเว้นสำหรับค่าทั้งหมดที่อยู่นอกช่วงของlong.


2
Floor ส่งคืนการแทนค่าจำนวนเต็มของคู่และส่งกลับเป็นสองเท่าสำหรับการคำนวณทางวิทยาศาสตร์คำตอบนี้ไม่ถูกต้องเนื่องจาก double มี 64 บิตและยาวก็มี 64 บิต แต่ double ไม่สามารถเก็บตัวเลขที่แน่นอนของบิตที่มีนัยสำคัญต่ำกว่าแม้ว่าจะสามารถจัดเก็บได้อย่างถูกต้อง ในระยะยาว
Akash Kava

1
@ จอน: ทำไมคุณถึงไม่ได้ชั่งน้ำหนักในการอภิปรายที่โหมกระหน่ำว่าจะทำให้จำนวนบวกเป็นลบใน C # ได้อย่างไร: stackoverflow.com/questions/1348080/…
MusiGenesis

3
@ จอน: ใช้เวลาของคุณ ปรากฎว่าชุมชนค้นพบว่าการคูณจำนวนบวกด้วย -1 จะทำให้เป็นลบ ทั้งหมดอยู่ใน StackOverflow
MusiGenesis

1
@javapowered: ไม่ (int) 15.0 ไม่ใช่ 0 มีบางอย่างผิดพลาด แต่เราไม่สามารถบอกได้ว่าเกิดจากอะไร โปรดสร้างโปรแกรมสั้น ๆ แต่สมบูรณ์เพื่อสาธิตสิ่งนี้แล้วถามคำถาม ฉันสงสัยว่าคุณจะพบว่ามันยากที่จะทำซ้ำ ...
Jon Skeet

1
@MusiGenesis: <code> (int) IGNORE_RATIO * Volume </code> คำนวณเป็น <code> (int) 0.15 * Volume </code> แต่ตัวพิมพ์จะใช้กับอัตราส่วนเท่านั้นไม่ใช่ผลลัพธ์ของผลิตภัณฑ์และ คุณจะได้รับ <code> 0 * Volume </code> คือศูนย์! ใช้ <code> (int) (IGNORE_RATIO * Volume) </code> แทนเพื่อแก้บั๊กของคุณ
verdy_p

11

ตาม MSDN Math.Floor (double) ส่งคืนค่าสองเท่า: http://msdn.microsoft.com/en-us/library/e0b5f0xb.aspx

หากคุณต้องการเป็น int:

int result = (int)Math.Floor(yourVariable);

ฉันเห็นว่าบทความ MSDN ทำให้เข้าใจผิดได้อย่างไรพวกเขาควรระบุว่าแม้ว่าผลลัพธ์จะเป็น "จำนวนเต็ม" (ในกรณีนี้หมายถึงจำนวนเต็ม) ก็ยังคงเป็น TYPE Double


ขอบคุณสำหรับการตอบกลับของคุณ. จริงๆแล้วฉันกำลังดูบทความนี้: msdn.microsoft.com/en-us/library/e0b5f0xb.aspx แต่อย่างไรก็ตามฉันจะลองทำตามคำแนะนำของคุณ ขอบคุณ.

จริงอยู่ที่ด้านบน "ส่งกลับจำนวนเต็ม" แต่ระบุประเภทไว้ด้านล่าง: Public static double Floor (double d)
Neil N

3
จำนวนเต็ม! = int( answers.com/integer ) - จำนวนเต็มสามารถเก็บไว้ในDouble(ดูคำตอบของจอน) และมีจำนวนเต็มจำนวนไม่ จำกัด ที่ไม่สามารถเก็บไว้ในintไฟล์.
Shog9

Shog ฉันไม่ได้บอกว่าพวกเขาทำไม่ได้ สิ่งที่ฉันพูดคือ "มันยังคงเป็น TYPE Double"
Neil N

1
@ นีล: ใช่ - แค่ต้องการเน้นความแตกต่างระหว่าง "จำนวนเต็ม" (ชื่อของชุด) และint(ชื่อประเภท)
Shog9

4

หากคุณต้องการเพียงแค่ส่วนจำนวนเต็มของตัวเลขให้โยนตัวเลขเป็นint. ซึ่งจะเป็นการตัดตัวเลขที่จุดทศนิยม

double myDouble = 4.6;
int myInteger = (int)myDouble;

2
สิ่งสำคัญที่ควรทราบว่าการแคสต์จะintทำงานแตกต่างกันไปFloorสำหรับจำนวนลบ Floorจะตัดทอนเป็นจำนวนลบมากที่สุดเสมอในขณะที่การแคสต์intจะตัดเป็น 0
แม็กนัส


0

ชั้นปล่อยให้เป็นสองเท่าเพื่อให้คุณสามารถคำนวณซ้ำได้มากขึ้นด้วย ถ้าคุณต้องการให้เป็น int ให้ส่งผลลัพธ์ของพื้นเป็น int อย่าโยนคู่เดิมเป็น int เนื่องจากกฎสำหรับพื้นแตกต่างกัน (IIRC) สำหรับจำนวนลบ


0
Convert.ToInt32(Math.Floor(Convert.ToDouble(value)))

สิ่งนี้จะทำให้คุณได้ค่าที่แน่นอนตามที่คุณต้องการหากคุณนำ4.6มันกลับมา4เป็นผลลัพธ์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.