ผลรวมของการลอยตัวแบบไม่กำหนดค่า


10

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

ตอนนี้มันออกไปให้ฉันแสดงให้คุณเห็นกรณีแปลก ๆ ที่ฉันสังเกตเห็นในวันนี้ ฉันมีรายการค่าจุดลอยตัวและฉันต้องการรวมค่าเหล่านี้:

CREATE TABLE #someFloats (val float);
INSERT INTO #someFloats (val) VALUES (1), (1), (1.2), (1.2), (1.2), (3), (5);

SELECT STR(SUM(#someFloats.val), 30, 15) FROM #someFloats;

DROP TABLE #someFloats;

-- yields:
--   13.600000000000001

จนถึงตอนนี้ดีมาก - ไม่น่าประหลาดใจที่นี่ เราทุกคนรู้ว่า1.2ไม่สามารถแสดงได้อย่างแน่นอนในการเป็นตัวแทนไบนารีดังนั้นคาดว่าจะได้ผลลัพธ์ที่ "ไม่ชัดเจน"

ต่อไปนี้เป็นสิ่งที่แปลกประหลาดเกิดขึ้นเมื่อฉันออกจากโต๊ะอื่น:

CREATE TABLE #A (a int);
INSERT INTO #A (a) VALUES (1), (2);

CREATE TABLE #someFloats (val float);
INSERT INTO #someFloats (val) VALUES (1), (1), (1.2), (1.2), (1.2), (3), (5);

SELECT #A.a, STR(SUM(#someFloats.val), 30, 15)
  FROM #someFloats LEFT JOIN #A ON 1 = 1
 GROUP BY #A.a;

DROP TABLE #someFloats;
DROP TABLE #A;

-- yields
--   1   13.600000000000001
--   2   13.599999999999998

( ซอซอฟท์แว sqlคุณยังสามารถดูแผนการดำเนินการที่นั่น)

ฉันมีผลรวมเท่ากันมากกว่าค่าเดียวกันแต่ข้อผิดพลาดจุดลอยตัวที่แตกต่างกัน ถ้าฉันเพิ่มแถวลงในตาราง#Aเราจะเห็นว่าค่าสลับกันระหว่างค่าทั้งสอง ฉันสามารถทำซ้ำปัญหานี้ด้วยLEFT JOIN; INNER JOINทำงานได้ตามที่คาดไว้ที่นี่

นี้จะไม่สะดวกเพราะมันหมายความว่าDISTINCT, GROUP BYหรือPIVOTเห็นพวกเขาเป็นค่าที่แตกต่างกัน (ซึ่งจริง ๆ แล้ววิธีการที่เราค้นพบปัญหานี้)

ทางออกที่ชัดเจนคือการปัดเศษคุณค่า แต่ฉันอยากรู้: มีคำอธิบายเชิงตรรกะสำหรับพฤติกรรมนี้หรือไม่?

คำตอบ:


15

ที่จริงแล้วลิงค์ที่คุณอ้างถึงไม่ได้บอกว่าการคำนวณเลขคณิตจุดลอยตัวนั้นถูกกำหนดไว้เสมอ ในความเป็นจริงหนึ่งในคำตอบก็กล่าวถึงว่านอกจากนี้ไม่ได้เชื่อมโยง (ความหมาย(a + b) + cไม่จำเป็นต้องเท่ากับa + (b + c)) ซึ่งยังกล่าวในคำตอบนี้

หากการรวมกระแสข้อมูลเกิดขึ้นกับแถวกระบวนการของแต่ละกลุ่มในลำดับที่แตกต่างกัน - ซึ่งโดยปกติแล้ว SQL Server จะให้ทำฟรี หากไม่มีORDER BYในประโยคที่เหมาะสมตัวเพิ่มประสิทธิภาพจะเลือกสแกนหรือค้นหาหรือตัวดำเนินการค้นหาอื่น ๆ จะเร็วที่สุดโดยไม่คำนึงถึงลำดับที่ดำเนินการเพิ่มเติมใน - สิ่งนี้สามารถอธิบายพฤติกรรมที่คุณสังเกตเห็น

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


การเชื่อมโยงไม่มีความเกี่ยวข้องกับระดับดังนั้นบิตนั้นจึงทำให้เข้าใจผิด
Mooing Duck

การไม่เชื่อมโยงของการเพิ่มจุดลอยตัวนำไปสู่พฤติกรรมที่ไม่ได้กำหนดไว้SUM()ล่วงหน้าของฟังก์ชันการรวม SQL Server คุณจะเห็นด้วย @MooingDuck หรือไม่?
mustaccio

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

การแบ่งจำนวนเต็มเป็นตัวอย่างสำหรับ SQL Server SUM()เกี่ยวกับการขัดแย้งจุดลอยตัวว่าเป็นอย่างไร
mustaccio

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