เมื่อเปรียบเทียบการลอยคุณเรียกเกณฑ์ความแตกต่างว่าอะไร


10

ฉันเปรียบเทียบลอยใน Java ตอนนี้และสูตรที่ง่ายที่สุดคือ:

Math.abs(a - b) < THRESHOLD

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

ภาษาการเขียนโปรแกรมเป็นคำเฉพาะหรือเป็นสากลในภาษา?


1
ข้อกำหนดอื่น: "ความแม่นยำ", "ความละเอียด" ฉันชอบสิ่งเหล่านี้อย่างแน่นอน;) เพราะพวกเขาไม่ได้ฟังเรื่องเทคนิคมากเกินไป
stakx

1
ปิดหัวข้อ: ลอย-Point คู่มือแนะนำกับการใช้ประเภทของการเปรียบเทียบความเท่าเทียมกันใกล้นี้
stakx

1
@stakx - คำที่คุณแนะนำไม่ถูกต้องและมีความหมายแตกต่างจากสิ่งที่ OP ขอ คำถามนี้มีรายละเอียดใช่ แต่สามารถตอบได้ตามการอ้างอิงภายนอกและมีความเกี่ยวข้องกับการเขียนโปรแกรมเมื่อจัดการกับค่าทศนิยม มันสร้างสรรค์และในหัวข้อ

1
@ GlenH7: ฉันไม่เคยพูดว่าคำถามนั้นไม่ดีหรือตอบไม่ได้ ในความเป็นจริงฉันเป็นคนหนึ่งที่สนับสนุนมัน และเนื่องจากคุณอ้างว่าคำศัพท์ที่ฉันแนะนำนั้นไม่ถูกต้องฉันจึงสนใจที่จะเรียนรู้ว่าทำไมถึงเป็นเช่นนั้น
stakx

@stakx - ขออภัยในความหมายที่คุณโหวตให้ปิด ฉันมีปฏิกิริยาต่อคะแนนโหวตทั้งสี่ของคำถามนี้ในขณะนั้น

คำตอบ:


18

เอปไซลอนในวิชาคณิตศาสตร์และวิศวกรรม

ในวิชาคณิตศาสตร์และวิศวกรรมโดยทั่วไป:

  • โดยทั่วไปแล้วเดลต้าใช้เพื่ออ้างถึงความแตกต่างซึ่งอาจเป็นขนาดใดก็ได้
  • โดยทั่วไปเอปไซลอนจะใช้เพื่ออ้างถึงปริมาณเล็กน้อย

และ epsilon ดูเหมือนจะเหมาะสมกว่าในกรณีของคุณ


เอปไซลอนในวิทยาการคอมพิวเตอร์

วิทยาการคอมพิวเตอร์โดยเฉพาะในระยะ epsilon ยังหมายถึงespilon เครื่องซึ่งมาตรการความแตกต่างระหว่างและลอยเล็กที่สุดซึ่งเป็นขนาดใหญ่กว่าอย่างเคร่งครัด1.0f 1.0fหมายเลขหลังนั้นใช้1.00000011920928955078125fสำหรับการลอยใน Java และสามารถคำนวณได้ด้วย:

float f = Float.intBitsToFloat(Float.floatToIntBits(1f) + 1);

คำจำกัดความของเครื่อง epsilon นั้นสอดคล้องกับการใช้งานทั่วไปของ epsilon ที่อธิบายไว้ข้างต้น


เปรียบเทียบลอย

โปรดทราบว่าก่อนที่จะเปรียบเทียบการลอยสำหรับ "ความใกล้ชิด" คุณจะต้องมีความคิดเกี่ยวกับขนาดของมัน โฟลว์ที่มีขนาดใหญ่มากและลอยตัวที่ต่างกันมากน่าจะเท่ากัน:

9223372036854775808f == 9223372036854775808f + 1000000000f; //this is true!

และในทางกลับกันอาจมีค่าลอยที่เป็นไปได้มากมาย (และคำสั่งหลายขนาด) ระหว่างสองลอยเล็ก ๆ ซึ่งแตกต่างกันโดยเครื่อง epsilon "เท่านั้น" ในตัวอย่างด้านล่างมีค่าลอยตัวที่มีอยู่ 10,000,000 ค่าระหว่างsmallและfแต่ความแตกต่างยังต่ำกว่าเครื่อง epsilon:

float small = Float.MIN_VALUE; // small = 1.4E-45
float f = Float.intBitsToFloat(Float.floatToIntBits(small) + 100000000); // f = 2.3122343E-35
boolean b = (f - small < 0.00000011920928955078125f); //true!

บทความที่เชื่อมโยงอยู่ในคำตอบของ GlenH7 จะทำการตรวจสอบการเปรียบเทียบแบบลอยตัวต่อไปและเสนอวิธีแก้ไขปัญหาต่าง ๆ เพื่อแก้ไขปัญหาเหล่านี้


2
-1: ในซอฟต์แวร์การคำนวณทางวิทยาศาสตร์ Epsilon อ้างถึงMachine epsilonหรือ epsilon ที่สัมพันธ์กัน (ดูบทความเดียวกัน) โดยทั่วไปแล้วนี่ไม่ใช่ปริมาณเดียวกันที่ใช้ในการยอมรับความเสมอภาคโดยประมาณเนื่องจากข้อผิดพลาดในการปัดเศษเป็นทวีคูณของเครื่อง epsilons หรือ epsilons สัมพัทธ์และโดยทั่วไปจะมีขนาดใหญ่กว่านั้นเล็กน้อย
วง

1
@rwong นั่นเป็นหนึ่งในความเชี่ยวชาญของคำเอปไซลอนและมีอื่น ๆ อีกมากมาย โดยทั่วไปแล้ววิศวกรรม epsilon อ้างถึงปริมาณเล็กน้อยหรือมีข้อผิดพลาดและ Machine epsilon เข้ากันได้กับแนวคิดนั้น
assylias

@assylias ใช้ชื่อที่มีคำจำกัดความมาตรฐานในบริบทที่การกำหนดมาตรฐานเหมาะสม แต่สำหรับสิ่งที่ไม่สอดคล้องกับคำจำกัดความมาตรฐานคือใบเสร็จรับเงินสำหรับปัญหา
AProgrammer

@AProgrammer ฉันไม่เห็นด้วยกับคำจำกัดความทั่วไปของ epsilon ที่ไม่สามารถใช้ได้กับการคำนวณ
assylias

1
@assylias: ขอบคุณสำหรับการชี้แจง ฉันลบ -1 ออกแล้ว
ร. ว.

16

ในทางคณิตศาสตร์ delta ถูกใช้เพื่อแสดงถึงความแตกต่างบางอย่างจากค่า epsilon ใช้แทนค่าความผิดพลาดโดยพลการ ในกรณีนี้ epsilon จะเป็นชื่อธรรมดา


8

หากต้องการตอบคำถามของคุณโดยตรงคุณต้องการใช้คำepsilonนั้น ถูกต้องมากขึ้นก็machine epsilonแต่การใช้งานทั่วไปลดลง "เครื่อง" epsilonและเพียงแค่ใช้

มองหาสำเนาที่float.hฉันดู:

#define DBL_EPSILON     2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */  
#define FLT_EPSILON     1.192092896e-07F        /* smallest such that 1.0+FLT_EPSILON != 1.0 */  
#define LDBL_EPSILON    DBL_EPSILON             /* smallest such that 1.0+LDBL_EPSILON != 1.0 */

และความคิดเห็นที่เกี่ยวข้องทำให้ชัดเจนว่า epsilon เป็นคำที่คุณอ้างอิง

แต่เรายังสามารถอ้างอิงภายนอกอื่น ๆ เพื่อตรวจสอบว่าepsilonเป็นคำที่ถูกต้อง ดูที่นี่ , ที่นี่ , ที่นี่และในที่สุดก็รวมกันนี้แท็กแบบสอบถาม SO ฉันไม่สามารถค้นหาการอ้างอิงโดยตรงกับมาตรฐาน IEEE 754 เพื่อเสนอราคา


คุณไม่ได้ถาม แต่ฉันพบข้อมูลอ้างอิงนี้เกี่ยวข้องกับตัวอย่างที่คุณให้ไว้เพื่อชี้แจงคำถามของคุณ

ลองดูที่บทความในบล็อกนี้โดย Bruce Dawson of Valve เกี่ยวกับการเปรียบเทียบค่าทศนิยมสำหรับข้อมูลเชิงลึกเกี่ยวกับสาเหตุที่คุณไม่ต้องการใช้การเปรียบเทียบที่คุณแนะนำ

มีข้อมูลบางส่วนที่บรรจุอยู่ในบทความนั้น แต่นี่เป็นตัวอย่างที่เกี่ยวข้องมากที่สุด:

หากเปรียบเทียบการลอยเพื่อความเท่าเทียมนั้นเป็นแนวคิดที่ไม่ดีดังนั้นวิธีการตรวจสอบว่าความแตกต่างนั้นอยู่ในขอบเขตข้อผิดพลาดหรือค่า epsilon เช่นนี้:

bool isEqual = fabs(f1 – f2) <= epsilon;

ด้วยการคำนวณนี้เราสามารถแสดงแนวคิดของการลอยสองลูกที่อยู่ใกล้พอที่เราต้องการพิจารณาพวกมันให้เท่ากัน แต่เราควรใช้เอปไซลอนเพื่อประโยชน์อะไร
จากการทดลองของเราข้างต้นเราอาจถูกล่อลวงให้ใช้ข้อผิดพลาดในผลรวมของเราซึ่งมีค่าประมาณ 1.19e-7f ในความเป็นจริงมีแม้กระทั่งการกำหนดใน float.h ด้วยค่าที่แน่นอนนั้นและมันเรียกว่า FLT_EPSILON
เห็นได้ชัดว่ามัน เทพเจ้าไฟล์ส่วนหัวพูดและ FLT_EPSILON เป็น epsilon จริงหนึ่งตัว!
ยกเว้นว่าเป็นขยะ สำหรับตัวเลขระหว่าง 1.0 ถึง 2.0 FLT_EPSILON แสดงถึงความแตกต่างระหว่างการลอยตัวที่อยู่ติดกัน สำหรับตัวเลขที่น้อยกว่า 1.0 เอปไซลอนของ FLT_EPSILON จะใหญ่เกินไปอย่างรวดเร็วและด้วยจำนวนที่น้อยพอ ๆ กัน FLT_EPSILON อาจใหญ่กว่าตัวเลขที่คุณกำลังเปรียบเทียบ!

ดอว์สันพิจารณาข้อพิจารณาอื่น ๆ อีกสองสามข้อเกี่ยวกับความสลับซับซ้อนที่เกี่ยวข้องเมื่อเปรียบเทียบการลอยตัวและจัดการกับค่าที่น้อยมากเช่นนี้ดังนั้นฉันขอแนะนำให้คุณอ่านส่วนที่เหลือของโพสต์ของเขา


คุณอาจต้องการชี้แจงส่วนแรกของคำตอบของคุณ: บทความของ Bruce อธิบายแล้วว่าทำไมไม่ควรใช้ epsilon คงที่ (เช่นส่วนที่กำหนดไว้ในไฟล์ส่วนหัว) เพื่อเปรียบเทียบความอดทน นอกจากนี้ในหลาย ๆ กรณีข้อผิดพลาดของ ULP สองสามล้านไม่ใช่สิ่งที่ต้องกังวลเพราะในแอปพลิเคชันส่วนใหญ่เราใส่ใจเกี่ยวกับตัวเลขที่สำคัญมากกว่าข้อผิดพลาดในตัวเลขที่มีนัยสำคัญน้อยที่สุดเพราะความแม่นยำสองเท่าได้ให้แล้ว ตัวเลขมากกว่าที่เราใส่ใจ
rwong

@rwong - เมื่อฉันอ่านมันคำถามก็คือการระบุคำที่ถูกต้องที่จะใช้สำหรับชื่อของค่าคงที่ นั่นเป็นเหตุผลที่ฉันให้การอ้างอิง float.h พร้อมกับคนอื่น ๆ อีกสองสามคนเพื่อใช้ epsilon บทความจาก Dawson เป็นสิ่งที่ฉันพบในขณะที่ค้นหาการอ้างอิง IEEE 754 และฉันคิดว่ามีความเกี่ยวข้องกับ OP simplest formulaเพื่อการเปรียบเทียบ หลายคนใช้วิธีการนั้นเป็นความพยายามครั้งแรกและฉันรวมบทความของดอว์สันไว้ด้วยเพราะมันเข้าสู่ความแตกต่างของการเปรียบเทียบที่ยุ่งยาก ดังนั้นฉันจึงพยายามตอบคำถามโดยตรงแล้วชี้ให้เห็นว่าทำไมไม่ใช้อย่างนั้น

5

นี่คือฟังก์ชันข้อผิดพลาด ข้อผิดพลาดแบบสัมบูรณ์มักเรียกว่าε (epsilon) หรือΔ xสำหรับปริมาณx:

ε = | คาดหวัง - จริง |

Δ x = | x 0 - x  |

ข้อผิดพลาดบางครั้งเรียกว่าη (eta):

η = | 1 - จริง / ที่คาดหวัง |

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

ดู:


3

ฉันจะเรียกมันว่า "ความอดทน"

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

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


+1 ฉันหวังว่าทุกคนจะถามเพื่อนร่วมงานเกี่ยวกับคำถามตั้งชื่อเหล่านี้รวมถึงการโพสต์ที่นี่
MarkJ

6
-1, ดีกว่าที่จะเรียนรู้การประชุมมากกว่าหลีกเลี่ยง
djechlin

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