แก้ไขสรุป
- คำตอบเดิมของฉันเพียงแค่ตั้งข้อสังเกตว่ารหัสมีการคำนวณจำลองจำนวนมากและอำนาจหลายอย่างเกี่ยวข้องกับปัจจัย 1/3 ยกตัวอย่างเช่นเป็นเช่นเดียวกับ
pow(x, 0.1e1/0.3e1)
cbrt(x)
- การแก้ไขครั้งที่สองของฉันผิดพลาดและครั้งที่สามของฉันคาดการณ์ถึงความผิดนี้ นี่คือสิ่งที่ทำให้ผู้คนกลัวที่จะเปลี่ยนผลลัพธ์ที่เหมือน oracle จากโปรแกรมคณิตศาสตร์สัญลักษณ์ที่ขึ้นต้นด้วยตัวอักษร 'M' ฉันได้แก้ไข (เช่น
ขีดฆ่า) การแก้ไขเหล่านั้นและผลักดันไปที่ด้านล่างของการแก้ไขปัจจุบันของคำตอบนี้ อย่างไรก็ตามฉันไม่ได้ลบออก ฉันเป็นมนุษย์ เป็นเรื่องง่ายที่เราจะทำพลาด
- แก้ไขที่สี่ของฉันพัฒนาแสดงออกขนาดเล็กมากที่ถูกต้องหมายถึงการแสดงออกที่ซับซ้อนในคำถามถ้าพารามิเตอร์
l1
, l2
และl3
ตัวเลขจริงบวกและถ้าa
เป็นที่ไม่ใช่ศูนย์จำนวนจริง (เรายังไม่ได้รับฟังจาก OP เกี่ยวกับลักษณะเฉพาะของค่าสัมประสิทธิ์เหล่านี้เนื่องจากลักษณะของปัญหานี่เป็นสมมติฐานที่สมเหตุสมผล)
- การแก้ไขนี้พยายามที่จะตอบปัญหาทั่วไปเกี่ยวกับวิธีลดความซับซ้อนของนิพจน์เหล่านี้
สิ่งแรกก่อน
ฉันใช้ Maple เพื่อสร้างรหัส C ++ เพื่อหลีกเลี่ยงข้อผิดพลาด
Maple และ Mathematica บางครั้งก็พลาดสิ่งที่ชัดเจน ที่สำคัญบางครั้งผู้ใช้ Maple และ Mathematica ก็ทำผิดพลาด การแทนที่ "บ่อยครั้ง" หรืออาจจะเป็น "เกือบตลอดเวลา" แทน "บางครั้งอาจใกล้เคียงกับเครื่องหมายมากกว่า
คุณสามารถช่วย Maple ลดความซับซ้อนของนิพจน์นั้นได้โดยการบอกเกี่ยวกับพารามิเตอร์ที่เป็นปัญหา ในตัวอย่างที่อยู่ในมือผมสงสัยว่าl1
, l2
และl3
ตัวเลขจริงบวกและที่a
เป็นที่ไม่ใช่ศูนย์จำนวนจริง ถ้าเป็นอย่างนั้นบอกเลย โดยทั่วไปแล้วโปรแกรมคณิตศาสตร์สัญลักษณ์เหล่านี้ถือว่าปริมาณที่มีอยู่นั้นซับซ้อน การ จำกัด โดเมนช่วยให้โปรแกรมตั้งสมมติฐานที่ไม่ถูกต้องในจำนวนเชิงซ้อน
วิธีลดความซับซ้อนของสิ่งเหล่านี้จากโปรแกรมคณิตศาสตร์สัญลักษณ์ (แก้ไขนี้)
โดยทั่วไปโปรแกรมคณิตศาสตร์สัญลักษณ์ให้ความสามารถในการให้ข้อมูลเกี่ยวกับพารามิเตอร์ต่างๆ ใช้ความสามารถนั้นโดยเฉพาะอย่างยิ่งถ้าปัญหาของคุณเกี่ยวข้องกับการหารหรือการยกกำลัง ในตัวอย่างที่อยู่ในมือคุณอาจได้ช่วยลดความซับซ้อนของเมเปิลที่แสดงออกด้วยการบอกว่าl1
, l2
และl3
ตัวเลขจริงบวกและที่a
เป็นที่ไม่ใช่ศูนย์จำนวนจริง ถ้าเป็นอย่างนั้นบอกเลย โปรแกรมคณิตศาสตร์สัญลักษณ์เหล่านี้มักจะถือว่าปริมาณที่มีอยู่นั้นซับซ้อน การ จำกัด โดเมนช่วยให้สมมติฐานโปรแกรมทำเช่นx B x = (AB) x นี่คือในกรณีที่a
และb
เป็นจำนวนจริงบวกและถ้าx
เป็นจริง มันไม่ถูกต้องในจำนวนเชิงซ้อน
ในที่สุดโปรแกรมคณิตศาสตร์สัญลักษณ์เหล่านั้นเป็นไปตามอัลกอริทึม ช่วยด้วย ลองเล่นด้วยการขยายรวบรวมและทำให้ง่ายขึ้นก่อนที่คุณจะสร้างโค้ด ในกรณีนี้คุณอาจจะมีการเก็บรวบรวมแง่ผู้ที่เกี่ยวข้องกับปัจจัยของและผู้ที่เกี่ยวข้องกับปัจจัยของmu
K
การลดนิพจน์ให้เป็น "รูปแบบที่ง่ายที่สุด" ยังคงเป็นศิลปะอยู่เล็กน้อย
เมื่อคุณได้รับโค้ดที่สร้างขึ้นอย่างไม่เป็นระเบียบอย่ายอมรับว่าเป็นความจริงที่คุณต้องไม่แตะต้อง พยายามทำให้ง่ายขึ้นด้วยตัวคุณเอง ดูว่าโปรแกรมคณิตศาสตร์สัญลักษณ์มีอะไรก่อนที่จะสร้างโค้ด ดูว่าฉันลดการแสดงออกของคุณให้ง่ายขึ้นและเร็วขึ้นมากแค่ไหนและคำตอบของวอลเตอร์ทำให้ฉันก้าวไปอีกขั้นได้อย่างไร ไม่มีสูตรวิเศษ หากมีสูตรวิเศษเมเปิ้ลจะนำไปใช้และให้คำตอบที่วอลเตอร์ให้
เกี่ยวกับคำถามเฉพาะ
คุณกำลังทำการบวกและลบจำนวนมากในการคำนวณนั้น คุณอาจมีปัญหาอย่างหนักหากคุณมีเงื่อนไขที่เกือบจะยกเลิกซึ่งกันและกัน คุณกำลังสิ้นเปลือง CPU เป็นจำนวนมากหากคุณมีคำศัพท์หนึ่งคำที่ครอบงำคำอื่น ๆ
ถัดไปคุณจะสิ้นเปลือง CPU จำนวนมากโดยทำการคำนวณซ้ำ ๆ เว้นแต่คุณจะเปิดใช้งาน-ffast-math
ซึ่งทำให้คอมไพลเลอร์ทำลายกฎบางส่วนของจุดลอยตัวของ IEEE คอมไพเลอร์จะไม่ (ในความเป็นจริงต้องไม่) ทำให้นิพจน์นั้นง่ายขึ้นสำหรับคุณ แต่จะทำในสิ่งที่คุณบอกให้ทำแทน อย่างน้อยที่สุดคุณควรคำนวณl1 * l2 * l3
ก่อนที่จะคำนวณความยุ่งเหยิงนั้น
ในที่สุดคุณก็โทรหาpow
บ่อยมากซึ่งช้ามาก หมายเหตุว่าหลายสายที่มีรูปแบบ (L1 L2 * * * * * l3) (1/3) การโทรจำนวนมากเหล่านั้นpow
สามารถทำได้ด้วยการโทรครั้งเดียวไปที่std::cbrt
:
l123 = l1 * l2 * l3;
l123_pow_1_3 = std::cbrt(l123);
l123_pow_4_3 = l123 * l123_pow_1_3;
ด้วยสิ่งนี้,
X * pow(l1 * l2 * l3, 0.1e1 / 0.3e1)
X * l123_pow_1_3
จะกลายเป็น
X * pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
X / l123_pow_1_3
จะกลายเป็น
X * pow(l1 * l2 * l3, 0.4e1 / 0.3e1)
X * l123_pow_4_3
จะกลายเป็น
X * pow(l1 * l2 * l3, -0.4e1 / 0.3e1)
X / l123_pow_4_3
จะกลายเป็น
เมเปิ้ลพลาดอย่างเห็นได้ชัด
ตัวอย่างเช่นมีวิธีที่ง่ายกว่ามากในการเขียน
(pow(l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow(l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
สมมติว่าl1
, l2
และl3
เป็นจริงมากกว่าตัวเลขที่ซับซ้อนและรากที่สามจริง (มากกว่ารากซับซ้อนหลักการ) จะมีการสกัดดังกล่าวข้างต้นจะช่วยลด
2.0/(3.0 * pow(l1 * l2 * l3, 1.0/3.0))
หรือ
2.0/(3.0 * l123_pow_1_3)
การใช้cbrt_l123
แทนl123_pow_1_3
การแสดงออกที่น่ารังเกียจในคำถามจะลดลง
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu/(3.0*l123)*( pow(l1/cbrt_l123,a)*(2.0*N1-N2-N3)
+ pow(l2/cbrt_l123,a)*(2.0*N2-N3-N1)
+ pow(l3/cbrt_l123,a)*(2.0*N3-N1-N2))
+K*(l123-1.0)*(N1+N2+N3);
ตรวจสอบอีกครั้งเสมอ แต่จะทำให้ง่ายขึ้นเช่นกัน
นี่คือขั้นตอนบางส่วนของฉันในการมาถึงด้านบน:
T=(mu*(pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l1-pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l1/0.3e1-pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l1/0.3e1)/a+K*(l1*l2*l3-0.1e1)*l2*l3)*N1/l2/l3+(mu*(-pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l2/0.3e1+pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l2-pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l2/0.3e1)/a+K*(l1*l2*l3-0.1e1)*l1*l3)*N2/l1/l3+(mu*(-pow(l1*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l3/0.3e1-pow(l2*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a/l3/0.3e1+pow(l3*pow(l1*l2*l3,-0.1e1/0.3e1),a)*a*(pow(l1*l2*l3,-0.1e1/0.3e1)-l1*l2*l3*pow(l1*l2*l3,-0.4e1/0.3e1)/0.3e1)*pow(l1*l2*l3,0.1e1/0.3e1)/l3)/a+K*(l1*l2*l3-0.1e1)*l1*l2)*N3/l1/l2;
l123 = l1 * l2 * l3;
T=(mu*(pow(l1*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l1-pow(l2*pow(l123,-1.0/3),a)*a/l1/3-pow(l3*pow(l123,-1.0/3),a)*a/l1/3)/a+K*(l123-1.0)*l2*l3)*N1/l2/l3+(mu*(-pow(l1*pow(l123,-1.0/3),a)*a/l2/3+pow(l2*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l2-pow(l3*pow(l123,-1.0/3),a)*a/l2/3)/a+K*(l123-1.0)*l1*l3)*N2/l1/l3+(mu*(-pow(l1*pow(l123,-1.0/3),a)*a/l3/3-pow(l2*pow(l123,-1.0/3),a)*a/l3/3+pow(l3*pow(l123,-1.0/3),a)*a*(pow(l123,-1.0/3)-l123*pow(l123,-4.0/3)/3)*pow(l123,1.0/3)/l3)/a+K*(l123-1.0)*l1*l2)*N3/l1/l2;
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T=(mu*(pow(l1/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l1-pow(l2/cbrt_l123,a)*a/l1/3-pow(l3/cbrt_l123,a)*a/l1/3)/a+K*(l123-1.0)*l2*l3)*N1/l2/l3+(mu*(-pow(l1/cbrt_l123,a)*a/l2/3+pow(l2/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l2-pow(l3/cbrt_l123,a)*a/l2/3)/a+K*(l123-1.0)*l1*l3)*N2/l1/l3+(mu*(-pow(l1/cbrt_l123,a)*a/l3/3-pow(l2/cbrt_l123,a)*a/l3/3+pow(l3/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l3)/a+K*(l123-1.0)*l1*l2)*N3/l1/l2;
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l1
-pow(l2/cbrt_l123,a)*a/l1/3
-pow(l3/cbrt_l123,a)*a/l1/3)/a
+K*(l123-1.0)*l2*l3)*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)*a/l2/3
+pow(l2/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l2
-pow(l3/cbrt_l123,a)*a/l2/3)/a
+K*(l123-1.0)*l1*l3)*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)*a/l3/3
-pow(l2/cbrt_l123,a)*a/l3/3
+pow(l3/cbrt_l123,a)*a*2.0/(3.0*cbrt_l123)*cbrt_l123/l3)/a
+K*(l123-1.0)*l1*l2)*N3/l1/l2;
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3))*N1/l2/l3
+K*(l123-1.0)*l2*l3*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l2
-pow(l3/cbrt_l123,a)/l2/3))*N2/l1/l3
+K*(l123-1.0)*l1*l3*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/(3.0*cbrt_l123)*cbrt_l123/l3))*N3/l1/l2
+K*(l123-1.0)*l1*l2*N3/l1/l2;
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
(mu*( pow(l1/cbrt_l123,a)*2.0/3.0/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3))*N1/l2/l3
+(mu*(-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2
-pow(l3/cbrt_l123,a)/l2/3))*N2/l1/l3
+(mu*(-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/3.0/l3))*N3/l1/l2
+K*(l123-1.0)*N1
+K*(l123-1.0)*N2
+K*(l123-1.0)*N3;
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu*( ( pow(l1/cbrt_l123,a)*2.0/3.0/l1
-pow(l2/cbrt_l123,a)/l1/3
-pow(l3/cbrt_l123,a)/l1/3)*N1/l2/l3
+ (-pow(l1/cbrt_l123,a)/l2/3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2
-pow(l3/cbrt_l123,a)/l2/3)*N2/l1/l3
+ (-pow(l1/cbrt_l123,a)/l3/3
-pow(l2/cbrt_l123,a)/l3/3
+pow(l3/cbrt_l123,a)*2.0/3.0/l3)*N3/l1/l2)
+K*(l123-1.0)*(N1+N2+N3);
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu*( pow(l1/cbrt_l123,a)*2.0/3.0/l1*N1/l2/l3
-pow(l2/cbrt_l123,a)/l1/3*N1/l2/l3
-pow(l3/cbrt_l123,a)/l1/3*N1/l2/l3
-pow(l1/cbrt_l123,a)/l2/3*N2/l1/l3
+pow(l2/cbrt_l123,a)*2.0/3.0/l2*N2/l1/l3
-pow(l3/cbrt_l123,a)/l2/3*N2/l1/l3
-pow(l1/cbrt_l123,a)/l3/3*N3/l1/l2
-pow(l2/cbrt_l123,a)/l3/3*N3/l1/l2
+pow(l3/cbrt_l123,a)*2.0/3.0/l3*N3/l1/l2)
+K*(l123-1.0)*(N1+N2+N3);
l123 = l1 * l2 * l3;
cbrt_l123 = cbrt(l123);
T =
mu/(3.0*l123)*( pow(l1/cbrt_l123,a)*(2.0*N1-N2-N3)
+ pow(l2/cbrt_l123,a)*(2.0*N2-N3-N1)
+ pow(l3/cbrt_l123,a)*(2.0*N3-N1-N2))
+K*(l123-1.0)*(N1+N2+N3);
ตอบผิดตั้งใจเก็บไว้เพื่อความนอบน้อม
โปรดทราบว่านี่เป็นเรื่องยาก มันผิด.
อัปเดต
เมเปิ้ลพลาดอย่างเห็นได้ชัด ตัวอย่างเช่นมีวิธีที่ง่ายกว่ามากในการเขียน
(ผง (l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * ธาร (l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
สมมติว่าl1
, l2
และl3
เป็นจริงมากกว่าตัวเลขที่ซับซ้อนและรากที่สามจริง (มากกว่ารากซับซ้อนหลักการ) จะมีการสกัดดังกล่าวข้างต้นจะช่วยลดให้เป็นศูนย์ การคำนวณศูนย์นี้จะทำซ้ำหลาย ๆ ครั้ง
การปรับปรุงครั้งที่สอง
ถ้าฉันทำคณิตศาสตร์ถูกต้อง ( ไม่มีการรับประกันว่าฉันทำคณิตศาสตร์ถูกต้อง) การแสดงออกที่น่ารังเกียจในคำถามจะลดลงเป็น
l123 = l1 * l2 * l3;
cbrt_l123_inv = 1.0 / cbrt(l123);
nasty_expression =
K * (l123 - 1.0) * (N1 + N2 + N3)
- ( pow(l1 * cbrt_l123_inv, a) * (N2 + N3)
+ pow(l2 * cbrt_l123_inv, a) * (N1 + N3)
+ pow(l3 * cbrt_l123_inv, a) * (N1 + N2)) * mu / (3.0*l123);
ดังกล่าวข้างต้นสันนิษฐานว่าl1
, l2
และl3
ตัวเลขจริงบวก
pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
ตัวแปรทั้งหมดด้วยตัวแปร ... คุณต้องเปรียบเทียบโค้ดของคุณเพื่อให้แน่ใจว่ามันทำงานเร็วหรือช้า