2

EDIT下の私のコメントを参照してください(問題は解決されていません)。私のコードを試してみたい人は誰でもここでできます: http://tinker.io/e0676

EDIT2私は問題を見つけたと思います: http://www.geocomputation.org/1999/076/gc_076.htm何とか解決しようとします...

これが問題です。多角形の面積と周囲がある場合、面積/(周囲*周囲) の結果を取得することで、多角形が円にどれだけ近いかを測定できます。周囲を測定する方法を知っています:

function getPolySize(arrP){ //the first and last point in arrP is the same!
   var S = 0;
 for(var i=1, l=arrP.length;i<l;i++)
    S += Math.sqrt(Math.pow(arrP[i-1].x-arrP[i].x,2)+Math.pow(arrP[i-1].y-arrP[i].y,2));
return S;
}

そしてエリア:

function getPolyArea(arrP){
var A = 0;
for(var i=0,l=arrP.length-1;i<l;i++)
    A += arrP[i].x*arrP[i+1].y - arrP[i+1].x*arrP[i].y;
A = A/2;    
return Math.abs(A);
}

すべてが正常に機能しますが、できるだけ円に近いポリゴンを作成すると、奇妙な結果が得られ始めます。これを使用して円ポリゴンを作成します。

var arrCircle = [];
function setPixel(x,y){
arrCircle.push({x:x,y:y});
}
function rasterCircle(xCenter, yCenter, radius)
{       
var x, y, r2;
r2 = radius * radius;

for (x = -radius+1; x <= radius; x++){      
    y = Math.floor(Math.sqrt(r2 - x*x) + 0.5);
    setPixel(xCenter + x, yCenter + y);
}
for (x = radius-1; x >= -radius; x--) {
    y = Math.floor(Math.sqrt(r2 - x*x) + 0.5);
    setPixel(xCenter + x, yCenter - y);
}
}
arrCircle.push(arrCircle[0]);

半径が大きい円ポリゴンは、半径が小さい円ポリゴンよりも理想的な円に近いので、円が大きいほど面積/(周囲*周囲)が大きくなるはずですが、そうではないようで、私は理由がわからない。理想的な円の「真円度」は 1/4PI (0,07957747154594766788444188168626) です。(多角形のような円) でいくつかのテストを行いましたが、これらは私の結果でした:

radius 10 roundness 0.0760194950578244
radius 20 roundness 0.07542738445429042
radius 30 roundness 0.07549530319982335
radius 40 roundness 0.07472106160782283
radius 50 roundness 0.07490614579701928
radius 60 roundness 0.0750939048274632
radius 70 roundness 0.07502892726254591
radius 80 roundness 0.07512064515249058
radius 90 roundness 0.0752191417813967

では、なぜ増加するはずなのに減少するのでしょうか。誰でも助けることができますか?

4

3 に答える 3

1

これは、他の多くの言語と同様に JavaScript にも浮動小数点に関する問題があるためです。これは既知の問題です。あなたの最善の解決策は、数値を四捨五入することです。別のオプションは、代わりに大きな数を扱うことです。精度については、このライブラリをご覧ください: http://jsfromhell.com/classes/bignumber

あなたが数学に興味があり、より詳細に理解したい場合は、これをチェックしてください: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

于 2013-03-29T23:21:48.400 に答える
0

Jaycが提案したことをやろうとしましたが、それは大きな数字で使用しなかった場合にのみ機能し、小数点以下3桁しか変更されませんでした. 私の数字はすでに小数点以下第 3 位まで間違っています。

上記のように大きな数字も試してみましたが、それもうまくいきませんでした。https://github.com/MikeMcl/big.jsを DP = 40 (小数点以下の桁数) で使用しました。このライブラリは、上記で提案されたものとは異なり、sqrt を実行できます (上記は pow(0.5) も実行できませんでした)。

結果は次のとおりです。

radius 10 roundness 0.0760194950578243423134496712198170723197 
radius 20 roundness 0.0754273844542903459173216205506653687584 
radius 30 roundness 0.0754953031998234468551935482682038382823 
radius 40 roundness 0.0747210616078230319421955905769628317386 
radius 50 roundness 0.0749061457970194359965013537625645613175 
radius 60 roundness 0.0750939048274633950478066316279606244677 
radius 70 roundness 0.0750289272625461826452420199713700795491 
radius 80 roundness 0.0751206451524908473183103264150172570221 
radius 90 roundness 0.0752191417813970247297347505177938519628 

そして新しいコード:

var S = new Big(0);
var arr = [];
for(var i=1, l=arrP.length;i<l;i++){       
    var add = Math.pow(arrP[i-1].x-arrP[i].x,2)+Math.pow(arrP[i-1].y-arrP[i].y,2);      
    var x = new Big(add);       
    x = x.sqrt();
    arr.push(x);
    S = S.plus(x);
}

arr.sort(function(a,b){return a-b});
var c = new Big(0);
for(var i=0;i<arr.length;i++){
    var y = arr[i].minus(c);
    var t = S.plus(y);
    c = t.minus(S).minus(y);
    S = t;      
}

ここでは浮動小数点は問題ではないと思わざるを得ません。小数点以下 1000 桁 (!) でテストを試みたところ、上記とまったく同じ数値が得られました (少し長いだけですが、最初の 40 桁は同じです)。

他に何かが間違っていますが、何ですか?

于 2013-03-30T16:32:44.650 に答える