`Vector <float> ควรจะสะท้อนกลับหรือควรเป็นไปตามความหมายของ IEEE 754?


9

เมื่อเปรียบเทียบค่าทศนิยมเพื่อความเท่าเทียมมีสองวิธีที่แตกต่างกัน:

สร้างขึ้นใน IEEE ลอยชนิดจุดใน C # ( floatและdouble) ปฏิบัติตามมาตรฐาน IEEE ความหมายสำหรับ==และ!=(และผู้ประกอบการเชิงสัมพันธ์เช่น<) แต่ให้มั่นใจ reflexivity สำหรับobject.Equals, IEquatable<T>.Equals(และCompareTo)

ตอนนี้พิจารณาห้องสมุดที่ให้ structs เวกเตอร์ที่ด้านบนของ/float doubleประเภทเวกเตอร์ดังกล่าวจะเกิน==/ !=และแทนที่/object.EqualsIEquatable<T>.Equals

สิ่งที่ทุกคนเห็นพ้องต้องกันคือ==/ !=ควรทำตามความหมายของ IEEE คำถามคือห้องสมุดควรใช้Equalsวิธีการ (ซึ่งแยกจากตัวดำเนินการความเสมอภาค) ในวิธีที่สะท้อนกลับหรือในวิธีที่ตรงกับความหมายของ IEEE

อาร์กิวเมนต์สำหรับการใช้ความหมายของ IEEE สำหรับEquals:

  • เป็นไปตาม IEEE 754
  • มันเร็วกว่า (อาจมาก) เพราะสามารถใช้ประโยชน์จากคำสั่ง SIMD ได้

    ฉันได้ถามคำถามแยกต่างหากเกี่ยวกับสแต็คโอเวอร์โฟลว์เกี่ยวกับวิธีที่คุณแสดงความเท่าเทียมสะท้อนกลับโดยใช้คำสั่ง SIMD และผลกระทบต่อประสิทธิภาพการทำงานของพวกเขา: คำแนะนำ SIMD สำหรับการเปรียบเทียบความเท่าเทียมกันของจุดลอยตัว

    อัปเดต:ดูเหมือนว่าเป็นไปได้ที่จะใช้ความเท่าเทียมแบบสะท้อนได้อย่างมีประสิทธิภาพโดยใช้คำสั่ง SIMD สามคำ

  • เอกสารสำหรับEqualsไม่จำเป็นต้องมีการสะท้อนกลับเมื่อเกี่ยวข้องกับจุดลอยตัว:

    ข้อความต่อไปนี้ต้องเป็นจริงสำหรับการใช้งานทั้งหมดของวิธีการ Equals (Object) ในรายการx, yและzแทนการอ้างอิงวัตถุที่ไม่เป็นโมฆะ

    x.Equals(x)ผลตอบแทนtrueยกเว้นในกรณีที่เกี่ยวข้องกับประเภทจุดลอย ดูที่ ISO / IEC / IEEE 60559: 2011, เทคโนโลยีสารสนเทศ - ระบบไมโครโปรเซสเซอร์ - เลขทศนิยม

  • หากคุณกำลังใช้โฟลทเป็นคีย์พจนานุกรมคุณกำลังใช้ชีวิตอยู่ในสภาพบาปและไม่ควรคาดหวังพฤติกรรมที่มีสติ

อาร์กิวเมนต์สำหรับการสะท้อนกลับ:

  • มันเป็นเรื่องที่สอดคล้องกับประเภทที่มีอยู่รวมทั้งSingle, Double, และTupleSystem.Numerics.Complex

    ฉันไม่รู้แบบอย่างใด ๆ ใน BCL ที่Equalsติดตาม IEEE แทนที่จะสะท้อนกลับ เคาน์เตอร์ตัวอย่าง ได้แก่Single, Double, และTupleSystem.Numerics.Complex

  • Equalsส่วนใหญ่จะใช้โดยคอนเทนเนอร์และอัลกอริทึมการค้นหาซึ่งขึ้นอยู่กับการสะท้อนกลับ สำหรับอัลกอริธึมเหล่านี้ประสิทธิภาพที่เพิ่มขึ้นนั้นไม่เกี่ยวข้องหากป้องกันไม่ให้ทำงานได้ อย่าเสียสละความถูกต้องในการแสดง
  • จะแบ่งทุกชุดกัญชาและพจนานุกรมContains, Find, IndexOfคอลเลกชันต่างๆ / LINQ การดำเนินงานชุด LINQ based ( Union, Exceptฯลฯ ) หากข้อมูลที่มีNaNค่า
  • โค้ดที่ทำการคำนวณจริงที่ยอมรับได้ในความหมายของ IEEE มักใช้กับรูปแบบที่เป็นรูปธรรมและใช้==/ !=(หรือการเปรียบเทียบ epsilon ที่มีแนวโน้มมากกว่า)

    ขณะนี้คุณไม่สามารถเขียนการคำนวณประสิทธิภาพสูงโดยใช้ generics เนื่องจากคุณต้องการการดำเนินการทางคณิตศาสตร์สำหรับสิ่งนั้น แต่สิ่งเหล่านี้ไม่สามารถใช้ได้ผ่านทางอินเตอร์เฟส / วิธีการเสมือน

    ดังนั้นEqualsวิธีที่ช้ากว่าจะไม่ส่งผลกระทบต่อรหัสประสิทธิภาพสูงที่สุด

  • เป็นไปได้ที่จะให้IeeeEqualsวิธีการหรือIeeeEqualityComparer<T>กรณีที่คุณต้องการความหมายของ IEEE หรือคุณต้องการประสิทธิภาพที่เหนือกว่า

ในความคิดของฉันข้อโต้แย้งเหล่านี้สนับสนุนการใช้งานแบบสะท้อนกลับอย่างยิ่ง

ทีม CoreFX ของ Microsoft วางแผนที่จะแนะนำประเภทเวกเตอร์ดังกล่าวใน. NET ซึ่งแตกต่างจากฉันพวกเขาชอบโซลูชัน IEEEส่วนใหญ่เนื่องจากข้อได้เปรียบด้านประสิทธิภาพ เนื่องจากการตัดสินใจดังกล่าวจะไม่เปลี่ยนแปลงหลังจากการเปิดตัวครั้งสุดท้ายฉันต้องการได้รับคำติชมจากชุมชนในสิ่งที่ฉันเชื่อว่าเป็นความผิดพลาดครั้งใหญ่


1
คำถามที่ยอดเยี่ยมและคิดกระตุ้น สำหรับฉัน (อย่างน้อย) มันไม่สมเหตุสมผล==และEqualsจะให้ผลลัพธ์ที่แตกต่าง โปรแกรมเมอร์จำนวนมากถือว่าพวกเขาเป็นและทำในสิ่งเดียวกัน นอกจากนี้ - โดยทั่วไปการใช้งานของตัวดำเนินการความเสมอภาคจะเรียกใช้Equalsเมธอด คุณยังเป็นที่ถกเถียงกันว่าหนึ่งอาจรวมถึงIeeeEqualsแต่อย่างหนึ่งอาจทำวิธีอื่น ๆ และรวมถึงReflexiveEquals-method Vector<float>ชนิดอาจจะใช้ในหลายประสิทธิภาพการใช้งานที่มีความสำคัญและควรได้รับการปรับให้เหมาะสมตาม
ตาย

@diemaus เหตุผลบางประการที่ทำให้ฉันไม่เชื่อว่า: 1) สำหรับfloat/ doubleและประเภทอื่น ๆ==และEqualsแตกต่างกันไปแล้ว ผมคิดว่าไม่สอดคล้องกับชนิดที่มีอยู่จะทำให้เกิดความสับสนมากยิ่งขึ้นกว่าที่ไม่สอดคล้องกันระหว่าง==และEqualsคุณยังจะต้องจัดการกับประเภทอื่น ๆ 2) อัลกอริธึมทั่วไป / คอลเลกชันทั่วไปใช้Equalsและพึ่งพาการสะท้อนกลับของฟังก์ชั่น (LINQ และพจนานุกรม) ในขณะที่อัลกอริธึมจุดลอยตัวที่เป็นรูปธรรมมักจะใช้ใน==ที่ที่พวกเขาได้รับความหมาย IEEE
CodesInChaos

ผมจะพิจารณาVector<float>เป็น "สัตว์" ที่แตกต่างกว่าที่เรียบง่ายหรือfloat doubleจากมาตรการดังกล่าวฉันไม่เห็นเหตุผลEqualsหรือ==ผู้ปฏิบัติงานปฏิบัติตามมาตรฐานของพวกเขา คุณพูดกับตัวเองว่า: "ถ้าคุณกำลังลอยเป็นกุญแจพจนานุกรมที่คุณใช้ชีวิตอยู่ในสภาพบาปและไม่ควรคาดหวังพฤติกรรมที่มีสติ" หากมีใครที่จะเก็บไว้NaNในพจนานุกรมก็เป็นความผิดของตัวเองสำหรับการใช้การปฏิบัติที่น่ากลัว ฉันแทบจะไม่คิดว่าทีม CoreFX ไม่ได้คิดอย่างนั้น ฉันจะไปด้วยReflexiveEqualsหรือคล้ายกันเพียงเพื่อประสิทธิภาพ
ตาย

คำตอบ:


5

ฉันจะยืนยันว่าพฤติกรรม IEEE นั้นถูกต้อง NaNไม่เทียบเท่ากันในทางใดทางหนึ่ง พวกเขาสอดคล้องกับเงื่อนไขที่กำหนดไว้ไม่ดีซึ่งคำตอบที่เป็นตัวเลขไม่เหมาะสม

นอกเหนือจากผลประโยชน์ที่มาจากการใช้มาตรฐาน IEEE เลขคณิตที่ประมวลผลส่วนใหญ่สนับสนุนการกำเนิดผมคิดว่ามีปัญหากับความหมายบอกว่าถ้าแล้วisnan(x) && isnan(y) x == yตัวอย่างเช่น

// C++
double inf = std::numeric_limits<double>::infinity();
double x = 0.0 / 0.0;
double y = inf - inf;

ฉันจะยืนยันว่าไม่มีเหตุผลที่มีความหมายว่าทำไมหนึ่งจะพิจารณาเท่ากับx yคุณแทบจะไม่สามารถสรุปได้ว่าพวกเขาเป็นตัวเลขที่เทียบเท่ากัน พวกมันไม่ใช่ตัวเลขเลยดังนั้นมันจึงดูเหมือนว่าเป็นแนวคิดที่ไม่ถูกต้องทั้งหมด

นอกจากนี้จากมุมมองการออกแบบ API หากคุณกำลังทำงานกับไลบรารีวัตถุประสงค์ทั่วไปที่ตั้งใจจะใช้โดยโปรแกรมเมอร์จำนวนมากมันก็สมเหตุสมผลที่จะใช้ซีแมนทิกส์จุดลอยตัวทั่วไปในอุตสาหกรรม เป้าหมายของห้องสมุดที่ดีคือการประหยัดเวลาสำหรับผู้ที่ใช้ห้องสมุดดังนั้นการสร้างพฤติกรรมที่ไม่เป็นมาตรฐานนั้นทำให้เกิดความสับสน


3
ที่NaN == NaNควรกลับเท็จไม่ได้โต้แย้ง คำถามคือ.Equalsวิธีที่ควรทำ ตัวอย่างเช่นถ้าฉันใช้NaNเป็นคีย์พจนานุกรมค่าที่เกี่ยวข้องจะไม่สามารถเรียกNaN.Equals(NaN)คืนได้หากส่งคืนค่าเท็จ
CodesInChaos

1
ฉันคิดว่าคุณต้องปรับให้เหมาะสมสำหรับกรณีทั่วไป กรณีที่พบบ่อยสำหรับเวกเตอร์ของตัวเลขคือการคำนวณตัวเลขที่ให้ปริมาณงานสูง (มักปรับให้เหมาะสมกับคำสั่ง SIMD) ฉันจะยืนยันว่าการใช้เวกเตอร์เป็นคีย์พจนานุกรมเป็นกรณีการใช้งานที่หายากมากและเป็นสิ่งที่คุ้มค่าที่จะออกแบบความหมายของคุณ โต้แย้งที่ดูเหมือนว่าเหมาะสมที่สุดให้ฉันเป็นความมั่นคงตั้งแต่ที่มีอยู่Single, Doubleการเรียน ฯลฯ มีพฤติกรรมที่สะท้อน IMHO นั่นเป็นการตัดสินใจที่ผิดที่เริ่มต้น แต่ฉันจะไม่ปล่อยให้ความงดงามเข้ามาในทางที่มีประโยชน์ / ความเร็ว
Jason R

แต่โดยทั่วไปการคำนวณเชิงตัวเลขจะใช้==ซึ่งตามหลัง IEEE เสมอดังนั้นพวกเขาจะได้รับรหัสที่รวดเร็วไม่ว่าEqualsจะนำไปใช้อย่างไร IMO จุดทั้งหมดของการมีEqualsวิธีแยกใช้ในอัลกอริทึมที่ไม่สนใจเกี่ยวกับชนิดคอนกรีตเช่นDistinct()ฟังก์ชันของ LINQ
CodesInChaos

1
ฉันเข้าใจ. แต่ฉันจะเถียงกับ API ที่มี==โอเปอเรเตอร์และEquals()ฟังก์ชั่นที่มีความหมายต่างกัน ฉันคิดว่าคุณกำลังจ่ายค่าใช้จ่ายของความสับสนที่อาจเกิดขึ้นจากมุมมองของนักพัฒนาโดยไม่มีผลประโยชน์จริง (ฉันไม่ได้กำหนดค่าใด ๆ ให้สามารถใช้เวกเตอร์ของตัวเลขเป็นคีย์พจนานุกรม) มันเป็นเพียงความคิดเห็นของฉัน; ฉันไม่คิดว่าจะมีคำตอบที่ตรงกับคำถามในมือ
Jason R

0

มีปัญหา: IEEE754 กำหนดการดำเนินงานเชิงสัมพันธ์และความเท่าเทียมกันในลักษณะที่เหมาะสมกับแอปพลิเคชั่นตัวเลข มันไม่เหมาะที่จะเรียงลำดับและคร่ำเครียด ดังนั้นหากคุณต้องการเรียงลำดับอาร์เรย์ตามค่าตัวเลขหรือถ้าคุณต้องการเพิ่มค่าตัวเลขให้กับชุดหรือใช้เป็นคีย์ในพจนานุกรมคุณอาจประกาศว่าไม่อนุญาตให้ใช้ค่า NaN หรือไม่ใช้ IEEE754 การดำเนินงานในตัว ตารางแฮชของคุณจะต้องตรวจสอบให้แน่ใจว่า NaNs ทั้งหมดนั้นตรงกับค่าเดียวกันและเปรียบเทียบให้เท่ากัน

หากคุณกำหนด Vector คุณต้องตัดสินใจออกแบบว่าคุณต้องการใช้เพื่อวัตถุประสงค์เชิงตัวเลขเท่านั้นหรือควรเข้ากันได้กับการเรียงลำดับและการแปลงแป้นพิมพ์ โดยส่วนตัวผมคิดว่าจุดประสงค์เชิงตัวเลขควรมีความสำคัญมากกว่า หากจำเป็นต้องมีการเรียงลำดับ / hashing คุณสามารถเขียนคลาสที่มี Vector เป็นสมาชิกและกำหนด hashing และความเท่าเทียมกันในชั้นเรียนตามที่คุณต้องการ


1
ฉันยอมรับว่าวัตถุประสงค์เชิงตัวเลขมีความสำคัญมากกว่า แต่เรามี==และ!=ผู้ให้บริการสำหรับพวกเขาอยู่แล้ว จากประสบการณ์ของฉันEqualsวิธีนี้ค่อนข้างใช้โดยอัลกอริธึมที่ไม่ใช่ตัวเลขเท่านั้น
CodesInChaos
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.