著作権フリーのC++高速汎用多倍長演算を作るスレ
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
2007/11/24(土) 09:53:51ネット上でここが詳しい
http://homepage1.nifty.com/~umetani/ims/Algebra.html
0002デフォルトの名無しさん
2007/11/24(土) 09:55:520003デフォルトの名無しさん
2007/11/24(土) 10:02:0300041
2007/11/24(土) 10:07:130005デフォルトの名無しさん
2007/11/24(土) 10:15:38単発依頼スレを自分だけ特別に立てて良いと思った理由を述べろ。
00061
2007/11/24(土) 11:03:2300071
2007/11/24(土) 11:27:300008デフォルトの名無しさん
2007/11/24(土) 12:02:03できんやつはスレ立てる.
若干反例があるが,これは普遍の真理.
00091
2007/11/24(土) 12:02:480010デフォルトの名無しさん
2007/11/24(土) 12:08:16その著作権は誰のものになるんだ?
0011デフォルトの名無しさん
2007/11/24(土) 12:08:32ちなみに、それはもう存在してて、ググれば見つかるよ。
商用利用もOK。GPLじゃない。
00121
2007/11/24(土) 12:15:50R[X]/(X^n-1) → R[G] (同型のフーリエ変換)
という写像を作って
多項式環の乗法が、 右側だと簡単で計算出来て、
それを同型で戻すという寸法だ
00131
2007/11/24(土) 12:28:08では、高速離散フーリエ変換のライブラリでフリーで高速にうごくやつを組み込んで作ろう
どこかにいいやつありますか?
0014デフォルトの名無しさん
2007/11/24(土) 12:34:1000151
2007/11/24(土) 12:49:28それより厳密な整数演算に使える高速フーリエ変換ってあるんですか?
誤差が出るやつでは駄目です 整数演算のみでやるやつです
0016デフォルトの名無しさん
2007/11/24(土) 16:00:2900171
2007/11/24(土) 17:43:360018デフォルトの名無しさん
2007/11/24(土) 18:30:37とりあえず
基幹部分はC
インターフェイスはPython
でいいんだよな
0019デフォルトの名無しさん
2007/11/24(土) 18:34:5200201
2007/11/24(土) 19:29:10数値を多項式と見立てて、多項式の乗算、即ち、離散系の畳み込みをフーリエ空間で行い、
それを実空間に戻して、数値の乗算をしたことにするのである。
今、4096個の一次元データに4096個データの一次元フィルタを掛けるとすれば、
実空間では、4096*4096 約1678万回の乗算が必要となるが、
DFTでは、畳み込みだけでは、0.4万回で済む。前後に3回のDFTが必要となるが、
この分は、FFTで行えば8万回程度なので、約8.4万回で済むことになる。約200倍のスピードとなる。
http://www.nextftp.com/swlabo/m0_pctech/hp_ultraprecision/up_815_1.htm
00211
2007/11/24(土) 19:34:583/4 N*Nにできるアルゴリズムがあるが断然違うよな
0022デフォルトの名無しさん
2007/11/24(土) 19:37:550023デフォルトの名無しさん
2007/11/24(土) 19:48:590024デフォルトの名無しさん
2007/11/24(土) 22:23:19多倍長整数の加減乗除を実装するスレなのかと思った。
0025デフォルトの名無しさん
2007/11/24(土) 22:32:200026デフォルトの名無しさん
2007/11/24(土) 23:11:52じゃあ低速でいいからとっとと作れよ、簡単なんだろ。
高速化するのはその後でいいよ。
最低限、自分の発言に責任を持て。
0027デフォルトの名無しさん
2007/11/25(日) 00:32:341がDQNあつかいされてるな。
フーリエ変換って、多倍長乗算やCTとか、
周波数とか関係のない、意外なとこで利用されてるから面白いよね。
0028デフォルトの名無しさん
2007/11/25(日) 02:31:310029デフォルトの名無しさん
2007/11/25(日) 14:53:532ちゃんねるに書き込んだものってひろゆきが権利持つんじゃないだろうか。
00301
2007/11/25(日) 14:54:26可換環Rに対して、次を満たす要素eが存在するとする
・ eは1の原始n+1乗根 (すなわち、eのn+1乗は1かつ、n乗以下では1ではない)
・ kがn以下ならば、 Σ( i, 0, n) E(k) ^ i =0 ただしE(k) =e^k
このとき、G={1,E(1),・・・,E(n)}は群をなす
GからRへの写像全体をC(e)と置くと、次のようにしてR上の有限次元ベクトル空間になる
内積を、(f,g)=Σ( i, 0, n) f( E(j)) g( E(-j))で定義すると、{λi}が正規直交基底を与える (ただしλi( E(j) )=E(jj))
さらにC(e)は次で与える積でR代数になる (f*g)( E(k)) = Σ( i, 0, n) f( E(k-i)) g( E(i))
R[X]の要素fに対して、C(e)の要素F(f)を次のように定義する F(f)( E(k)) = Σ( i, 0, n) f( E(i)) E(ki)
この対応はR代数として準同型写像を与える
これから導かれる 同型 R[X]/(X^(n+1) - 1) ≡ C(e) を離散フーリエ変換という
00311
2007/11/25(日) 15:00:24R[X]/(X^4-1) からC(2)への離散フーリエ変換が定義できる
0032デフォルトの名無しさん
2007/11/25(日) 18:34:53だからまずフーリエ変換を使わないプログラムを作るべきでは?
00331
2007/11/25(日) 18:54:30しかしフーリエで適用できるようにデータ構造は決めないと駄目なんです
00341
2007/11/25(日) 19:06:03可換環Rに対して、次を満たす要素eが存在するとする
・ eは1の原始n乗根
・ kがn未満ならば、 Σ( i, 0, n-1) E(k) ^ i =0 ただしE(k) =e^k
このときR[X]/(x^n - 1)の自己同型写像F
f → Σ( i, 0, n-1) f( E(i) ) X^i をフーリエ変換という
逆写像は、f → (1/n) Σ( i, 0, n-1) f( E(n-i) ) X^i で与えられる
このとき、畳み込み積 (f*g)( E(k)) = Σ( i, 0, n-1) f( E(k-i)) g( E(i))に対して F(fg) = F(f) * F(g)が成り立つ
X^s * X^t = X^s (s=t) or 0 (それ以外)を満たす この性質から畳み込み積の計算は簡単にできる
00351
2007/11/25(日) 19:09:5400361
2007/11/25(日) 19:55:32最大位数が大きいほど、計算できる桁数が上がります しかし、pが大きすぎると計算時間がかかります
どうやって最大位数の大きい元をみつけたらいいんでしょうか?
00371
2007/11/25(日) 20:00:5000381
2007/11/25(日) 20:06:43#include <iostream>
using namespace std;
main(){
int n,k,N,cnt;
for(N=(1<<16)-1;N>2;N--){
for(n=2;n*n<N;n++){k=N/n; if(k*n==N)break;}
if(n*n<=N)continue;
for(n=2;n<=N/2;n++){
k=n;
for(cnt=1;k!=1;cnt++){k*=n;if(k>N)for(;k>N;k-=N);}
if(cnt+1==N){cout<<"素数 "<<N<<"に対し要素"<<n<<"の位数は"<<cnt<<endl;break;}
}}}
00391
2007/11/25(日) 20:16:0700401
2007/11/25(日) 21:55:11p=2^16 + 1 とe=3とおく
f(X) = Σa_i ・X^i (a_i < 2^16) を多倍長整数とします
これをフーリエ変換すると、 Σf( e^i ) ・X^i になります
g(X)も多倍長整数とするとフーリエ変換はΣg( e^i ) ・X^i になります
fとgの畳み込み積は、 Σf( e^i ) g( e^i ) ・X^i となり
これをフーリエ逆変換すると、Σf( e^(p-1-i) ) g( e^((p-1-i)) ) ・X^i になります
この係数のうち、2^16であるものは桁上がりを処理して結果が出ます
00411
2007/11/25(日) 21:59:03f(1)g(1) 、 f(3)g(3)、 f(3^2)g(3^2)、・・・をmod pの範囲で求めれば良いだけです
0042デフォルトの名無しさん
2007/11/25(日) 22:14:09もし本当にそうなら47氏逮捕のときにひろゆきも逮捕されてるはず
00431
2007/11/25(日) 22:18:37Z/(p)での演算から 1/3 =21846
0044デフォルトの名無しさん
2007/11/25(日) 22:21:16馬鹿?
金子がWinnyの実装を2ちゃんに書き込んだかよ?
00451
2007/11/26(月) 14:47:41それは、2進数に対応させるんだ 例えば1024*1024のサイズのフーリエ変換ならば
0〜1023の2進数ごとに一定の手続きをすることで計算が完了する
00461
2007/11/26(月) 14:50:1600471
2007/11/26(月) 15:00:41サイズは2Nの、(Xi) = (ω^ij) (xi)というフーリエ変換は、
(X2i) = (ω^2ij) (xi+xN+i)
(X2i+1) = (ω^2ij+j) (xi+xN+iω^N)
に変換できる
これを繰り返したとき、Xの添え字、ωの指数、xの足し算の仕方を
000011101などの2進数から決定できる
0048デフォルトの名無しさん
2007/11/26(月) 15:03:1800491
2007/11/26(月) 16:36:20単純な総当たり掛け算より多いような気がする 特典は桁上がりの死よりが少ないだけでは?
00501
2007/11/26(月) 16:45:06Karatsuba法だとN^1.59だね やはり高速フーリエ変換が最速か
しかし、より詳細に求めると、 2N* log N + N だから、場合によってはN^1.59のほうが速いかもしれないね
0051デフォルトの名無しさん
2007/11/26(月) 17:01:0200521
2007/11/26(月) 17:37:49使い方分からないし、整数演算に使えるか分からないので自作してみるよ・・・
あと、自作使用した理由が、多倍長ライブラリのコンパイルが出来なかった為だったのだ
C++言語のみで、他のライブラリに依存しないで単体で動くと導入が簡単なのだ
00531
2007/11/26(月) 17:50:11たとえば
Lint x;
x=2;
for(int i; i<1000; i++)x=x*x;
x.printf();
としたとき xのサイズが自動で拡張されるようにしたいのですが
0054デフォルトの名無しさん
2007/11/26(月) 17:54:49それで性能上困ることがあれば、
自分でmalloc/free呼んだり、OSのメモリ確保APIを直接呼んだり、
それをメモリプールしてみたり。
00551
2007/11/26(月) 18:03:24vectorは速度的に速いと思うので、内部でvector使うことにします 自分で領域を動的に管理するとバグでやすいですし
00561
2007/11/26(月) 18:25:05a = x + y という演算子を定義するとき、x+y演算と、代入演算を分離するとしない場合より代入分
計算コストがかかると思うのですが、tasu(&a, &x, &y)という関数と同じように定義することは出来ないですか?
これなら計算結果を直接格納できるのですが
0057デフォルトの名無しさん
2007/11/26(月) 18:41:310058デフォルトの名無しさん
2007/11/26(月) 18:41:4400591
2007/11/26(月) 19:00:39サンクス でも使い方分からなかったよ
なんか代入にかかる計算程度をケチっても
意味がある計算には変化なさそうなので知ってるやり方でやってみる
わざと、代入が多くなるような計算すれば違いが出るとはおもうけど
00601
2007/11/26(月) 20:21:12符号と数値を保存してあるとして、足し算が負になるか正になるかで計算を分類しなくていけない
00611
2007/11/26(月) 20:35:530062デフォルトの名無しさん
2007/11/26(月) 20:36:0400631
2007/11/26(月) 22:01:58http://kansai2channeler.hp.infoseek.co.jp/cgi-bin/joyful/img/5338.txt
0064デフォルトの名無しさん
2007/11/26(月) 22:10:52コメントとインデントつけてくれるとうれしいな
00651
2007/11/26(月) 22:19:29int fugou; //正負
vector< unsigned short int > a; //一区切りは2バイトのunsigned整数
Lint& operator=(Lint x); // Lint の代入
Lint& operator=(int x); //整数の代入
int operator>(Lint& x);
int operator<(Lint& x); //絶対値の比較
Lint operator+(Lint& x) //足し算
絶対値の大きい方を先頭にして、残りの数値を引いたり足したりする
00661
2007/11/26(月) 22:24:20x / y = x * (1/y) だから1/yを求められればよい
すると、符号の他に小数(の位置)を記録する必要がある
ニュートン法で1/yを計算するのが良いらしいけど
有効桁数までもとめ続けた方が良いのだろうか
0067デフォルトの名無しさん
2007/11/26(月) 22:28:460068デフォルトの名無しさん
2007/11/26(月) 22:32:57あとFFTを理解するの面倒でスレを読んでないんだけど多倍長整数みたいなもんだよね?
Lint& operator=(int x)を見る限り4294967296までしか行けそうにないけど、俺が馬鹿なだけ?
0069デフォルトの名無しさん
2007/11/26(月) 22:37:30歌ってるのか?
0070デフォルトの名無しさん
2007/11/26(月) 22:40:55どうでもいいからやんわりと書こうとしただけで洒落ようとかこれっぽっちも思ってなかったのにorz
0071デフォルトの名無しさん
2007/11/26(月) 23:30:130072デフォルトの名無しさん
2007/11/26(月) 23:33:550073デフォルトの名無しさん
2007/11/26(月) 23:38:38FFTWとかFFTEより速いもんが出来上がる訳もないわな。
ついでにその整数環FFT使った多倍長乗算は普通のFFTの物より遅いでFA出てた筈。
プロセッサの設計・製造からやるんなら話が違うかもしれんがね。
0074デフォルトの名無しさん
2007/11/26(月) 23:48:06しーっ、リバーシスレのようになるから触っちゃダメ。
00751
2007/11/26(月) 23:49:350076デフォルトの名無しさん
2007/11/26(月) 23:52:070077デフォルトの名無しさん
2007/11/26(月) 23:54:49ところでoperator +=は?
そっち作った後、それを使って残りを定義するのが普通。
More effective C++ 22項
Lint operator +(Lint const& x, Lint const& y)
{
return Lint(x) += y;
}
あと、operator<はreturn x > *this;で十分なはず。
さらに!(*this < x)でoperator >=、!(*this > x)でoperator <=も実装できる。
ついでにoperator ==とoperator !=も作ってしまえ。
単項operator +と-も今すぐできるはずだ。
欲を言えばswapが欲しい。
0078デフォルトの名無しさん
2007/11/26(月) 23:55:36やっぱりリバーシスレと同じ匂い感じた人がいたかw
00791
2007/11/27(火) 00:29:23あと逆数の計算方法の書いてあるサイトをのせます
1/n を求めるには
http://www.nextftp.com/swlabo/m0_pctech/hp_ultraprecision/up_820.htm
http://yowaken.dip.jp/tdiary/20070428.html
00801
2007/11/27(火) 01:13:47引数1つにしてくれというエラーが出ます
Lint operator +(Lint const& x, Lint const& y) { return Lint(x) += y; }
0081デフォルトの名無しさん
2007/11/27(火) 01:29:47応援するよ
00821
2007/11/27(火) 01:29:58+は他で使えます +を定義してから +=を定義する方向で行こうと思います
0083デフォルトの名無しさん
2007/11/27(火) 01:38:29うまくまとめてるサイトってないものかね?
http://www.nitoyon.com/vc/tips/multi_precision.htm
こんな感じのサンプル上がってるとこ見て、見よう見まねで実装してるんだけど・・・
00841
2007/11/27(火) 01:52:2800851
2007/11/27(火) 02:19:09http://kansai2channeler.hp.infoseek.co.jp/cgi-bin/joyful/img/5341.txt
00861
2007/11/27(火) 02:34:46opPostInc() {
int i,s=a.size();
for(i=0;i<s;i++){
if(a[i]==65535)a[i]=0;
else {a[i]++;break;}}
if(i==s){a.resize(s+1);a[s]=1;}}
00871
2007/11/27(火) 02:40:1900881
2007/11/27(火) 03:07:26Lint operator*(Lint & x){
Lint *p,*q;
if(*this > x){p=&x; q=this;} else {p=this; q=&x;}
int s,t,u;
s=(*p).a.size(); t=(*q).a.size(); u=s*t;
Lint y; y.a.resize(u+1,0);
if(sign + x.sign==0) y.sign=-1;
int i,n; unsigned w,k=0;
for(n=0; n < u; n++){
w=k; k=0;
for(i=0; i<=min(n,s); i++){
w += (*p).a[i] * (*q).a[n-i];
k+=(w>>16); w&=LIMIT;}
y.a[n]=w;}
if(k>0)y.a[u]=k; else y.a.resize(u,0);
return y;}
0089デフォルトの名無しさん
2007/11/27(火) 03:34:38ここを
a[i]==999999999
にすれば?
00901
2007/11/27(火) 03:53:38インクリメントの部分ですか? それはコードの中身ではなくて初めの宣言が違っていました
opPostInc() という名前はD言語用のインクリメントの宣言でした
2^16進数を10進表示にするにはどうしたらいいんだろう? 10で割ってその余りを出力していけばいいけど10で割るのが難しい
0091デフォルトの名無しさん
2007/11/27(火) 03:58:0500921
2007/11/27(火) 03:59:44小数点を導入して、値を1以下になるようにシフトさせてから10倍していきます
整数になった部分が最上位の10進表示になります それを0にして繰り返します
00931
2007/11/27(火) 05:44:19cout<< (x&65535)<<" "<<(x%65536);
この正解は10のはずなんですけど値が違います なぜでしょうか
00941
2007/11/27(火) 05:47:35int xx=4259850;
でした
0096デフォルトの名無しさん
2007/11/27(火) 07:36:290097デフォルトの名無しさん
2007/11/27(火) 13:33:2010000進の掛け算と足し算でできるのでは?
00981
2007/11/27(火) 16:00:47>>97 詳細を教えて下さい やっぱり割り算はいると思うのですが
xを表示するなら x%10を出力して、x=x/10として繰り返すという方法です
0099デフォルトの名無しさん
2007/11/27(火) 16:57:552進10進変換が10進多倍長の掛け算と足し算でできるということです。
0100デフォルトの名無しさん
2007/11/27(火) 17:00:06そのopeartor +は非メンバ関数。
swapはそれだと意味がない。代入より効率よく実装できる可能性があるからみんな定義する。
例えばstd::vectorなら、交換は内部のポインタを取り替えるだけで済む。
(代入ならメモリのコピーをしないといけない)
そしてswapという名前のメンバ関数にするのがお約束。
void swap(Lint& x) {
a.swap(x.a);
std::swap(sign, a.sign); //<algorithm>
}
そしてグローバルにもswapを定義しておく。
void swap(Lint& x, Lint& y) {
x.swap(y);
}
単項operator+と-はこういうメンバ関数でいい。
Lint opreotar +() const {
return *this;
}
Lint opreotar -() const {
Lint x = *this;
x.sign = -1;
return x;
}
っていうかコピーコンストラクタLint(Lint const& x)作れ。対称性からLint(int x)も欲しい。
>>98
こういう整数を十進法として出力するにはそれくらいしかないと思う。
0101デフォルトの名無しさん
2007/11/27(火) 17:14:17■ このスレッドは過去ログ倉庫に格納されています