เคยลองสรุปตัวเลขทั้งหมดตั้งแต่ 1 ถึง 2,000,000 ในภาษาการเขียนโปรแกรมที่คุณชื่นชอบ? ผลลัพธ์ที่ได้นั้นง่ายต่อการคำนวณด้วยตนเอง: 2,000,001,000,000 ซึ่งมีขนาดใหญ่กว่า 900 เท่าของค่าสูงสุดของจำนวนเต็ม 32 บิตที่ไม่ได้ลงนาม
C # พิมพ์ออกมา-1453759936
- ค่าลบ! และฉันเดาว่า Java ทำเช่นเดียวกัน
นั่นหมายความว่ามีบางภาษาโปรแกรมทั่วไปที่ละเว้น Arithmetic Overflow โดยค่าเริ่มต้น (ใน C # มีตัวเลือกที่ซ่อนอยู่สำหรับการเปลี่ยนแปลงนั้น) นั่นเป็นพฤติกรรมที่ดูเสี่ยงมากสำหรับฉันและไม่ใช่ความผิดพลาดของ Ariane 5 ที่เกิดจากการไหลล้นเช่นนี้ใช่ไหม
ดังนั้น: อะไรคือการตัดสินใจในการออกแบบที่อยู่เบื้องหลังพฤติกรรมที่อันตราย
แก้ไข:
คำตอบแรกสำหรับคำถามนี้แสดงค่าใช้จ่ายในการตรวจสอบที่มากเกินไป มารันโปรแกรม C # สั้น ๆ เพื่อทดสอบสมมติฐานนี้:
Stopwatch watch = Stopwatch.StartNew();
checked
{
for (int i = 0; i < 200000; i++)
{
int sum = 0;
for (int j = 1; j < 50000; j++)
{
sum += j;
}
}
}
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
บนเครื่องของฉันรุ่นที่ตรวจสอบใช้เวลา 11015 มิลลิวินาทีในขณะที่รุ่นที่ไม่ได้ตรวจสอบใช้เวลา 4125 มิลลิวินาที นั่นคือขั้นตอนการตรวจสอบใช้เวลาเกือบสองเท่าในการเพิ่มตัวเลข (รวมทั้งหมด 3 เท่าของเวลาเดิม) แต่ด้วยการทำซ้ำ 10,000,000,000 ครั้งเวลาที่ใช้ในการตรวจสอบยังคงน้อยกว่า 1 นาโนวินาที อาจมีสถานการณ์ที่สำคัญ แต่สำหรับแอปพลิเคชันส่วนใหญ่นั้นจะไม่สำคัญ
แก้ไข 2:
ฉันคอมไพล์แอปพลิเคชั่นเซิร์ฟเวอร์ของเราอีกครั้ง (บริการ Windows วิเคราะห์ข้อมูลที่ได้รับจากเซ็นเซอร์หลายตัวและมีจำนวนที่เกี่ยวข้องกับ/p:CheckForOverflowUnderflow="false"
พารามิเตอร์) (โดยปกติแล้วฉันจะสลับการตรวจสอบโอเวอร์โฟลว์) และปรับใช้บนอุปกรณ์ การตรวจสอบ Nagios แสดงให้เห็นว่าภาระ CPU เฉลี่ยอยู่ที่ 17%
ซึ่งหมายความว่าประสิทธิภาพการทำงานที่พบในตัวอย่างที่สร้างขึ้นด้านบนนั้นไม่เกี่ยวข้องกับแอปพลิเคชันของเราโดยสิ้นเชิง
(1..2_000_000).sum #=> 2000001000000
ใช่: อีกภาษาที่ฉันชอบ: sum [1 .. 2000000] --=> 2000001000000
. Array.from({length: 2000001}, (v, k) => k).reduce((acc, el) => acc + el) //=> 2000001000000
ไม่ได้ชื่นชอบ: (เพื่อความยุติธรรมคนสุดท้ายคือการโกง)
Integer
ใน Haskell มีความแม่นยำตามอำเภอใจมันจะเก็บหมายเลขใด ๆ ไว้ตราบใดที่คุณไม่ได้ใช้ RAM ที่จัดสรรไม่ได้
But with the 10,000,000,000 repetitions, the time taken by a check is still less than 1 nanosecond.
นั่นเป็นข้อบ่งชี้ของการวนซ้ำที่ถูกปรับให้เหมาะสม อีกทั้งประโยคนั้นขัดแย้งกับตัวเลขก่อนหน้าซึ่งดูเหมือนจะใช้ได้กับฉันมาก
checked { }
ส่วนเพื่อทำเครื่องหมายส่วนต่าง ๆ ของรหัสที่ควรทำการตรวจสอบทางคณิตศาสตร์มากเกินไป นี่คือเนื่องจากประสิทธิภาพ