요약 수정
- 내 원래 대답은 코드에 많은 복제 계산이 포함되어 있고 많은 힘이 1/3의 요소와 관련이 있다는 점에 주목했습니다. 예를 들어
pow(x, 0.1e1/0.3e1)
는 cbrt(x)
.
- 두 번째 편집은 틀렸고 세 번째 편집은이 잘못을 외삽했습니다. 이것은 사람들이 문자 'M'으로 시작하는 상징적 수학 프로그램에서 오라클과 같은 결과를 변경하는 것을 두려워하게 만드는 것입니다. 나는 그 편집을
스트라이크 (즉, 스트라이크 ) 하고이 답변의 현재 개정판의 맨 아래로 밀어 넣었습니다. 그러나 나는 그것들을 삭제하지 않았다. 나는 인간이다. 우리는 실수하기 쉽습니다.
- 나의 네 번째 편집 올바르게 문제의 복잡한 표현을 나타내는 매우 컴팩트 한 표정으로 개발 IF 매개 변수가
l1
, l2
그리고 l3
긍정적 인 실제 숫자와 경우에 a
비 제로 실수입니다. (이 계수의 특정 특성에 대해서는 아직 OP로부터 듣지 못했습니다. 문제의 특성을 감안할 때 이는 합리적인 가정입니다.)
- 이 편집은 이러한 표현을 단순화하는 방법에 대한 일반적인 문제에 대한 답변을 시도합니다.
먼저 첫 번째 것들
실수를 피하기 위해 Maple을 사용하여 C ++ 코드를 생성합니다.
Maple과 Mathematica는 때때로 명백한 것을 놓칩니다. 더욱 중요한 것은 Maple 및 Mathematica 사용자가 때때로 실수를한다는 것입니다. "때때로"대신 "자주"또는 "거의 항상"으로 대체하는 것은 아마도 마크에 더 가깝습니다.
Maple이 문제의 매개 변수에 대해 말함으로써 해당 표현을 단순화하는 데 도움이 될 수 있습니다. 손의 예에서, 그 의심 l1
, l2
그리고 l3
있습니다 긍정적 인 실수를하고는 a
비 제로 실수입니다. 그럴 경우 그렇게 말하십시오. 이러한 상징적 수학 프로그램은 일반적으로 당면한 양이 복잡하다고 가정합니다. 도메인을 제한하면 프로그램이 복소수에서 유효하지 않은 가정을 할 수 있습니다.
기호 수학 프로그램에서 이러한 큰 혼란을 단순화하는 방법 (이 편집)
기호 수학 프로그램은 일반적으로 다양한 매개 변수에 대한 정보를 제공하는 기능을 제공합니다. 특히 문제가 나눗셈이나 지수화와 관련된 경우 그 능력을 사용하십시오. 손의 예에서, 당신은 단풍 나무가 그것을 말함으로써 그 표현을 단순화 도움이 수 l1
, l2
및 l3
포지티브 실수를하고는 a
비 제로 실수입니다. 그럴 경우 그렇게 말하십시오. 이러한 상징적 수학 프로그램은 일반적으로 당면한 양이 복잡하다고 가정합니다. 도메인을 제한하면 프로그램이 a x b x = (ab) x 와 같은 가정을 할 수 있습니다 . 이 경우에만입니다 a
및 b
긍정적 인 실수하고있는 경우는 x
진짜입니다. 복소수에서는 유효하지 않습니다.
궁극적으로 이러한 상징적 수학 프로그램은 알고리즘을 따릅니다. 함께 도와주세요. 코드를 생성하기 전에 확장, 수집 및 단순화를 시도해보십시오. 이 경우, 당신은 그의 요소를 포함하는 용어 수집 한 수 mu
와의 요소를 포함하는 사람들을 K
. 표현을 "가장 단순한 형태"로 줄이는 것은 약간의 예술로 남아 있습니다.
생성 된 코드가 엉망이 될 때 만져서는 안된다는 사실로 받아들이지 마십시오. 직접 단순화하십시오. 기호 수학 프로그램이 코드를 생성하기 전에 무엇을 가지고 있는지 살펴보십시오. 내가 어떻게 당신의 표현을 훨씬 더 간단하고 훨씬 빠르게 줄 였는지, 그리고 Walter의 대답 이 어떻게 내 여러 단계를 더 발전 시켰 는지 보세요. 마법의 레시피는 없습니다. 마법의 레시피가 있다면 메이플은 그것을 적용하고 월터가 준 대답을했을 것입니다.
구체적인 질문에 대해
당신은 그 계산에서 많은 덧셈과 뺄셈을하고 있습니다. 서로 거의 취소되는 조건이 있으면 심각한 문제에 빠질 수 있습니다. 다른 용어보다 우세한 용어가 있으면 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);
항상 두 번 확인하지만 항상 단순화하십시오.
위의 단계에 도달하는 몇 가지 단계는 다음과 같습니다.
// 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);
오답, 의도적으로 겸손하게 유지
이것은 위험하다는 점에 유의하십시오. 틀렸어.
최신 정보
메이플은 명백한 것을 놓쳤습니다. 예를 들어 작성하는 훨씬 쉬운 방법이 있습니다.
(pow (l1 * l2 * l3, -0.1e1 / 0.3e1)-l1 * l2 * l3 * pow (l1 * l2 * l3, -0.4e1 / 0.3e1) / 0.3e1)
그 가정 l1
, l2
그리고 l3
복잡한 숫자보다 실제가 아니라이며, 실제 큐브 루트 (보다는 원칙 복잡한 루트)입니다 추출 할 것을, 위에서 제로로 줄일 수 있습니다. 이 0의 계산은 여러 번 반복됩니다.
두 번째 업데이트
내가 수학을 제대로했다면 (내가 수학을 제대로 했다는 보장 은 없다 ), 질문의 불쾌한 표현은 다음과 같이 줄어든다.
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)
변수를 변수 로 대체하는 것 입니다 ...하지만 코드가 빠르게 실행되는지 느리게 실행되는지 확인하려면 코드를 벤치마킹해야합니다.