ab.com コミュニティ https://www.activebasic.com/forum/ |
|
QWord型とInt64型を操作する関数 https://www.activebasic.com/forum/viewtopic.php?t=916 |
ページ 1 / 1 |
作成者: | konisi [ 2006年4月05日(水) 06:29 ] |
記事の件名: | QWord型とInt64型を操作する関数 |
関数のソースコード [ここをクリックすると内容が表示されます] コード: Function StrForQWord$(qwd As QWord) As String Dim buffer[32] As Byte Dim i As Long Dim a As QWord Dim s=48 As Byte Dim buffer2[32] As Byte Dim I As Long Dim x As QWord Dim y As QWord i = 0 x = 10 y = 1 debug Do a = qwd Mod x buffer = Waru_QWord(a,y) + s As Byte qwd = qwd - a x = x * 10 y = y * 10 i = i + 1 Loop Until qwd = 0 buffer2 = 0 For I=1 To i buffer2(I-1)=buffer(i-I) Next I StrForQWord$ = MakeStr(buffer2) End Function Function Waru_QWord(A As QWord,B As QWord) As Byte Dim C As QWord Dim I As Byte Do C=A A=A-B If A>C then Exit Do I=I+1 Loop Waru_QWord=I End Function Function ValForQWordString(A$ As String) As QWord ValForQWordString=ValForQWord(StrPtr(A$)) End Function Function ValForQWord(pA As BytePtr) As QWord Dim I As Long Dim buffer(32) As Byte Dim A$ As String Dim x As QWord A$=MakeStr(pA) For I=0 To Len(A$)-1 buffer(I)=A$(I)-48 Next I x=1 For I=Len(A$)-1 To 0 Step -1 If buffer(I)>10 then Exit For ValForQWord = ValForQWord + Kakeru_QWord(buffer(I),x) x = x * 10 Next I End Function Function Kakeru_QWord(A As Byte,B As QWord) As QWord Dim C As QWord Dim I As Long C = 0 If A>1 then For I=1 To A C = C + B Next I Else C = B End If Kakeru_QWord = C End Function Sub InputForQWord(PrintString As String,fQuestion As Long,ByRef Inp As QWord) Dim A$ As String If fQuestion then Print PrintString+"?"; Else Print PrintString; End If Input A$ Inp=ValForQWordString(A$) End Sub Sub PrintForQWord(PrintQWord As QWord,fReturn As Long) Dim A$ As String A$=StrForQWord$(PrintQWord) If fReturn then Print A$ Else Print A$; End If End Sub Function StrForInt64$(it64 As Int64) As String Dim buffer[32] As Byte Dim i As Long Dim a As QWord Dim s=48 As Byte Dim buffer2[32] As Byte Dim I As Long Dim x As QWord Dim y As QWord Dim flag=0 As Long If it64<0 then flag=1 it64 = -1 * it64 End If i = 0 x = 10 y = 1 Do a = it64 Mod x buffer = Waru_Int64(a,y) + s it64 = it64 - a x = x * 10 y = y * 10 i = i + 1 Loop Until it64 = 0 buffer2 = 0 For I=1 To i buffer2(I-1)=buffer(i-I) Next I StrForInt64$ = MakeStr(buffer2) If flag=1 then StrForInt64$="-"+StrForInt64$ End If End Function Function Waru_Int64(A As Int64,B As Int64) As Byte Dim I As Byte Do A=A-B If 0>A then Exit Do I=I+1 Loop Waru_Int64=I End Function Function ValForInt64String(A$ As String) As Int64 ValForInt64String=ValForInt64(StrPtr(A$)) End Function Function ValForInt64(pA As BytePtr) As Int64 Dim I As Long Dim buffer(32) As Byte Dim A$ As String Dim x As Int64 A$=MakeStr(pA) For I=0 To Len(A$)-1 buffer(I)=A$(I)-48 Next I x=1 For I=Len(A$)-1 To 0 Step -1 If buffer(I)>10 then Exit For ValForInt64 = ValForInt64 + Kakeru_Int64(buffer(I),x) x = x * 10 Next I End Function Function Kakeru_Int64(A As Byte,B As Int64) As Int64 Dim C As QWord Dim I As Long C = 0 If A>1 then For I=1 To A C = C + B Next I Else C = B End If Kakeru_Int64 = C End Function Sub InputForInt64(PrintString As String,fQuestion As Long,ByRef Inp As Int64) Dim A$ As String If fQuestion then Print PrintString+"?"; Else Print PrintString; End If Input A$ Inp=ValForInt64String(A$) End Sub Sub PrintForInt64(PrintInt64 As Int64,fReturn As Long) Dim A$ As String A$=StrForInt64$(PrintInt64) If fReturn then Print A$ Else Print A$; End If End Sub 各関数の説明 ここをクリックすると各関数の説明が表示されます。 [ここをクリックすると内容が表示されます]
StrForQWord$(qwd As QWord) As String 第一パラメータ:String型にするためのQWord型変数を入れてください。 概要:指定した数値を文字列に変換します。 ValForQWordString(A$ As String) As QWord 第一パラメータ:QWord型にするためのString型変数を入れてください。 概要:指定した文字列を数値に変換します。 ValForQWord(pA As BytePtr) As QWord 第一パラメータ:QWord型にするための文字列ポインタを入れてください。 概要:指定した文字列ポインタにある文字列を数値に変換します。 InputForQWord(PrintString As String,fQuestion As Long,ByRef Inp As QWord) 第一パラメータ:質問時に表示する文字列を入れてください。 第二パラメータ:疑問符をつける場合はTRUEを、つけない場合はFALSEを入れてください。 第三パラメータ:返り値を格納するためのQWord型変数を入れてください。 注意:Promptディレクティブが読み込まれている必要があります。 概要:ユーザーからのデータ入力(数値)を受け付けます。 PrintForQWord(PrintQWord As QWord,fReturn As Long) 第一パラメータ:表示するQWord型変数を入れてください。 第二パラメータ:リターンする場合はTRUEを、しない場合はFALSEを入れてください。 注意:Promptディレクティブが読み込まれている必要があります。 概要:QWord型変数を表示します。 StrForInt64$(it64 As Int64) As String 第一パラメータ:Int64型にするためのQWord型変数を入れてください。 概要:指定した数値を文字列に変換します。 ValForInt64String(A$ As String) As Int64 第一パラメータ:Int64型にするためのString型変数を入れてください。 概要:指定した文字列を数値に変換します。 ValForInt64(pA As BytePtr) As Int64 第一パラメータ:Int64型にするための文字列ポインタを入れてください。 概要:指定した文字列ポインタにある文字列を数値に変換します。 InputForInt64(PrintString As String,fQuestion As Long,ByRef Inp As Int64) 第一パラメータ:質問時に表示する文字列を入れてください。 第二パラメータ:疑問符をつける場合はTRUEを、つけない場合はFALSEを入れてください。 第三パラメータ:返り値を格納するためのInt64型変数を入れてください。 注意:Promptディレクティブが読み込まれている必要があります。 概要:ユーザーからのデータ入力(数値)を受け付けます。 PrintForInt64(PrintInt64 As Int64,fReturn As Long) 第一パラメータ:表示するInt64型変数を入れてください。 第二パラメータ:リターンする場合はTRUEを、しない場合はFALSEを入れてください。 注意:Promptディレクティブが読み込まれている必要があります。 概要:Int64型変数を表示します。 ※ここに説明されていない関数は説明されている関数を支えるために設計されてある隠し関数です。よって直接使用する事を推奨しません。 QWord型とInt64型用に、Print,Input,Str$,Valの4関数を作ってみました。 バグや明らかな書き間違い、質問や意見など何かあったらどうぞ。 |
作成者: | konisi [ 2006年6月24日(土) 20:57 ] |
記事の件名: | |
QWord型とInt64型用の、掛け算と割り算と余り算(Mod)を作りました。 関数のソースコード [ここをクリックすると内容が表示されます]
各関数の説明 コード: Function Mul_ForQWord(A As QWord,B As QWord) As QWord Dim i As Long Dim Ret As QWord If B=0 then Mul_ForQWord=0 Exit Function End If If (B And 1)=1 then Ret=A else Ret=0 For i=0 To 62 B=B>>1 A=A<<1 If B=0 then Exit For If (B And 1)=1 then Ret=Ret+A Next i Mul_ForQWord=Ret End Function Function Mul_ForInt64(A As Int64,B As Int64) As Int64 Dim FlagA As Long,FlagB As Long Dim C As Int64 If A<0 then FlagA=1:A=0-A If B<0 then FlagB=1:B=0-B C=Mul_ForQWord(A As QWord,B As QWord) If FlagA=1 then C=0-C If FlagB=1 then C=0-C Mul_ForInt64=C End Function Function Div_ForQWord(A As QWord,B As QWord) As QWord 'Ret=A/B Dim i As Long,C As QWord,Ret As QWord If A<B then Div_ForQWord=0 Exit Function ElseIf A=B then Div_ForQWord=1 Exit Function ElseIf B=0 then '0除算は出来ません。 Div_ForQWord=&HFFFFFFFFFFFFFFFF debug Exit Function End If C=A i=0 Do i+=1 A=A>>1 If A<=B then Exit Do Loop If A=B then Div_ForQWord=1<<i Exit Function End If i-=1 C=C-(B<<i) Ret=1<<i While TRUE i-=1 A=C>>i If A>=B then Ret=Ret+(1<<i) C=C-(B<<i) End If If C=0 then Exit While End If If i=0 then Exit While Wend Div_ForQWord=Ret End Function Function Div_ForInt64(A As Int64,B As Int64) As Int64 Dim FlagA As Long,FlagB As Long Dim C As Int64 If A<0 then FlagA=1:A=0-A If B<0 then FlagB=1:B=0-B C=Div_ForQWord(A As QWord,B As QWord) If FlagA=1 then C=0-C If FlagB=1 then C=0-C Div_ForInt64=C End Function Function Mod_ForQWord(A As QWord,B As QWord) As QWord Mod_ForQWord=A-Mul_ForQWord(Div_ForQWord(A,B),B) End Function Function Mod_ForInt64(A As Int64,B As Int64) As Int64 Mod_ForInt64=A-Mul_ForInt64(Div_ForInt64(A,B),B) End Function ここをクリックすると各関数の説明が表示されます。 [ここをクリックすると内容が表示されます]
64ビット型の乗除算は、内部でDouble型に直してから行うらしく大きい数を行うとずれが生じます。
Mul_ForQWord(A As QWord,B As QWord) As QWord 第一引数:掛けられる数を指定します。 第二引数:掛ける数を指定します。 返り値:掛け算の結果が返ります。 備考:この関数では符号無し掛け算を行います。 Mul_ForInt64(A As Int64,B As Int64) As Int64 第一引数:掛けられる数を指定します。 第二引数:掛ける数を指定します。 返り値:掛け算の結果が返ります。 備考:この関数では符号有り掛け算を行います。ただし、少し手を抜いているので符号無し版を同時に定義しなければ使えません。 Div_ForQWord(A As QWord,B As QWord) As QWord 第一引数:割られる数を指定します。 第二引数:割る数を指定します。 返り値:割り算の結果が返ります。 備考:この関数では符号無し割り算を行います。 Div_ForInt64(A As Int64,B As Int64) As Int64 第一引数:割られる数を指定します。 第二引数:割る数を指定します。 返り値:割り算の結果が返ります。 備考:この関数では符号有り割り算を行います。ただし、少し手を抜いているので符号無し版を同時に定義しなければ使えません。 Mod_ForQWord(A As QWord,B As QWord) As QWord 第一引数:割られる数を指定します。 第二引数:割る数を指定します。 返り値:割り算の余りを返します。 備考:この関数では符号無し割り算を行います。 Mod_ForInt64(A As Int64,B As Int64) As Int64 第一引数:割られる数を指定します。 第二引数:割る数を指定します。 返り値:割り算の余りを返します。 備考:この関数では符号有り割り算を行います。 これらの関数ではシフト演算と加算減算のみの作業でこれらを行っているため、ずれは生じません。(ただし、普通に乗除算を行うより少し遅くなります。) |
作成者: | tak [ 2006年6月25日(日) 02:46 ] |
記事の件名: | |
64bit 版乗除算について このアルゴリズムでは、乗算は 63 回、除算では条件を満たすまで無限ループ(!)を行っていますが、実際は乗算ならば 4 回の乗算と 3 回の加算、また除算ならば2 回の除算と 1 回の加算、その他細々としたビット演算で計算可能です。 と言うわけで作ってみたのですが、AB が期待したとおりに動作しなかったり、地雷を踏みまくったりでそれらを回避するために酷いコードになったので、ここに挙げるのは遠慮させてもらいます(ぉ バグ報告レポートを作成していたのですが、結構な数になったのでくじけちまったorz |
作成者: | イグトランス [ 2006年6月25日(日) 09:25 ] |
記事の件名: | |
既に書いた分だけでもバグ報告へ出したほうがよいと思います。 ところで整数除算演算子 \ を使ったときだけは64ビット整数でも浮動小数点演算を使っていないようです。 効率はあまり良くなさそうですが。 |
作成者: | tak [ 2006年6月25日(日) 12:21 ] |
記事の件名: | |
自分はいったい何をしているのだろう?という疑問に駆られたので、コーディング作業を中断して覗いてみましたよ、EXE の中を。 そしたら地雷原や不審な挙動の原因が少しだけ判りました。それは後ほどバグ板に提出する方向で。 ここでは調査結果の一部を報告します。 > 64ビット型の乗除算は、内部でDouble型に直してから行うらしく こちらでは確認できませんでした。といっても QWord * QWord の組み合わせしか検証していませんが(汗 この現象が発生する条件を記してもらえればたすかります(バグ板で)。 なお QWord の乗算では、洗練された専用乗算ルーチンを使用して計算していました。 > ところで整数除算演算子 \ を使ったときだけは64ビット整数でも浮動小数点演算を使っていないようです。 > 効率はあまり良くなさそうですが。 こちらは確認できました。こちらも専用の関数を呼び出していますね。 効率は良くなさそうとのことですが、乗算関数同様に最適化されているように見えます。おそらく C++ が吐いたコードでしょうね。 |
作成者: | konisi [ 2006年6月25日(日) 19:08 ] |
記事の件名: | |
>>tak > 除算では条件を満たすまで無限ループ(!)を行っていますが 最高でも63回程度のはずです。(毎回iの数値を減算していって、i=0の時に抜け出すため。) > こちらでは確認できませんでした。といっても QWord * QWord の組み合わせしか検証していませんが(汗 調べたところ、乗算の場合はQWord型のまま行うみたいなのですが、除算の場合にDouble型を使用しているようです。 > 効率は良くなさそうとのことですが、乗算関数同様に最適化されているように見えます。 比較したいところでしたが、手元にあるOpcodes.hlp(機械語の速度の表みたいなやつ)に載っていない命令がいくつもあったので比較できません。 誰か次の物についてクロック数が分かる人は教えてください。 FILD,FDIVRP,FSTP,FLD,FNSTCW,OpdSz,FLDCW,FISTP,FLDCW 実数除算のほうにクロック数が分からない未知の命令語がこれだけあります。 お手上げですね^^; 分かる部分だけで38クロックです。 整数除算の方は分かるやつばっかりなのですぐに算出できました。 途中で後分岐のループが一個入ってますが、それをスルーしたとして166クロック~228クロック、ループを一回繰り返すごとに+16クロックです。 ちなみにこのループを使わない場合もあって、そちらは158クロックでした。 ところで、QWord型に対してインクリメントを行った時に変数の値が壊れたような気がしました。誰か試してみてください。 |
作成者: | S_K_ [ 2007年3月05日(月) 03:55 ] |
記事の件名: | バグ報告 |
Val関数にて、文字列中の「0」の部分が戻り値では「1」となるバグがあります。 隠し関数が原因のようなので、以下のように修正してみました。 コード: Function Kakeru_QWord(A As Byte,B As QWord) As QWord Dim C As QWord Dim I As Long C = 0 If A>0 then 'この行と For I=1 To A C = C + B Next I Else C = 0 'この行を修正 End If Kakeru_QWord = C End Function Function Kakeru_Int64(A As Byte,B As Int64) As Int64 Dim C As QWord Dim I As Long C = 0 If A>0 then '同じくこの行と For I=1 To A C = C + B Next I Else C = 0 'この行を修正 End If Kakeru_Int64 = C End Function |
ページ 1 / 1 | 全ての表示時間は UTC+09:00 です |
Powered by phpBB® Forum Software © phpBB Limited https://www.phpbb.com/ |