Chỉnh sửa tóm tắt
- Câu trả lời ban đầu của tôi chỉ lưu ý rằng mã chứa rất nhiều phép tính được lặp lại và nhiều quyền hạn liên quan đến hệ số 1/3. Ví dụ,
pow(x, 0.1e1/0.3e1)
giống như cbrt(x)
.
- Lần chỉnh sửa thứ hai của tôi chỉ là sai, và lần thứ ba của tôi ngoại suy cho sự sai lầm này. Đây là điều khiến mọi người sợ thay đổi kết quả giống như lời tiên tri từ các chương trình toán biểu tượng bắt đầu bằng chữ 'M'. Tôi đã bị ảnh hưởng ra (ví dụ,
đình công ) những chỉnh sửa và đẩy nó vào phần cuối của phiên bản hiện tại của câu trả lời này. Tuy nhiên, tôi đã không xóa chúng. Tôi là người. Rất dễ để chúng tôi mắc sai lầm.
- Chỉnh sửa thứ tư của tôi đã phát triển một biểu hiện rất nhỏ gọn mà chính xác đại diện cho sự biểu hiện phức tạp trong câu hỏi NẾU các thông số
l1
, l2
và l3
là những con số thực dương và nếu a
là một tổ chức phi zero số thực. (Chúng tôi vẫn chưa nhận được phản hồi từ OP về bản chất cụ thể của các hệ số này. Với bản chất của vấn đề, đây là những giả định hợp lý.)
- Chỉnh sửa này cố gắng giải đáp vấn đề chung về cách đơn giản hóa các biểu thức này.
Điều đầu tiên trước tiên
Tôi sử dụng Maple để tạo mã C ++ để tránh những sai lầm.
Maple và Mathematica đôi khi bỏ lỡ điều hiển nhiên. Thậm chí quan trọng hơn, người dùng Maple và Mathematica đôi khi mắc lỗi. Thay thế "thường xuyên", hoặc thậm chí có thể "hầu như luôn luôn", thay cho "đôi khi có lẽ gần với dấu hơn.
Bạn có thể đã giúp Maple đơn giản hóa biểu thức đó bằng cách cho nó biết về các tham số được đề cập. Trong ví dụ ở tay, tôi nghi ngờ rằng l1
, l2
và l3
là những con số thực dương và đó a
là một số thực khác không. Nếu đúng như vậy, hãy nói với nó điều đó. Các chương trình toán biểu tượng đó thường giả định các đại lượng trong tầm tay là phức tạp. Việc hạn chế miền cho phép chương trình đưa ra các giả định không hợp lệ trong các số phức.
Làm thế nào để đơn giản hóa những mớ hỗn độn lớn đó từ các chương trình toán biểu tượng (chỉnh sửa này)
Các chương trình toán tượng trưng thường cung cấp khả năng cung cấp thông tin về các tham số khác nhau. Sử dụng khả năng đó, đặc biệt nếu vấn đề của bạn liên quan đến phép chia hoặc lũy thừa. Trong ví dụ bên mình, bạn có thể đã giúp Maple đơn giản hóa biểu thức bằng cách nói với nó rằng l1
, l2
và l3
là những con số thực dương và đó a
là một số thực khác không. Nếu đúng như vậy, hãy nói với nó điều đó. Các chương trình toán biểu tượng đó thường giả định các đại lượng trong tầm tay là phức tạp. Việc giới hạn miền cho phép chương trình đưa ra các giả định như a x b x = (ab) x . Đây chỉ là nếu a
và b
là các số thực dương và nếu x
là thực. Nó không hợp lệ trong các số phức.
Cuối cùng, các chương trình toán biểu tượng đó tuân theo các thuật toán. Giúp nó cùng. Hãy thử chơi với việc mở rộng, thu thập và đơn giản hóa trước khi bạn tạo mã. Trong trường hợp này, bạn có thể đã thu thập những thuật ngữ liên quan đến hệ số mu
và những thuật ngữ liên quan đến hệ số K
. Giảm một biểu thức về "dạng đơn giản nhất" của nó vẫn là một nghệ thuật.
Khi bạn nhận được một mớ mã được tạo xấu xí, đừng chấp nhận nó như một sự thật mà bạn không được chạm vào. Cố gắng đơn giản hóa nó cho mình. Hãy xem chương trình toán biểu tượng có gì trước khi tạo mã. Hãy xem cách tôi giảm biểu hiện của bạn thành một thứ gì đó đơn giản và nhanh hơn nhiều, và câu trả lời của Walter đã đưa tôi tiến thêm vài bước. Không có công thức kỳ diệu. Nếu có một công thức ma thuật, Maple sẽ áp dụng nó và đưa ra câu trả lời mà Walter đưa ra.
Về câu hỏi cụ thể
Bạn đang thực hiện rất nhiều phép tính cộng và trừ trong phép tính đó. Bạn có thể gặp rắc rối lớn nếu bạn có các điều khoản gần như hủy bỏ nhau. Bạn đang lãng phí rất nhiều CPU nếu bạn có một thuật ngữ chiếm ưu thế hơn các thuật ngữ khác.
Tiếp theo, bạn đang lãng phí rất nhiều CPU do thực hiện các phép tính lặp đi lặp lại. Trừ khi bạn đã bật -ffast-math
, điều này cho phép trình biên dịch phá vỡ một số quy tắc của dấu chấm động IEEE, trình biên dịch sẽ không (trên thực tế, không được) đơn giản hóa biểu thức đó cho bạn. Thay vào đó, nó sẽ làm chính xác những gì bạn đã yêu cầu. Ít nhất, bạn nên tính toán l1 * l2 * l3
trước khi tính toán mớ hỗn độn đó.
Cuối cùng, bạn đang thực hiện rất nhiều cuộc gọi đến pow
, cuộc gọi này cực kỳ chậm. Lưu ý rằng một số lệnh gọi đó có dạng (l1 * l2 * l3) (1/3) . Nhiều cuộc gọi đến pow
có thể được thực hiện chỉ với một lệnh gọi tới std::cbrt
:
l123 = l1 * l2 * l3;
l123_pow_1_3 = std::cbrt(l123);
l123_pow_4_3 = l123 * l123_pow_1_3;
Với cái này,
X * pow(l1 * l2 * l3, 0.1e1 / 0.3e1)
trở thành X * l123_pow_1_3
.
X * pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
trở thành X / l123_pow_1_3
.
X * pow(l1 * l2 * l3, 0.4e1 / 0.3e1)
trở thành X * l123_pow_4_3
.
X * pow(l1 * l2 * l3, -0.4e1 / 0.3e1)
trở thành X / l123_pow_4_3
.
Maple đã bỏ lỡ điều hiển nhiên.
Ví dụ: có một cách dễ dàng hơn để viết
(pow(l1 * l2 * l3, -0.1e1 / 0.3e1) - l1 * l2 * l3 * pow(l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
Giả sử rằng l1
, l2
và l3
là số thực chứ không phải số phức, và gốc khối lập phương thực (chứ không phải gốc phức nguyên tắc) phải được trích xuất, phần trên giảm xuống còn
2.0/(3.0 * pow(l1 * l2 * l3, 1.0/3.0))
hoặc là
2.0/(3.0 * l123_pow_1_3)
Sử dụng cbrt_l123
thay vì l123_pow_1_3
, biểu thức khó chịu trong câu hỏi giảm xuống
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);
Luôn kiểm tra kỹ, nhưng cũng luôn đơn giản hóa.
Dưới đây là một số bước của tôi để đạt được ở trên:
// Step 0: Trim all whitespace.
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;
// Step 1:
// l1*l2*l3 -> l123
// 0.1e1 -> 1.0
// 0.4e1 -> 4.0
// 0.3e1 -> 3
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;
// Step 2:
// pow(l123,1.0/3) -> cbrt_l123
// l123*pow(l123,-4.0/3) -> pow(l123,-1.0/3)
// (pow(l123,-1.0/3)-pow(l123,-1.0/3)/3) -> 2.0/(3.0*cbrt_l123)
// *pow(l123,-1.0/3) -> /cbrt_l123
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;
// Step 3:
// Whitespace is nice.
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;
// Step 4:
// Eliminate the 'a' in (term1*a + term2*a + term3*a)/a
// Expand (mu_term + K_term)*something to mu_term*something + K_term*something
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;
// Step 5:
// Rearrange
// Reduce l2*l3*N1/l2/l3 to N1 (and similar)
// Reduce 2.0/(3.0*cbrt_l123)*cbrt_l123/l1 to 2.0/3.0/l1 (and similar)
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;
// Step 6:
// Factor out mu and K*(l123-1.0)
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);
// Step 7:
// Expand
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);
// Step 8:
// Simplify.
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);
Câu trả lời sai, cố ý giữ lại cho khiêm tốn
Lưu ý rằng điều này được đánh dấu. Nó sai.
Cập nhật
Maple đã bỏ lỡ điều hiển nhiên. Ví dụ: có một cách dễ dàng hơn để viết
(pow (l1 * l2 * l3, -0,1e1 / 0,3e1) - l1 * l2 * l3 * pow (l1 * l2 * l3, -0,4e1 / 0,3e1) / 0,3e1)
Giả sử rằng l1
, l2
và l3
là số thực chứ không phải là số phức, và gốc lập phương thực (chứ không phải gốc phức nguyên tắc) được trích xuất, thì giá trị trên giảm xuống còn 0. Phép tính số 0 này được lặp đi lặp lại nhiều lần.
Cập nhật thứ hai
Nếu tôi đã làm đúng phép toán (không có gì đảm bảo rằng tôi đã làm đúng phép toán), biểu thức khó chịu trong câu hỏi giảm xuống
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);
Trên giả định rằng l1
, l2
và l3
là những con số thực dương.
pow(l1 * l2 * l3, -0.1e1 / 0.3e1)
bằng một biến ... Tuy nhiên, bạn cần phải chuẩn mã của mình để chắc chắn rằng nó chạy nhanh hay chậm.