เหตุใดจึงจำเป็นต้องใช้ "f" ในการประกาศการลอยตัว


88

ตัวอย่าง:

float timeRemaining = 0.58f;

เหตุใดจึงfต้องระบุต่อท้ายตัวเลขนี้


4
doubleอาจจะเป็นเพราะมิฉะนั้นก็จะได้รับการปฏิบัติ
Uwe Keim

2
0.58 (ไม่มีคำต่อท้าย f) เป็นลิเทอรัลประเภท double และไม่สามารถกำหนดค่า double ให้กับ float ได้เช่นเดียวกับที่ไม่สามารถกำหนดค่า int ให้กับสตริงได้ อย่างไรก็ตามคุณสามารถกำหนดค่า float ให้เป็นสองเท่าได้เนื่องจากที่นี่คุณกำลังขยับขยาย (C # จะแปลงค่านี้ให้คุณโดยปริยายเนื่องจากจะไม่มีการสูญเสียความแม่นยำ)
Dave New


@AVD แม้ว่าจะซ้ำกัน แต่หัวข้อคำถามด้านบนจะไม่แสดงลิงก์ของคุณในรายการที่อาจซ้ำกันได้ ดังนั้นนี่อาจเป็นการเพิ่มมูลค่าในแง่ของเกณฑ์การค้นหามากขึ้นอย่างน้อยที่สุด
Adam Houldsworth

1
@AdamHouldsworth - ทั้งหมดถนนไป double & int
adatapost

คำตอบ:


98

การประกาศลอยของคุณประกอบด้วยสองส่วน:

  1. มันบอกว่าตัวแปรเป็นชนิดtimeRemainingfloat
  2. กำหนดค่า0.58ให้กับตัวแปรนี้

ปัญหาเกิดขึ้นในส่วนที่ 2

ด้านขวามือจะได้รับการประเมินด้วยตนเอง ตามข้อกำหนด C # ตัวเลขที่มีจุดทศนิยมที่ไม่มีคำต่อท้ายจะถูกตีความว่าเป็นdouble.

ดังนั้นตอนนี้เรามีค่าที่เราต้องการที่จะกำหนดให้กับตัวแปรประเภทdouble floatเพื่อที่จะทำเช่นนี้จะต้องมีการแปลงนัยจากการdouble floatไม่มีการแปลงดังกล่าวเนื่องจากคุณอาจ (และในกรณีนี้) สูญเสียข้อมูลในการแปลง

เหตุผลก็คือค่าที่คอมไพเลอร์ใช้ไม่ใช่ 0.58 จริง ๆ แต่เป็นค่าทศนิยมที่ใกล้เคียงที่สุดกับ 0.58 ซึ่งก็คือ 0.57999999999999978655962351581366 ... สำหรับdouble0.579999946057796478271484375 สำหรับfloat.

พูดอย่างเคร่งครัดfไม่จำเป็นต้องใช้ คุณสามารถหลีกเลี่ยงการใช้fคำต่อท้ายได้โดยการส่งค่าเป็นfloat:

float timeRemaining = (float)0.58;

4
คำถามสองข้อคุณมาถึงหมายเลข '0.579999946057796478271484375' ได้อย่างไรและจะ(float) 0.58ทำงานอย่างไร คุณบอกก่อนหน้านี้ว่าไม่มีการแปลงเนื่องจากข้อมูลอาจสูญหายแล้วนักแสดงจะทำงานได้อย่างไร?
SexyBeast

9
1. ฉันใช้เครื่องคิดเลขของ Windows ซึ่งใช้มากถึง 34 หลัก 2. ฉันบอกว่าไม่มีการแปลงโดยปริยาย การแคสต์เป็นการแปลงอย่างชัดเจนดังนั้นคุณจึงบอกคอมไพเลอร์อย่างชัดเจนว่าคุณต้องการการแปลงและนั่นเป็นสิ่งที่อนุญาต
Jeffrey Sax

น่าสนใจ ... ฉันหวังว่าคุณจะยังติดตามโพสต์นี้ ฉันได้รับการแนะนำให้รู้จักกับคำต่อท้ายที่พบว่า "m" ก่อนหน้านี้สำหรับการออกอากาศทางเว็บที่ฉันกำลังดูอยู่ คุณทำให้เครื่องคิดเลข Windows แสดง. 58 เป็นค่าลอยได้อย่างไร ฉันลองใช้ปุ่มสองปุ่มที่ดูเหมือนว่ามันจะบังคับให้สิ่งนี้เกิดขึ้น แต่ไม่ ... ยังคงได้รับ 0.58 ฉันต้องเคารพผู้ชายคนหนึ่งที่รู้จักเครื่องมือของเขาเป็นอย่างดี ...
user1585204

ฉันเข้าใจ F ทั้งหมดสำหรับการลอย แต่ทำไม? เมื่อคุณประกาศตัวแปรจะถูกประกาศว่าเป็น float ดังนั้นเมื่อคอมไพล์แล้วควรรู้ว่าค่านี้เป็น float และเมื่อคุณประกาศสิ่งเดียวกันสองครั้ง มันไม่สมเหตุสมผลเพราะคุณลอย myvalue = 2.4; ตอนนี้เมื่อคอมไพเลอร์คอมไพเลอร์ควรรู้แล้ว float เป็นประเภทของตัวแปร ฉันพลาดอะไรไปรึเปล่า? ขอบคุณ!
Frank G.

@ แฟรงค์ก. เหตุผลสองประการ: 1. นิพจน์2.4ถูกตีความว่าเป็นสองเท่าในทุกที่ 2. ไม่อนุญาตให้มีการ จำกัด การแปลงโดยนัย (เช่นจากคู่เป็นลอย) หากคุณต้องการยกเว้นกฎเหล่านี้คุณต้องมีเหตุผลที่ดีมาก การประหยัดจังหวะสำคัญ 1 ครั้งไม่น่าจะดีพอ
Jeffrey Sax

36

เพราะมีหลายประเภทที่เป็นตัวเลขหลายอย่างที่คอมไพเลอร์สามารถใช้เพื่อเป็นตัวแทนของความคุ้มค่า0.58: float, และdouble decimalเว้นแต่คุณจะตกลงกับคอมไพลเลอร์ที่เลือกมาให้คุณคุณต้องแยกความคลุมเครือ

เอกสารสำหรับdoubleระบุว่าถ้าคุณไม่ระบุประเภทด้วยตัวเองคอมไพเลอร์จะเลือกdoubleเป็นประเภทของลิเทอรัลตัวเลขจริงเสมอ:

ตามค่าเริ่มต้นลิเทอรัลตัวเลขจริงทางด้านขวาของตัวดำเนินการกำหนดจะถือว่าเป็นสองเท่า อย่างไรก็ตามหากคุณต้องการให้จำนวนเต็มถือว่าเป็นสองเท่าให้ใช้คำต่อท้าย d หรือ D

การต่อท้ายคำต่อท้ายfจะสร้างfloat; คำต่อท้ายdสร้างdouble; คำต่อท้ายmจะสร้างไฟล์decimal. ทั้งหมดนี้ยังใช้ตัวพิมพ์ใหญ่

อย่างไรก็ตามสิ่งนี้ยังไม่เพียงพอที่จะอธิบายว่าเหตุใดจึงไม่รวบรวม:

float timeRemaining = 0.58;

ครึ่งหนึ่งของคำตอบที่หายไปคือการแปลงจากเป็นdouble 0.58ไปเป็นfloat timeRemainingข้อมูลที่อาจสูญเสียไปดังนั้นคอมไพเลอร์จึงปฏิเสธที่จะนำไปใช้โดยปริยาย หากคุณเพิ่มการร่ายอย่างชัดเจนการแปลงจะดำเนินการ หากคุณเพิ่มfคำต่อท้ายก็ไม่จำเป็นต้องมีการแปลง ในทั้งสองกรณีโค้ดจะคอมไพล์


แต่มันจะเป็นสองเท่าหรือทศนิยมได้อย่างไรถ้าตัวแปรเป็นทศนิยมฉันขาดอะไรไป
โทมัส

@BlazArt ใช่ประโยคที่ระบุว่าคอมไพเลอร์ไม่ได้พยายามตรวจสอบเป้าหมายการกำหนด เหตุผลนี้จะฝังอยู่ในตัวเลือกการออกแบบที่ทำโดยทีมคอมไพเลอร์ ฉันจะคิดว่ามันเป็นดีที่สุดที่จะมีความชัดเจนในการเผชิญกับความสับสนที่เป็นไปได้หรือมันแพงเกินไปที่จะรำคาญการดำเนินการแทนเพียงแค่มีสองกฎหนึ่งสำหรับและหนึ่งสำหรับint double
Adam Houldsworth

@BlazArt: เพิ่งเสร็จสิ้นการหาคำตอบโปรดดูอีกครั้ง
จอน

1
เกี่ยวกับการสูญหายของข้อมูลคุณสามารถบอกฉันได้ไหมว่าการแคสต์นั้นเกิดขึ้นจริงได้อย่างไรเมื่อเทียบกับรูปแบบ IEEE 754 ที่เก็บไว้ Double มีความแม่นยำสูงกว่านั่นหมายความว่าการโยนจากลูกลอยเป็นสองเท่าจะใช้ได้ผลเสมอdouble a = 0.69f;ใช่หรือไม่?
SexyBeast

@Cupidvogel: ใช่ข้อมูลจำเพาะรับประกัน (ใน§6.1.2) ว่า "การแปลงตัวเลขโดยนัยอื่น ๆ จะไม่สูญเสียข้อมูลใด ๆ " ซึ่งรวมถึงการแปลง floatdoubleไป
จอน

2

ปัญหาคือ. NET เพื่อให้การดำเนินการโดยนัยบางประเภทสามารถดำเนินการที่เกี่ยวข้องfloatและdoubleจำเป็นต้องระบุอย่างชัดเจนว่าจะเกิดอะไรขึ้นในทุกสถานการณ์ที่เกี่ยวข้องกับตัวถูกดำเนินการแบบผสมหรืออื่น ๆ ที่อนุญาตให้ทำการแปลงโดยนัยระหว่างประเภทในรูปแบบเดียว ทิศทางเท่านั้น ไมโครซอฟท์เลือกที่จะทำตามผู้นำของ Java ในการอนุญาตทิศทางที่บางครั้งให้ความสำคัญกับความแม่นยำ แต่มักจะเสียสละความถูกต้องและมักสร้างความยุ่งยาก

ในเกือบทุกกรณีการรับdoubleค่าที่ใกล้เคียงที่สุดกับปริมาณตัวเลขเฉพาะและกำหนดให้กับ a floatจะให้floatค่าที่ใกล้เคียงกับปริมาณเดียวกันมากที่สุด มีบางกรณีมุมเช่นมูลค่า 9,007,199,791,611,905; การfloatแสดงที่ดีที่สุดคือ 9,007,200,328,482,816 (ซึ่งลดลง 536,870,911) แต่การคัดเลือกdoubleตัวแทนที่ดีที่สุด(เช่น 9,007,199,791,611,904) จะให้floatผล 9,007,199,254,740,992 (ซึ่งลดลง 536,870,913) โดยทั่วไปแล้วการแปลงการdoubleแทนค่าที่ดีที่สุดของปริมาณบางส่วนให้floatเป็นการนำเสนอที่ดีที่สุดเท่าที่จะเป็นไปได้floatหรือการแสดงหนึ่งในสองการแสดงที่ดีพอ ๆ กัน

โปรดสังเกตว่าพฤติกรรมที่พึงปรารถนานี้ใช้ได้แม้ในขั้นสุดขั้ว ตัวอย่างเช่นการfloatแทนค่าที่ดีที่สุดสำหรับปริมาณ 10 ^ 308 จะตรงกับการfloatแทนค่าที่ทำได้โดยการแปลงการdoubleแทนค่าที่ดีที่สุดของปริมาณนั้น ในทำนองเดียวกันการfloatแทนค่าที่ดีที่สุดของ 10 ^ 309 จะตรงกับการfloatแทนค่าที่ได้จากการแปลงการdoubleแทนค่าที่ดีที่สุดของปริมาณนั้น

น่าเสียดายที่การแปลงในทิศทางที่ไม่ต้องใช้การแคสต์อย่างชัดเจนนั้นแทบจะไม่มีความแม่นยำ การแปลงการfloatแสดงค่าที่ดีที่สุดเป็นdoubleแทบจะไม่ให้ผลใด ๆ โดยเฉพาะอย่างยิ่งใกล้เคียงกับการdoubleแสดงค่าที่ดีที่สุดและในบางกรณีผลลัพธ์อาจผิดไปจากลำดับความสำคัญหลายร้อย (เช่นการแปลงค่าที่ดีที่สุดfloatของ 10 ^ 40 เพื่อdoubleให้ได้ผล ค่าที่เปรียบเทียบมากกว่าค่าที่ดีที่สุดdoubleของ 10 ^ 300

อนิจจากฎการแปลงคือสิ่งที่เป็นดังนั้นเราจึงต้องใช้ชีวิตโดยใช้ตัวพิมพ์และคำต่อท้ายโง่ ๆ เมื่อแปลงค่าไปในทิศทางที่ "ปลอดภัย" และระวังตัวพิมพ์โดยนัยในทิศทางที่เป็นอันตรายซึ่งมักจะให้ผลลัพธ์ที่ผิดพลาด

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