問題 a^5 + b^5 + c^5 + d^5 = e^5 が成立する場合のa,b,c,d,eを計算するプログラムを作成したのですが、処理速度が30秒もかかってしまいます。
どこを変更、または何を追加すれば速くなるか教えてください。
条件は a < b < c < d < e
a,b,c,d,e, < 200 です。
どうかご教授お願いします。
#include <stdio.h>
int main (void)
{
int a,b,c,d,e ;
double A5,B5,C5,D5,E5;
for(a = 1; a <= 195 ; a++ )
{
A5 = a * a * a * a * (double)a ;
for(b = a+1; b <= 196 ; b++ )
{
B5 = b * b * b * b * (double)b ;
for(c = b+1; c <= 197 ; c++ )
{
C5 = c * c * c * c * (double)c ;
for(d = c+1; d <= 198 ; d++ )
{
D5 = d * d * d * d * (double)d ;
for(e = d+1; e <= 199 ; e++ )
{
E5 = e * e * e * e * (double)e ;
if((A5 + B5 + C5 + D5 ) == E5)
{
printf("a=%d,b=%d,c=%d,d=%d,e=%d\n",a,b,c,d,e);
printf("a^5=%.0lf,b^5=%.0lf,c^5=%.0lf,d^5=%.0lf,e^5=%.0lf\n",A5,B5,C5,D5,E5);
}
}
}
}
}
}
return 0;
}
A 回答 (16件中1~10件)
- 最新から表示
- 回答順に表示
No.16
- 回答日時:
固定値のテーブル作成例です。
(分量多いので少し横着しました)#define SSS(S) S(1),S(2),S(3),S(4),S(5),S(6),S(7),S(8),S( 9),S( 10),\
S( 11),S( 12),S( 13),S( 14),S( 15),S( 16),S( 17),S( 18),S( 19),S( 20),\
S( 21),S( 22),S( 23),S( 24),S( 25),S( 26),S( 27),S( 28),S( 29),S( 30),\
S( 31),S( 32),S( 33),S( 34),S( 35),S( 36),S( 37),S( 38),S( 39),S( 40),\
S( 41),S( 42),S( 43),S( 44),S( 45),S( 46),S( 47),S( 48),S( 49),S( 50),\
S( 51),S( 52),S( 53),S( 54),S( 55),S( 56),S( 57),S( 58),S( 59),S( 60),\
S( 61),S( 62),S( 63),S( 64),S( 65),S( 66),S( 67),S( 68),S( 69),S( 70),\
S( 71),S( 72),S( 73),S( 74),S( 75),S( 76),S( 77),S( 78),S( 79),S( 80),\
S( 81),S( 82),S( 83),S( 84),S( 85),S( 86),S( 87),S( 88),S( 89),S( 90),\
S( 91),S( 92),S( 93),S( 94),S( 95),S( 96),S( 97),S( 98),S( 99),S(100),\
S(101),S(102),S(103),S(104),S(105),S(106),S(107),S(108),S(109),S(110),\
S(111),S(112),S(113),S(114),S(115),S(116),S(117),S(118),S(119),S(120),\
S(121),S(122),S(123),S(124),S(125),S(126),S(127),S(128),S(129),S(130),\
S(131),S(132),S(133),S(134),S(135),S(136),S(137),S(138),S(139),S(140),\
S(141),S(142),S(143),S(144),S(145),S(146),S(147),S(148),S(149),S(150),\
S(151),S(152),S(153),S(154),S(155),S(156),S(157),S(158),S(159),S(160),\
S(161),S(162),S(163),S(164),S(165),S(166),S(167),S(168),S(169),S(170),\
S(171),S(172),S(173),S(174),S(175),S(176),S(177),S(178),S(179),S(180),\
S(181),S(182),S(183),S(184),S(185),S(186),S(187),S(188),S(189),S(190),\
S(191),S(192),S(193),S(194),S(195),S(196),S(197),S(198),S(199),S(200)
// 5乗値
#define D5D(n) (double)((double)n*(double)n*(double)n*(double)n*(double)n)
const double DIM5[201] = { (double)0,SSS(D5D) };
// 5乗値の32剰余
#define D5M32(n) ((n%32)*(n%32)*(n%32)*(n%32)*(n%32))%32
const int DIM5_MOD32[201] = { 0,SSS(D5M32) };
// 元値の32剰余
#define D1M32(n) n%32
const int DIM1_MOD32[201] = { 0,SSS(D1M32) };
// 元値の10剰余
#define D1M10(n) n%10
const int DIM1_MOD10[201] = { 0,SSS(D1M10) };
// 5乗値の10剰余(元値と同じ)
#defineDIM5_MOD10 DIM1_MOD10
No.15
- 回答日時:
32の剰余を使えばもっと手数が少なくできそうです。
//0~31の5乗を32で割った剰余
const int DIM5_MOD32[32] = {
0,1,0,19,0,21,0,7,0,9,0,27,0,29,0,15,
0,17,0,3,0,5,0,23,0,25,0,11,0,13,0,31
};
ここから考えると、
1)5乗値の剰余が0以外の偶数になることはない。
2)5乗値の剰余が奇数なら元値の剰余は特定できる。
は適用できそうです。
5乗値の和や差の剰余値は除算しなくても元値の剰余が分かれば
上の配列を使って計算できます。
例)1^5+3^5の剰余は20になる
偶数なら剰余が0のときだけ検索すればよく、
奇数なら候補は32飛ばしで多くても6~7個です。
前述の10の剰余を使ってさらに候補を減らすこともできます。
No.14
- 回答日時:
剰余から推測する方法は結構いけるようですね。
5乗値を10で割った剰余は元数と同じになるようです。
最下層は10飛ばしで検索できるので、
1,11,21,31,...191の5乗、
2,12,22,32,...192の5乗、
という10刻みで20個のテーブルを作っておけばいいかも。
No.13
- 回答日時:
肝心なところを説明してなかったですが、整数でまかなえる部分は整数
演算で行うと考えれば、
a,b,c,dを決めてeを探すよりも、
a,b,c,eを決めて差分からc<d<eの範囲でdを探すほうが
演算が若干整数範囲に入りやすいと思うのです。
浮動小数プロセッサを有効活用しないと演算時間は加減算でも数倍、
乗算だと10倍以上かかるはずです。(駆使しても何倍かは重いはず)
まぁあまりいじるとこぼしそうなので正攻法でこなした方が無難かもし
れませんけど、やはり自分なら73^5を閾値にして幾分かでも整数演
算を導入したいかな。
全部浮動小数で計算するつもりなら、今まで書いた
5乗値を固定配置する(乗算をなくす)
ループの各階層で中間合計を記憶して加算演算を減らす
オーバーフローを判定(してループを抜ける)
5つ目の変数を中点検索する
くらいです。
あと些細な小技ですが、
5つ目の数は残りの4つが決まれば偶数か奇数か判別できますから、
最下層のループは逐次検索でも半分に減らせます。
5乗値の浮動小数だと判別しづらいので元数の偶奇から判別すると
いいでしょう。
No.12
- 回答日時:
ごめんなさい。
読み違ってましたね。^^;4個和=残りの1つですか!!
200^5も一応39ビットで基数部に入るようですね。
手持ち環境(マイコン)で試してできましたから、
(double)1*(double)1*(double)1*(double)1*(double)1,
で固定値配置はPCでも可能だと思います。
73以下なら5乗しても21億を切るので、73までの5乗配列を
用意しておき、3個和からの差分が73^5より小さい場合は整数
で判定したほうがいいです。
CPUが専用演算を持ってたとしても整数演算のほうが数倍速いの
が普通なので、手間をかけたとしてもお釣りがたっぷり来るはず。
No.11
- 回答日時:
ループの条件式を見ると、5つの数値はそれぞれ違う数値でなければ
ならないのでしょうか?
とすれば、5乗値の配列から連続5個の和を読めば組み合わせの
上限と下限は判断つきますよね。
毎回5個和をとるのでなく、各階層で1~4個の中間和を記憶して
おけば、合計値が対象を超えた時点でブレークして次候補の演算に
すぐ移行できるはずです。
No.10
- 回答日時:
No.2のように、予め5乗の計算結果を共通の配列に保存しておきます。
a,b,c,d,e すべての5乗の計算は共通の配列から取り出します。
処理速度が変わらないというのは無いはずです。私が検証した結果40%ほど処理速度が向上しました。
もう一つ、No.8のように枝刈りをする方法です。ソースではaから順に昇順で計算していますが、e^5を計算した後の判定において a^5 + b^5 + c^5 + d^5 < e^5 であれば、それ以降eを加算しても右辺と左辺は同値になりません。
よって、左辺 < 右辺となった時点でeのループはbreakさせることができ、ループ回数を減らせます。
この処理によりループ回数を約75%減らせます。
こちらの環境で試したところ、質問文のソースでは50秒、上記の改良後は6秒まで短縮できました。
No.9
- 回答日時:
No.8 です。
もう一つ追加。効果のほどはわかりませんが。
一般に、a ~ d が正の数であれば、
(a + b + c + d)^5 >= a^5 + b^5 + c^5 + d^5 です。
ですから、
(a + b + c + d)^5 < e^5 なら、a^5 + b^5 + c^5 + d^5 は、(もっと小さいので)e^5 に等しくなることはありません。
これを利用して、ループする処理の先頭で、
double sum = a + b + c + d;
sum = sum * sum * sum * sum * sum;
e5 = e * e * e * e * double(e);
if (sum < e5) continue;
という判断を入れると、ループの回数はかなり減るのではないかと思います。
これは、例えば、
1^5 + 2^5 + 3^5 + 4^5 = 100^5
のようなケースのチェックを回避するためのものです。
この判断をするための計算量とトレードオフではありますが。
No.8
- 回答日時:
この場合、諸悪の根源は、約200回×5重のループの存在そのものです。
ループの回数を減らさないと、計算時間の向上は無理です。
例えば、
100^5 + 101^5 + 102^5 + 103^5 = 104^5
というのは、ちょっと考えれば、チェックする必要もないわけです。
実際には、(ちょっとではなく)よく考えて、チェックする必要のないものをあらかじめ除きます。
よく考えるのは苦手なので、思いつくのを2点
ループですが、
a < b < c < d < e
ですから、
for(e = 1; e <= 200; e++)
{
for(d = 1; d < e; d++)
{
for(c = 1; c < d; c++)
{
for(b = 1; b < c; b++)
{
for(a = 1; a < b; a++)
{
とネストさせることで、計算回数はかなり減らせるはずです。
また、a^5 + b ^5 の計算中に、e^5 以上になれば、それ以降チェックする必要はありません。
これは、大きい方からチェックするとすぐにあふれますから、このネストの中で、
double sum = 0
e5 = e*e*e*e*(double)e;
sum += d*d*d*d*(double)d;
if (sum>= e5) continue;
sum += c*c*c*c*(double)c;
if (sum >= e5) continue;
のようにすれば、それなりに計算量を減らすことができるはずです。
もっとじっくり考えれば、もっと計算量を減らすことができるでしょう。
もしかしたら、(a + b + c + d) が、「何とか以上」なら、計算不要というような関係が見つかるかもしれません。
No.7
- 回答日時:
5乗の数値はいちいち計算しなくても固定値配列で作れるはずです。
const int TBL[] = {
1*1*1*1*1,
2*2*2*2*2,
...
};
200の5乗は32ビット範囲(2^31-1まで)を超えるので
範囲内まで抑えてください。
合計値が比較対象を超えたらそれ以降の計算は無駄なのでブレーク
してください。
途中でオーバーフローする可能性も考慮必要です。
配列は右上がりなので、最後の判定部は逐次比較ではなく中点検索
でいけます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語でユーザ関数を利用して複素数のべき乗と絶対値の数列を計算するプログラムが作りたいです。 3 2023/01/29 22:13
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# LU分解法のピボッティングについて(C言語/gcc-9) 3 2022/07/11 23:10
- C言語・C++・C# LU分解法のピボット選択機能実装について(C言語・gcc-9) 1 2022/07/22 15:20
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# C言語(構造体) 3 2022/07/05 20:08
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
float型とdouble型の変数の違い...
-
C言語を実行すると-infが出てき...
-
doubleの変数にintとintの割り...
-
プログラムでの数字につく”f”の...
-
C 開放してるのにエラー(doubl...
-
doubleは常に%lfとするべきなのか
-
ニュートン法
-
相互相関関数
-
Cで3乗根を求める方法
-
floating point not loadedとは?
-
C言語で-23乗を取り扱うには
-
関数におけるif文とreturn文に...
-
C言語のプログラムで#include<m...
-
カウントアップタイマ
-
テイラー展開(C言語)
-
「割り算」 と 「分数の掛け算」
-
線形補間
-
物体が往復する動きを作りたい
-
EXE1→DLL→EXE2数値を受け渡す方法
-
-1.#IND00と出てしまうのですが...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
プログラムでの数字につく”f”の...
-
float型とdouble型の変数の違い...
-
doubleの変数にintとintの割り...
-
C言語を実行すると-infが出てき...
-
C 開放してるのにエラー(doubl...
-
至急です! マクロ定義で #defi...
-
c言語で、繰り返し文の中で、0....
-
関数におけるif文とreturn文に...
-
C言語 関数プロトタイプ宣言の...
-
C言語初心者 構造体 課題について
-
C言語の型による処理速度の違い
-
Cで3乗根を求める方法
-
C言語で-23乗を取り扱うには
-
2分法で方程式の複数の解を自...
-
doubleは常に%lfとするべきなのか
-
c言語のコンパイルエラー canno...
-
C言語で直角三角形の斜辺を求め...
-
C言語のプログラムで#include<m...
-
int とdoubleの比較
-
C++で外積
おすすめ情報