2011-01-06 3 views
2

私はUInt64値の大きな整数値に対して多少の作業をしていますが、Delphiにinteger square root関数があるかどうか疑問に思っていました。 今私はTrunc(Sqrt(x*1.0))を使用していますが、おそらくインラインアセンブラのスニペットで、よりパフォーマンスの高い方法が必要であると思いますか? (x:UInt64Sqrt(x)が故に*1.0ビット、D7で無効な型のコンパイラエラーがスローされます。)Delphiにはisqrtがありますか?

+0

に基づいて、私が使用して終了コード、うん、 '* 1.0'は、以降のバージョンで修正されました。それ以降のバージョンは確かではありませんが、D2010では正しく動作します。 –

答えて

10

私はアセンブリに関するエキスパートからは非常に遠いので、この回答は私をばかにしています。

function isqrt(const X: Extended): integer; 
asm 
    fld X 
    fsqrt 
    fistp @Result 
    fwait 
end; 

を限り、あなたは前isqrtを呼び出すには、「切り捨て」にFPU制御ワードの丸め設定を設定するよう:

しかし、これは動作しているようです。最も簡単な方法は、ヘルパー関数に

function SetupRoundModeForSqrti: word; 
begin 
    result := Get8087CW; 
    Set8087CW(result or $600); 
end; 

を定義するかもしれないと、あなたは

procedure TForm1.FormCreate(Sender: TObject); 
var 
    oldCW: word; 
begin 
    oldCW := SetupRoundModeForSqrti; // setup CW 
    // Compute a few million integer square roots using isqrt here 
    Set8087CW(oldCW); // restore CW 
end; 

テスト

これは本当に改善していパフォーマンスを行うことができますか?まあ、私は

procedure TForm1.FormCreate(Sender: TObject); 
var 
    oldCW: word; 
    p1, p2: Int64; 
    i: Integer; 
    s1, s2: string; 
const 
    N = 10000000; 
begin 
    oldCW := SetupRoundModeForSqrti; 

    QueryPerformanceCounter(p1); 
    for i := 0 to N do 
    Tag := isqrt(i); 
    QueryPerformanceCounter(p2); 
    s1 := inttostr(p2-p1); 

    QueryPerformanceCounter(p1); 
    for i := 0 to N do 
    Tag := trunc(Sqrt(i)); 
    QueryPerformanceCounter(p2); 
    s2 := inttostr(p2-p1); 

    Set8087CW(oldCW); 

    ShowMessage(s1 + #13#10 + s2); 
end; 

をテストし、その結果そこで

371802 
371774. 

を持って、それは単にそれだけの価値はありません。純粋なアプローチtrunc(sqrt(x))は、読んだり保守するのがはるかに簡単で、優れた将来性と後方互換性を持ち、エラーを起こしにくいです。

+0

とdownvoteの理由は? –

+0

@Andreas +1沈黙のダウンボッターを補う! –

+0

ああ、説明はもう必要ありません。それでは幸せな補償。 –

1

私は答えは何も、それは整数平方根機能を持っていないし、あなたのソリューションが合理的であるということではないと信じています。

私は浮動小数点値に変換するために1.0倍にする必要性に少し驚いています。私はそれがDelphiのバグでなければならないと思うし、最近のバージョンはあなたが望むように動作することは確かです。

+0

とdownvoteの理由は? (私は+1を "補償"します) –

+0

今、2^32マークを超えています。私はEInvalidOpを取得します:無効な浮動小数点演算が私のトリックに...私は実装に至っていると思いますisqrtをステップごとに計算する古いスキルのアルゴリズム... –

+0

@stijnあなたはuint64に戻っていますか? –

1

これはone of the algorhythms listed on wikipedia

type 
    baseint=UInt64;//or cardinal for the 32-bit version 
function isqrt(x:baseint):baseint; 
var 
    p,q:baseint; 
begin 
    //get highest power of four 
    p:=0; 
    q:=4; 
    while (q<>0) and (q<=x) do 
    begin 
    p:=q; 
    q:=q shl 2; 
    end; 
    // 
    q:=0; 
    while p<>0 do 
    begin 
    if x>=p+q then 
    begin 
     dec(x,p); 
     dec(x,q); 
     q:=(q shr 1)+p; 
    end 
    else 
     q:=q shr 1; 
    p:=p shr 2; 
    end; 
    Result:=q; 
end; 
関連する問題