CLang furcsasag

Mivel pinyo_villany olyan sokat irkal mostanaban a CLang-rol, kedvem tamadt kiprobalni. Fogtam is egy furcsasagot. Van egy ilyen kod, valahonnan a netrol:


#include <stdio.h>
#include <stdlib.h>

int main() {
    float x,y,i,a=0.0;
    int s;
    for(s=0; s<10000; s++) {
        x=1.*rand()/RAND_MAX;
        y=1.*rand()/RAND_MAX;
        i+=x*x+y*y<=1;
        printf("%lf\n",4*i/++a);
    }
}

Az egyetlen modositas benne, hogy a clang sirt az a inicializalatlansaga miatt, azt inicializaltam.

A pi kornyekerol szamol random szamokat. Egy tipikus kimenet reszlete ilyen:


3.172224
3.171906
3.171588
3.171671
3.171754
3.171837

A GCC-vel forditott binaris mindig ilyet general, a CLang-os viszont minden 3-5. futasnal ilyet:


-14799051161600.000000
-14797566377984.000000
-14796081594368.000000
-14794597859328.000000
-14793113075712.000000
-14791629340672.000000
-14790145605632.000000

Nem pasztazom be mind a tizezer szamot, ami kijon beloluk, a minta elteres szemmel lathato.

Mintha idofuggo lenne, ha pihentetem egy kicsit (nem futtatom a clang-os kodot), akkor neha eleve a hibas kimenettel indul, utana megjavul, neha viszont jo kimenettel indul.

Otlet?

Hozzászólások

Az i nincs inicializálva, talán amiatt van. Viszont ami érdekes, a clang nem szólt emiatt, de a gcc szólt, pedig a clang-tól is vártam volna, hogy szól miatta.

$ clang -v
clang version 3.0 (tags/RELEASE_30/final)
Target: i686-w64-mingw32
Thread model: posix
$ clang -Wall -Wextra -o testcl.exe test.c
nincs kimenet

$ gcc -Wall -Wextra -o testgcc.exe test.c
test.c: In function 'main':
test.c:13:1: warning: control reaches end of non-void function [-Wreturn-type]
test.c:10:11: warning: 'i' may be used uninitialized in this function [-Wuninitialized]

Nalam sem.


# gcc version 4.5.1 20101208 [gcc-4_5-branch revision 167585] (SUSE Linux) 

$ gcc -Wall -Wextra -o pi.o pi.c
pi.c: In function ‘main’:
pi.c:13:1: warning: control reaches end of non-void function

Hab a tortan, hogy a clang mintha a -Wreturn-type -re se lenne erzekeny, pedig ebben return aztan egy darab nincsen.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

a) ez nem az en kodom, en is csak ugy talaltam. Meg az algoritmust se igazan ertem, amit hasznal, viszont felettebb alkalmas C fordito tesztelesere. Erre hasznalom.
b) nem celom sem a kod karbantartasa sem a fejlesztese, egyszeruen csak erdekelt a problema
c) nem vagyok hardcore C programozo. Nekem mar az is eleg, ha a C fordito az altalam generalt kodra nem dob errort. Meg jobb, ha warningot sem. Hab a tortan, ha meg mukodik is a kod, ha pedig azt csinalja, amit szeretnek... nos, az szamomra a megtestesult tokely. Ilyen szinten vagyok C-bol.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

a) Nem olyan bonyolult. Az x^2+y^2<=1 az 1 sugarú, 0,0 középpontú "kitöltött" kör* egyenlete. Mivel az x és y csak a [0,1] intervallumon vesz fel értéket (de ott (elvileg) egyenletes eloszlású), ezért annak valószínűsége, hogy a kapott x, y koordináta a körön belülre esik, pi/4. Ha végtelenszer (megfelelően sokszor) növeljük i értékét, ha a kapott koordináta a körön belülre esik, és leosztjuk az iterációk számával (a-val, vagyis s+1-gyel), akkor épp pi/4-et kell, hogy kapjunk, aminek négyszerese pi.

* Ennek a kitöltött körnek mi a precíz, matematikai elnevezése?

@hrgy:
Így talán hasznosabb (a printf-et kivéve a belső ciklusból, és a végére tenni összegezve - idézőjelek nem kellenek, csak formázás miatt van). És akkor itt minél nagyobb a "c" értéke, annál pontosabb lesz a közelítés pi-hez ha jól gondolom:


const c = 100000;

int main() {
    float x,y,i,a=0.0;
    int s;
    for(s=0; s"<"c; s++) {
        x=1.*rand()/RAND_MAX;
        y=1.*rand()/RAND_MAX;
        i+=x*x+y*y<=1;
    }
    printf("%lf\n",4*i/c);
}

(Hogy lehet kiküszöbölni, hogy a code tag-en belüli formázást ne csessze szét a "<" jel?)

Csak tipp, mert tudom, hogy most tanulod a Ruby-t. Az egysoros blokkokhoz felesleges do/end -et hasznalni, oda siman jo a {} is. Egyre azonban figyelj, a {} mint blockwrapper nagyobbb precedenciaju, mint a {} mint hash-wrapper. A ketes esetekben mindig a blokk-definicioe az elsobbseg.

Tehat:


def doIt(options = {}); end

doIt { :foo => :bar } # Hiba
doIt({:foo => :bar}) # OK

Ugyanakkor:


(0..c).each { |i2| i += 1 if rand**2 + rand**2 <= 1 }

--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

Aha... most eljatszottam a koddal. Sajnos a valszam az nagyon kimaradt az eletembol... de valamit meg mindig nem ertek. Nem mindig pi jon ki a vegere, idonkent egy picit nagyobb szam jon, pl. 3.171 koruliek. Ez miert van?

Valamint ez a valszam resze se tiszta. Azert pi/4 a valoszinusege, hogy a pont a korlapon belul van, mert a kornek negy cikkelyebe eshet, es a korterulet pi? Kozben ezt a reszet megertettem.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

Persze hogy ingadozik, mivel véletlen bemenetre van alapozva.

Ha a random generátor eloszlása minél nagyobb elemszámot tekintve minél egyenletesebb, annál jobban fog közelíteni az értékhez a hányados. Futtasd le 1 vagy 10 milliószor a ciklust, meg egy srand(time(NULL)) paranccsal inicializáld minden futás előtt a random gen-t. Nagy elemszámnál a tört számlálója és nevezője is nagy lesz, ezért több tizedes jegyig lesz pontos.

Pontosan ugyanezért használtam decimalt C#-ban. A 28-29 értékes tizedesjegy (10-es számrendszerben) jól hangzik. Csak ehhez tényleg 100.000.000 iteráció kell.

Persze ezt a pontosságot nem fogja hozni a program, mert csak véges számú pontot tud "megcímezni" a véletlenszámgenerátor (nem végtelenül finom a felosztás). Szerintem ezért fluktuál neked is, bármennyire állítod az iterációszámot.

Fuszenecker_Róbert

> a clang sirt az a inicializalatlansaga miatt, azt inicializaltam.
:-O

dafuq did i just read

--
NetBSD - Simplicity is prerequisite for reliability