2010/02/10
lsl 多倍長演算
何に使うのか。。。といった風ですが(笑)、多倍長整数実数の演算です。
負数に対応しています(はずです。。。(笑))。
以下アルゴリズムです。
検索から飛んで来られる方がおられるようですが、こちらは32ビット符号付整数と(バグがあるとかないとか言う)単精度浮動小数点数しかないLSLという環境用です。乗算や除算には、メモリーが許せばもっと高速なアルゴリズムがあったと思います。
1:足し算引き算
筆算と同じです。9桁づつ文字列から取り出して計算し、繰上げ切り下げを次の桁で行います。
2:掛け算
筆算と同じです。3桁づつ文字列から取り出して計算し、9桁までの繰上げはその場で、10桁以降は次の桁計算に持ち越します。
3:割り算
筆算と同じです。ただし商を求める際に分母先頭8桁と分子先頭8桁を使って仮の商を算出し、手順を簡略化しています。
整数の割り算(longIntDiv())のみ、listが戻りになり、0番が商、1番が剰余になります。
longDiv()では戻りは商のみとなります。
// www.lsleditor.org by Alphons van der Heijden (SL: Alphons Jano)
//****************************************************************
//多倍長実数計算
//****************************************************************
//整数であるか調べ、符号かFALSEを返す
integer isInt(string s)
{
list l=["0","1","2","3","4","5","6","7","8","9","-"];
integer i=llStringLength(s);
if (!i) return FALSE;
if (s=="0") return FALSE;
if (s=="-0") return FALSE;
if (s=="-") return FALSE;
do
{
--i;
if (llListFindList(l,[llGetSubString(s,i,i)])<0) return FALSE;
} while (i);
if (llSubStringIndex(s,"-")==0) return -1;
return 1;
}
//実数であるか調べ、符号かFALSEを返す
integer isFloat(string s)
{
list l=["0","1","2","3","4","5","6","7","8","9","-","."];
integer i=llStringLength(s);
if (!i) return FALSE;
if (s=="0") return FALSE;
if (s=="-0") return FALSE;
if (s=="-") return FALSE;
do
{
--i;
if (llListFindList(l,[llGetSubString(s,i,i)])<0) return FALSE;
} while (i);
if (llSubStringIndex(s,"-")==0) return -1;
return 1;
}
//文字列先頭の指定文字を削除
string ltrim(string s, string t)
{
if (llGetSubString(s,0,0)!=t) return s;
integer i=0;
integer maxI=llStringLength(s);
if (!maxI) return s;
++maxI;
while(i<maxI)
{
++i;
if (llGetSubString(s,i,i)!=t) jump continue;
}
@continue;
return llGetSubString(s,i,maxI);
}
//文字列末尾の指定文字を削除
string rtrim(string s, string t)
{
if (llGetSubString(s,-1,-1)!=t) return s;
integer i=llStringLength(s);
if (!i) return s;
while(i--)
{
if (llGetSubString(s,i,i)!=t) jump continue;
}
@continue;
return llGetSubString(s,0,i);
}
//整数数値文字列の絶対値について大小比較
integer longIntAbsCmp(string a, string b)
{
a=ltrim(a,"-");
b=ltrim(b,"-");
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return 0;
if (a!="" && b=="") return 1;
if (a=="" && b!="") return -1;
if (a==b) return 0;
integer lA=llStringLength(a);
integer lB=llStringLength(b);
if (!lA && !lB) return 0;
if (lA>lB) return 1;
if (lA<lB) return -1;
integer i=0;
integer ia=0;
integer ib=0;
do
{
ia=(integer)llGetSubString(a,i,(i+8));
ib=(integer)llGetSubString(b,i,(i+8));
if (ia!=ib) jump continue;
i+=9;
} while(i<lA);
@continue;
if (ia>ib) return 1;
if (ia<ib) return -1;
return 0;
}
//****************************************************************
//足し算引き算
//****************************************************************
string longIntSum(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f1==0 && f2==0) return "0";
if (f1!=0 && f2==0) return a;
if (f1==0 && f2!=0) return b;
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return "0";
if (a!="" && b=="")
{
if (f1<0) return "-"+a;
return a;
}
if (a=="" && b!="")
{
if (f2<0) return "-"+b;
return b;
}
integer flag=1;
if (f1!=f2) flag=-1;
integer f3=longIntAbsCmp(a,b);
string rflag="";
if (f3==0 && flag==-1) return "0";
if (f3<0)
{
if (f2<0) rflag="-";
string c=a;
a=b;
b=c;
integer tmp=f2;
f1=f2;
f2=tmp;
}
else
{
if (f1<0) rflag="-";
}
//9ケタづつ加減算
integer lA=llStringLength(a)*-1;
integer lB=llStringLength(b)*-1;
integer k=0;
integer u=0;
string res="";
while(k>lA)
{
k-=9;
integer va=(integer)llGetSubString(a,k,k+8);
va=va+(integer)llGetSubString(b,k,k+8)*flag+u;
u=llFloor((float)va/1000000000.0);
va=llAbs(va-u*1000000000);
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<9)
{
l=8-l;
tmp=llGetSubString("000000000",0,l)+tmp;
}
res=tmp+res;
}
res=rflag+ltrim((string)u+res,"0");
if (res=="") return "0";
if (res=="-") return "0";
return res;
}
//****************************************************************
//掛け算
//****************************************************************
string longIntMul(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f1==0 || f2==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" || b=="") return "0";
if (b=="1")
{
if (f1*f2<0) return "-"+a;
return a;
}
if (a=="1")
{
if (f1*f2<0) return "-"+b;
return b;
}
//3ケタづつ乗算
integer lA=llStringLength(a)*-1;
integer lB=llStringLength(b)*-1;
integer i=0;
integer j=0;
integer k=0;
string res="";
integer of=0;
while(j>lB-3)
{
j-=3;
k=0;
while(k>lA)
{
k-=3;
integer va=(integer)llGetSubString(a,k,k+2);
va=va*(integer)llGetSubString(b,j,j+2)+of*1000000;
of=0;
i=k+j+3;
integer rlen=llStringLength(res);
if (rlen+i<0)
{
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<6)
{
l=5-l;
tmp=llGetSubString("000000",0,l)+tmp;
}
res=tmp+res;
}
else
{
va+=(integer)llGetSubString(res,i-6,i+2);
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<=9)
{
l=9-l;
if (l>0) tmp=llGetSubString("000000000",0,l-1)+tmp;
}
else
{
of=(integer)llGetSubString(tmp,0,l-9-1);
tmp=llGetSubString(tmp,l-9,l);
}
res=llGetSubString(res,rlen*-1+i-7,i-7)+tmp+llGetSubString(res,i+3,-1);
}
}
}
res=ltrim((string)of+res,"0");
if (res=="") return "0";
if (res=="0") return "0";
if (f1*f2>0)
{
return res;
}
else
{
return "-"+res;
}
}
//****************************************************************
//整数の割り算
//****************************************************************
list longIntDiv(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f2==0) return ["INFINITY","0"];
if (f1==0) return ["0",b];
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (b=="") return ["INFINITY","0"];
if (a=="")
{
if (f2<0) return ["0","-"+b];
return ["0",b];
}
//6桁以下の分子なら通常計算して終わる
if (llStringLength(a)<=6)
{
if (longIntAbsCmp(b,a)>0)
{
return ["0",a];
}
else
{
return [llFloor((float)a/(float)b),(integer)a % (integer)b];
}
}
integer lA=llStringLength(a);
integer lB=llStringLength(b);
if (lB>lA) return ["0",a];
if (longIntAbsCmp(a,b)<0) return ["0",a];
integer i=0;
integer j=0;
integer k=0;
string res="";
string mod="0";
string zero="0";
integer B1ToB8=(integer)llGetSubString(b,0,7);
//初期化
string A=llGetSubString(a,0,lB-1);
a=llGetSubString(a,lB,lB+lA);
if (longIntAbsCmp(A,b)<0)
{
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
}
//除算
do
{
integer q=0;
while (!q)
{
integer A1ToA8OrA9=(integer)llGetSubString(A,0,7);
if (llStringLength(A)>7)
{
if (A1ToA8OrA9<B1ToB8)
{
A1ToA8OrA9=A1ToA8OrA9*10+(integer)llGetSubString(A,8,8);
}
}
q=llFloor((float)A1ToA8OrA9/(float)B1ToB8);
if (!q)
{
if (a=="")
{
res=res+zero;
mod=A;
jump continue;
}
res=res+"0";
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
}
}
string bq;
integer test=-1;
while(q>0)
{
if (lB<8)
{
bq=(string)((integer)b*q);
mod=(string)((integer)A-(integer)bq);
test=0;
}
else
{
if (q==1)
{
//仮の商が1。桁が一桁違う場合がありうる。
if (llStringLength(A)>llStringLength(bq))
{
q=10;
while(--q)
{
bq=longIntMul(b,(string)q);
test=longIntAbsCmp(A,bq);
if (test>=0) jump continue3;
}
}
bq=longIntMul(b,(string)q);
@continue3;
}
else
{
bq=longIntMul(b,(string)q);
}
}
if (test==-1) test=longIntAbsCmp(A,bq);
if (test<0)
{
--q;
bq=longIntMul(b,(string)q);
test=longIntAbsCmp(A,bq);
if (test>=0)
{
res=res+(string)q;
jump continue2;
}
}
else
{
res=res+(string)q;
jump continue2;
}
}
@continue2;
if (q<=0)
{
mod=A;
jump continue;
}
zero="";
if (a!="") zero="0";
mod=ltrim(longIntSum(A,"-"+bq),"0");
//次の数字
integer modLen=llStringLength(mod);
A=mod;
if (modLen<lB)
{
integer m=lB-modLen;
integer an=llStringLength(a);
if (an>0)
{
if (m>an) m=an;
while(--m)
{
res=res+"0";
}
m=lB-modLen;
A=A+llGetSubString(a,0,m-1);
a=llGetSubString(a,m,lB+lA);
}
}
if (longIntAbsCmp(A,b)<0)
{
if (a!="")
{
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
if (modLen<lB)
{
res=res+"0";
}
}
else
{
res=res+zero;
jump continue;
}
}
if (llStringLength(A)<lB)
{
res=res+zero;
mod=A;
jump continue;
}
} while(TRUE);
@continue;
res=ltrim(res,"0");
mod=ltrim(mod,"0");
if (mod=="") mod="0";
if (f1*f2<0) res="-"+res;
if (f1<0 && mod!="0") mod="-"+mod;
if (res=="") res="0";
return [res,mod];
}
//****************************************************************
//実数の多倍長加減算
//****************************************************************
string longSum(string a,string b)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f1==0 && f2==0) return "0";
if (f1!=0 && f2==0) return a;
if (f1==0 && f2!=0) return b;
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return "0";
if (a!="" && b=="")
{
if (f1<0) return "-"+a;
return a;
}
if (a=="" && b!="")
{
if (f2<0) return "-"+b;
return b;
}
//準備
//小数点以下が長いほうにあわせて桁移動して整数化。
integer la=llStringLength(a);
integer lb=llStringLength(b);
integer pa=llSubStringIndex(a,".");
integer pb=llSubStringIndex(b,".");
integer digit;
if (pa!=-1 || pb!=-1)
{
if (pa!=la-1 || pb!=lb-1)
{
if (pa==-1)
{
pa=la;
++la;
a=a+".";
}
if (pb==-1)
{
pb=lb;
++lb;
b=b+".";
}
digit=la-pa;
if (lb-pb>digit)
{
digit=lb-pb-digit;
while(digit--)
{
a=a+"0";
}
}
else
{
digit=digit-(lb-pb);
while(digit--)
{
b=b+"0";
}
}
}
a=(string)llParseString2List(a,["."],[]);
b=(string)llParseString2List(b,["."],[]);
}
if (f1<0)
{
a="-"+a;
}
if (f2<0)
{
b="-"+b;
}
string res=longIntSum(a,b);
digit=la-pa;
if (lb-pb>digit)
{
digit=lb-pb;
}
--digit;
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
la=llStringLength(res);
string tmp="";
if (llSubStringIndex(res,"-")==0)
{
tmp="-";
res=llGetSubString(res,1,-1);
--la;
}
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
pa=la-digit;
res=llInsertString(res,pa,".");
}
return tmp+res;
}
//****************************************************************
//実数の多倍長乗算
//****************************************************************
string longMul(string a,string b)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f1==0 || f2==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" || b=="") return "0";
//準備
//小数点以下の長さを記憶しておく。
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
integer digit=llStringLength(a)-llSubStringIndex(a,".")+llStringLength(b)-llSubStringIndex(b,".")-2;
a=(string)llParseString2List(a,["."],[]);
b=(string)llParseString2List(b,["."],[]);
string res=longIntMul(a,b);
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
integer la=llStringLength(res);
if (llSubStringIndex(res,"-")==0)
{
res=llGetSubString(res,1,-1);
--la;
}
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
integer pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
integer pa=la-digit;
res=llInsertString(res,pa,".");
}
if (f1*f2>0)
{
return res;
}
else
{
return "-"+res;
}
}
//****************************************************************
//実数の多倍長割り算
//第一引数:分子(被除数)
//第二引数:分母(除数)
//第3引数は小数点以下の桁数を指定
//****************************************************************
string longDiv(string a, string b,integer digit)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f2==0) return "INFINITY";
if (f1==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (b=="") return "INFINITY";
if (a=="") return "0";
//準備 / 分子分母の整数化
integer pa=llSubStringIndex(a,".");
integer la=llStringLength(a);
if (pa==0)
{
a="0"+a;
pa=1;
++la;
}
if (pa==-1)
{
pa=la;
a=a+".";
++la;
}
integer pb=llSubStringIndex(b,".");
integer lb=llStringLength(b);
if (pb==-1)
{
pb=lb;
++lb;
}
else if (pb==0)
{
pb=1;
++lb;
}
//分子小数点以下に希望の桁数を追加
integer i=digit-(lb-pb-1);
if (i<0)
{
//小数点以下が長すぎる
b=llGetSubString(b,0,pb+digit);
lb=llStringLength(b);
pb=llSubStringIndex(b,".");
}
i=digit-(la-pa-1);
if (i<0)
{
//小数点以下が長すぎる
i=0;
a=llGetSubString(a,0,pa+digit);
la=llStringLength(a);
pa=llSubStringIndex(a,".");
}
if (la-pa<lb-pb) i=i+lb-pb-la+pa;
while(i--)
{
a=a+"0";
}
if (pb>=0)
{
//分母に小数点。
//分母を整数にし、分子の小数点を移動
b=(string)llParseString2List(b,["."],[]);
integer p=lb-pb-1;
string floatA=llGetSubString(a,pa+1,-1);
a=llGetSubString(a,0,pa-1)+llInsertString(floatA,p,".");
}
//桁数の補正
//digitより小数点以下の数が少なければ追加
pa=digit-(llStringLength(a)-llSubStringIndex(a,".")-1);
if (pa>0)
{
do
{
a=a+"0";
}while(--pa);
}
a=(string)llParseString2List(a,["."],[]);
//計算実行
string res=llList2String(longIntDiv(a,b),0);
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
la=llStringLength(res);
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
pa=la-digit;
res=llInsertString(res,pa,".");
}
if (f1*f2<0) res="-"+res;
return res;
}
//****************************************************************
//多倍長計算関連おしまい
//****************************************************************
default
{
state_entry()
{
llResetTime();
llOwnerSay(longSum("-0.0960866054","-0.0452746054"));
llOwnerSay((string)llGetTime());
llResetTime();
llOwnerSay(longMul("0.0960866054","-1.0452746054"));
llOwnerSay((string)llGetTime());
llResetTime();
llOwnerSay(longDiv("2304.0960866054","0.0452746054",20));
llOwnerSay((string)llGetTime());
}
}
負数に対応しています(はずです。。。(笑))。
以下アルゴリズムです。
検索から飛んで来られる方がおられるようですが、こちらは32ビット符号付整数と(バグがあるとかないとか言う)単精度浮動小数点数しかないLSLという環境用です。乗算や除算には、メモリーが許せばもっと高速なアルゴリズムがあったと思います。
1:足し算引き算
筆算と同じです。9桁づつ文字列から取り出して計算し、繰上げ切り下げを次の桁で行います。
2:掛け算
筆算と同じです。3桁づつ文字列から取り出して計算し、9桁までの繰上げはその場で、10桁以降は次の桁計算に持ち越します。
3:割り算
筆算と同じです。ただし商を求める際に分母先頭8桁と分子先頭8桁を使って仮の商を算出し、手順を簡略化しています。
整数の割り算(longIntDiv())のみ、listが戻りになり、0番が商、1番が剰余になります。
longDiv()では戻りは商のみとなります。
2010/4/28:追記および変更
サンプルを削除しました。
バグを修正し、実数計算を追加しました。
小数点を一旦消して整数計算して戻しているだけですが、高次の連立方程式用として現在試験中です。
桁数の管理や精度はかなりいい加減です。加減乗算では小数点以下の桁数を管理しておらず、割り算では桁数が多すぎると無条件に切り捨てていますので。。。^^;
また、いちいち文字列から部分を抜き出していますが、あらかじめlistに桁あふれしない長さの整数で格納しておくほうが高速に動作するはずです。(listはメモリー的に不利ですから。。。)
サンプルを削除しました。
バグを修正し、実数計算を追加しました。
小数点を一旦消して整数計算して戻しているだけですが、高次の連立方程式用として現在試験中です。
桁数の管理や精度はかなりいい加減です。加減乗算では小数点以下の桁数を管理しておらず、割り算では桁数が多すぎると無条件に切り捨てていますので。。。^^;
また、いちいち文字列から部分を抜き出していますが、あらかじめlistに桁あふれしない長さの整数で格納しておくほうが高速に動作するはずです。(listはメモリー的に不利ですから。。。)
// www.lsleditor.org by Alphons van der Heijden (SL: Alphons Jano)
//****************************************************************
//多倍長実数計算
//****************************************************************
//整数であるか調べ、符号かFALSEを返す
integer isInt(string s)
{
list l=["0","1","2","3","4","5","6","7","8","9","-"];
integer i=llStringLength(s);
if (!i) return FALSE;
if (s=="0") return FALSE;
if (s=="-0") return FALSE;
if (s=="-") return FALSE;
do
{
--i;
if (llListFindList(l,[llGetSubString(s,i,i)])<0) return FALSE;
} while (i);
if (llSubStringIndex(s,"-")==0) return -1;
return 1;
}
//実数であるか調べ、符号かFALSEを返す
integer isFloat(string s)
{
list l=["0","1","2","3","4","5","6","7","8","9","-","."];
integer i=llStringLength(s);
if (!i) return FALSE;
if (s=="0") return FALSE;
if (s=="-0") return FALSE;
if (s=="-") return FALSE;
do
{
--i;
if (llListFindList(l,[llGetSubString(s,i,i)])<0) return FALSE;
} while (i);
if (llSubStringIndex(s,"-")==0) return -1;
return 1;
}
//文字列先頭の指定文字を削除
string ltrim(string s, string t)
{
if (llGetSubString(s,0,0)!=t) return s;
integer i=0;
integer maxI=llStringLength(s);
if (!maxI) return s;
++maxI;
while(i<maxI)
{
++i;
if (llGetSubString(s,i,i)!=t) jump continue;
}
@continue;
return llGetSubString(s,i,maxI);
}
//文字列末尾の指定文字を削除
string rtrim(string s, string t)
{
if (llGetSubString(s,-1,-1)!=t) return s;
integer i=llStringLength(s);
if (!i) return s;
while(i--)
{
if (llGetSubString(s,i,i)!=t) jump continue;
}
@continue;
return llGetSubString(s,0,i);
}
//整数数値文字列の絶対値について大小比較
integer longIntAbsCmp(string a, string b)
{
a=ltrim(a,"-");
b=ltrim(b,"-");
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return 0;
if (a!="" && b=="") return 1;
if (a=="" && b!="") return -1;
if (a==b) return 0;
integer lA=llStringLength(a);
integer lB=llStringLength(b);
if (!lA && !lB) return 0;
if (lA>lB) return 1;
if (lA<lB) return -1;
integer i=0;
integer ia=0;
integer ib=0;
do
{
ia=(integer)llGetSubString(a,i,(i+8));
ib=(integer)llGetSubString(b,i,(i+8));
if (ia!=ib) jump continue;
i+=9;
} while(i<lA);
@continue;
if (ia>ib) return 1;
if (ia<ib) return -1;
return 0;
}
//****************************************************************
//足し算引き算
//****************************************************************
string longIntSum(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f1==0 && f2==0) return "0";
if (f1!=0 && f2==0) return a;
if (f1==0 && f2!=0) return b;
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return "0";
if (a!="" && b=="")
{
if (f1<0) return "-"+a;
return a;
}
if (a=="" && b!="")
{
if (f2<0) return "-"+b;
return b;
}
integer flag=1;
if (f1!=f2) flag=-1;
integer f3=longIntAbsCmp(a,b);
string rflag="";
if (f3==0 && flag==-1) return "0";
if (f3<0)
{
if (f2<0) rflag="-";
string c=a;
a=b;
b=c;
integer tmp=f2;
f1=f2;
f2=tmp;
}
else
{
if (f1<0) rflag="-";
}
//9ケタづつ加減算
integer lA=llStringLength(a)*-1;
integer lB=llStringLength(b)*-1;
integer k=0;
integer u=0;
string res="";
while(k>lA)
{
k-=9;
integer va=(integer)llGetSubString(a,k,k+8);
va=va+(integer)llGetSubString(b,k,k+8)*flag+u;
u=llFloor((float)va/1000000000.0);
va=llAbs(va-u*1000000000);
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<9)
{
l=8-l;
tmp=llGetSubString("000000000",0,l)+tmp;
}
res=tmp+res;
}
res=rflag+ltrim((string)u+res,"0");
if (res=="") return "0";
if (res=="-") return "0";
return res;
}
//****************************************************************
//掛け算
//****************************************************************
string longIntMul(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f1==0 || f2==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" || b=="") return "0";
if (b=="1")
{
if (f1*f2<0) return "-"+a;
return a;
}
if (a=="1")
{
if (f1*f2<0) return "-"+b;
return b;
}
//3ケタづつ乗算
integer lA=llStringLength(a)*-1;
integer lB=llStringLength(b)*-1;
integer i=0;
integer j=0;
integer k=0;
string res="";
integer of=0;
while(j>lB-3)
{
j-=3;
k=0;
while(k>lA)
{
k-=3;
integer va=(integer)llGetSubString(a,k,k+2);
va=va*(integer)llGetSubString(b,j,j+2)+of*1000000;
of=0;
i=k+j+3;
integer rlen=llStringLength(res);
if (rlen+i<0)
{
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<6)
{
l=5-l;
tmp=llGetSubString("000000",0,l)+tmp;
}
res=tmp+res;
}
else
{
va+=(integer)llGetSubString(res,i-6,i+2);
string tmp=(string)va;
integer l=llStringLength(tmp);
if (l<=9)
{
l=9-l;
if (l>0) tmp=llGetSubString("000000000",0,l-1)+tmp;
}
else
{
of=(integer)llGetSubString(tmp,0,l-9-1);
tmp=llGetSubString(tmp,l-9,l);
}
res=llGetSubString(res,rlen*-1+i-7,i-7)+tmp+llGetSubString(res,i+3,-1);
}
}
}
res=ltrim((string)of+res,"0");
if (res=="") return "0";
if (res=="0") return "0";
if (f1*f2>0)
{
return res;
}
else
{
return "-"+res;
}
}
//****************************************************************
//整数の割り算
//****************************************************************
list longIntDiv(string a, string b)
{
integer f1=isInt(a);
integer f2=isInt(b);
if (f2==0) return ["INFINITY","0"];
if (f1==0) return ["0",b];
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (b=="") return ["INFINITY","0"];
if (a=="")
{
if (f2<0) return ["0","-"+b];
return ["0",b];
}
//6桁以下の分子なら通常計算して終わる
if (llStringLength(a)<=6)
{
if (longIntAbsCmp(b,a)>0)
{
return ["0",a];
}
else
{
return [llFloor((float)a/(float)b),(integer)a % (integer)b];
}
}
integer lA=llStringLength(a);
integer lB=llStringLength(b);
if (lB>lA) return ["0",a];
if (longIntAbsCmp(a,b)<0) return ["0",a];
integer i=0;
integer j=0;
integer k=0;
string res="";
string mod="0";
string zero="0";
integer B1ToB8=(integer)llGetSubString(b,0,7);
//初期化
string A=llGetSubString(a,0,lB-1);
a=llGetSubString(a,lB,lB+lA);
if (longIntAbsCmp(A,b)<0)
{
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
}
//除算
do
{
integer q=0;
while (!q)
{
integer A1ToA8OrA9=(integer)llGetSubString(A,0,7);
if (llStringLength(A)>7)
{
if (A1ToA8OrA9<B1ToB8)
{
A1ToA8OrA9=A1ToA8OrA9*10+(integer)llGetSubString(A,8,8);
}
}
q=llFloor((float)A1ToA8OrA9/(float)B1ToB8);
if (!q)
{
if (a=="")
{
res=res+zero;
mod=A;
jump continue;
}
res=res+"0";
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
}
}
string bq;
integer test=-1;
while(q>0)
{
if (lB<8)
{
bq=(string)((integer)b*q);
mod=(string)((integer)A-(integer)bq);
test=0;
}
else
{
if (q==1)
{
//仮の商が1。桁が一桁違う場合がありうる。
if (llStringLength(A)>llStringLength(bq))
{
q=10;
while(--q)
{
bq=longIntMul(b,(string)q);
test=longIntAbsCmp(A,bq);
if (test>=0) jump continue3;
}
}
bq=longIntMul(b,(string)q);
@continue3;
}
else
{
bq=longIntMul(b,(string)q);
}
}
if (test==-1) test=longIntAbsCmp(A,bq);
if (test<0)
{
--q;
bq=longIntMul(b,(string)q);
test=longIntAbsCmp(A,bq);
if (test>=0)
{
res=res+(string)q;
jump continue2;
}
}
else
{
res=res+(string)q;
jump continue2;
}
}
@continue2;
if (q<=0)
{
mod=A;
jump continue;
}
zero="";
if (a!="") zero="0";
mod=ltrim(longIntSum(A,"-"+bq),"0");
//次の数字
integer modLen=llStringLength(mod);
A=mod;
if (modLen<lB)
{
integer m=lB-modLen;
integer an=llStringLength(a);
if (an>0)
{
if (m>an) m=an;
while(--m)
{
res=res+"0";
}
m=lB-modLen;
A=A+llGetSubString(a,0,m-1);
a=llGetSubString(a,m,lB+lA);
}
}
if (longIntAbsCmp(A,b)<0)
{
if (a!="")
{
A=A+llGetSubString(a,0,0);
a=llGetSubString(a,1,lB+lA);
if (modLen<lB)
{
res=res+"0";
}
}
else
{
res=res+zero;
jump continue;
}
}
if (llStringLength(A)<lB)
{
res=res+zero;
mod=A;
jump continue;
}
} while(TRUE);
@continue;
res=ltrim(res,"0");
mod=ltrim(mod,"0");
if (mod=="") mod="0";
if (f1*f2<0) res="-"+res;
if (f1<0 && mod!="0") mod="-"+mod;
if (res=="") res="0";
return [res,mod];
}
//****************************************************************
//実数の多倍長加減算
//****************************************************************
string longSum(string a,string b)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f1==0 && f2==0) return "0";
if (f1!=0 && f2==0) return a;
if (f1==0 && f2!=0) return b;
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" && b=="") return "0";
if (a!="" && b=="")
{
if (f1<0) return "-"+a;
return a;
}
if (a=="" && b!="")
{
if (f2<0) return "-"+b;
return b;
}
//準備
//小数点以下が長いほうにあわせて桁移動して整数化。
integer la=llStringLength(a);
integer lb=llStringLength(b);
integer pa=llSubStringIndex(a,".");
integer pb=llSubStringIndex(b,".");
integer digit;
if (pa!=-1 || pb!=-1)
{
if (pa!=la-1 || pb!=lb-1)
{
if (pa==-1)
{
pa=la;
++la;
a=a+".";
}
if (pb==-1)
{
pb=lb;
++lb;
b=b+".";
}
digit=la-pa;
if (lb-pb>digit)
{
digit=lb-pb-digit;
while(digit--)
{
a=a+"0";
}
}
else
{
digit=digit-(lb-pb);
while(digit--)
{
b=b+"0";
}
}
}
a=(string)llParseString2List(a,["."],[]);
b=(string)llParseString2List(b,["."],[]);
}
if (f1<0)
{
a="-"+a;
}
if (f2<0)
{
b="-"+b;
}
string res=longIntSum(a,b);
digit=la-pa;
if (lb-pb>digit)
{
digit=lb-pb;
}
--digit;
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
la=llStringLength(res);
string tmp="";
if (llSubStringIndex(res,"-")==0)
{
tmp="-";
res=llGetSubString(res,1,-1);
--la;
}
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
pa=la-digit;
res=llInsertString(res,pa,".");
}
return tmp+res;
}
//****************************************************************
//実数の多倍長乗算
//****************************************************************
string longMul(string a,string b)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f1==0 || f2==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (a=="" || b=="") return "0";
//準備
//小数点以下の長さを記憶しておく。
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
integer digit=llStringLength(a)-llSubStringIndex(a,".")+llStringLength(b)-llSubStringIndex(b,".")-2;
a=(string)llParseString2List(a,["."],[]);
b=(string)llParseString2List(b,["."],[]);
string res=longIntMul(a,b);
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
integer la=llStringLength(res);
if (llSubStringIndex(res,"-")==0)
{
res=llGetSubString(res,1,-1);
--la;
}
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
integer pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
integer pa=la-digit;
res=llInsertString(res,pa,".");
}
if (f1*f2>0)
{
return res;
}
else
{
return "-"+res;
}
}
//****************************************************************
//実数の多倍長割り算
//第一引数:分子(被除数)
//第二引数:分母(除数)
//第3引数は小数点以下の桁数を指定
//****************************************************************
string longDiv(string a, string b,integer digit)
{
if (llSubStringIndex(a,".")==-1) a=a+".";
if (llSubStringIndex(b,".")==-1) b=b+".";
a=rtrim(a,"0");
b=rtrim(b,"0");
integer f1=isFloat(a);
integer f2=isFloat(b);
if (f2==0) return "INFINITY";
if (f1==0) return "0";
if (f1<0)
{
a=llGetSubString(a,1,-1);
}
if (f2<0)
{
b=llGetSubString(b,1,-1);
}
a=ltrim(a,"0");
b=ltrim(b,"0");
if (b=="") return "INFINITY";
if (a=="") return "0";
//準備 / 分子分母の整数化
integer pa=llSubStringIndex(a,".");
integer la=llStringLength(a);
if (pa==0)
{
a="0"+a;
pa=1;
++la;
}
if (pa==-1)
{
pa=la;
a=a+".";
++la;
}
integer pb=llSubStringIndex(b,".");
integer lb=llStringLength(b);
if (pb==-1)
{
pb=lb;
++lb;
}
else if (pb==0)
{
pb=1;
++lb;
}
//分子小数点以下に希望の桁数を追加
integer i=digit-(lb-pb-1);
if (i<0)
{
//小数点以下が長すぎる
b=llGetSubString(b,0,pb+digit);
lb=llStringLength(b);
pb=llSubStringIndex(b,".");
}
i=digit-(la-pa-1);
if (i<0)
{
//小数点以下が長すぎる
i=0;
a=llGetSubString(a,0,pa+digit);
la=llStringLength(a);
pa=llSubStringIndex(a,".");
}
if (la-pa<lb-pb) i=i+lb-pb-la+pa;
while(i--)
{
a=a+"0";
}
if (pb>=0)
{
//分母に小数点。
//分母を整数にし、分子の小数点を移動
b=(string)llParseString2List(b,["."],[]);
integer p=lb-pb-1;
string floatA=llGetSubString(a,pa+1,-1);
a=llGetSubString(a,0,pa-1)+llInsertString(floatA,p,".");
}
//桁数の補正
//digitより小数点以下の数が少なければ追加
pa=digit-(llStringLength(a)-llSubStringIndex(a,".")-1);
if (pa>0)
{
do
{
a=a+"0";
}while(--pa);
}
a=(string)llParseString2List(a,["."],[]);
//計算実行
string res=llList2String(longIntDiv(a,b),0);
//戻り作成
//戻りの桁数がdigitより小さい場合冒頭に0.000・・・を追加
la=llStringLength(res);
if (la==digit)
{
res="0."+res;
}
else if (la<digit)
{
pa=digit-la;
while(pa--)
{
res="0"+res;
}
res="0."+res;
}
else
{
pa=la-digit;
res=llInsertString(res,pa,".");
}
if (f1*f2<0) res="-"+res;
return res;
}
//****************************************************************
//多倍長計算関連おしまい
//****************************************************************
default
{
state_entry()
{
llResetTime();
llOwnerSay(longSum("-0.0960866054","-0.0452746054"));
llOwnerSay((string)llGetTime());
llResetTime();
llOwnerSay(longMul("0.0960866054","-1.0452746054"));
llOwnerSay((string)llGetTime());
llResetTime();
llOwnerSay(longDiv("2304.0960866054","0.0452746054",20));
llOwnerSay((string)llGetTime());
}
}
Comments
Posted by グリ at 2010年02月11日 00:45
ながっ。w
>具
たぶん、おいしい(゜ω゜)w
>具
たぶん、おいしい(゜ω゜)w
Posted by Lieza at 2010年02月11日 10:51





それ美味しぃの?w