Sziasztok!
Adott az alábbi program. Ha n-et 11 millióra állítom, a program nem fut le, szegmentációs hibát jelent. 10 millió környékén még stabilan lefut. A határ a programban beállított érték környékén van; van amikor lefut, van amikor nem... Különböző hardvereken is ezt tapasztaltam, mindegyiken Ubuntu 10.10 volt, a tárolókban található gcc-vel.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
/*Addig dobalunk a kockaval, amig meg nem dobjuk mind a hat lehetoseget*/
void main()
{
unsigned long n,x;
float v,d;
n=10475400;
unsigned char a,e,q,w[6],s[n];
srand(time(NULL));
for(x=0; x<n; x++)
{
for(a=0; a<6; a++){w[a]=0;}
s[x]=0;
e=0;
while (e<6)
{
s[x]++;
q=rand()%6;
switch(q)
{
case 1:
w[1]=1;
break;
case 2:
w[2]=1;
break;
case 3:
w[3]=1;
break;
case 4:
w[4]=1;
break;
case 5:
w[5]=1;
break;
default:
w[0]=1;
break;
}
e=0;
for(a=0; a<6; a++){e+=w[a];}
}
}
v=0;
for(x=0; x<n; x++){v+=s[x];}
v=v/n;
d=0;
for(x=0; x<n; x++){d+=s[x]*s[x];}
d=sqrtf(d/n-v*v);
printf("%f\n%f\n", v,d);
}
Mit tehetnék, hogy nagyobb n-ekre is lefusson a program?
Hozzászólások
Ennyi memóriát dinamikusan kell foglalni.
+1
+1
Azt nem néztem meg, mit csinál a kód, mert nálam már a változóneveknél ledobta a láncot.
+1, es maris nem szall el. Azert szomoru hogy -Wall -nal sem futja egy warningra sem.
itt nem a programmal vagy a programkóddal volt a baj, hanem az elgondolással. Szegény gcc -Wall -al sem fogja tudni hogy te milyen merényletre készülsz;)
gondoltam, hogy lesz aki belekot...
A warning lenyege, hogy nem hiba hanem gyanithatolag problema forrasa. Esetleg nem az, akkor false positive - na es? Ertem en, hogy elofordulhat hogy valaki direkt ekkora stacket akar, az majd figyelmen kivul hogyja a warningot. Kerdes a gyakorlatban ennek az aranya a veletlenul igy elkovetett hiba aranyahoz.. Forditasi idoben ott volt a gcc-nek az orult nagy stack, nyugodtan warningolhatott volna ha akart volna.
Kicsit elterve a szaltol: a melohelyen is az az elgondolas hogy a warning az error es az jo ha -Werror -al forditunk.. De ha ez igy lenne mert kell a forditokban eleve megkulonboztetni a warningot az error-tol?
Meg annyi offot, hogy imho az a legrosszabb mikor a warning esetleg megrosszabb lint vagy hasonlo kodelemzo gyomlalas kedvert nekiallsz eleve jo kodot modositani..
Nem belekötöttem, megjegyeztem. De ha már ilyen mélységig esünk, akkor nosza.
Lehet kódot írni -Wall -al, úgy, hogy az soha az életben nem fog sikítozni hogy baj lesz belőle, de ha te úgy döntesz hogy valamit rosszul csinálsz, azért nem a gcc a felelős. (Lehet úgy is shared objecteket kezelni, hogy kézzel, fixen, behaxolod az entrypointokat ami teljesen szabályos, lévén fordított esetben ezt nevezik hook-nak, a gcc nem fog szolni érte, de az, hogy valamit nem, esetleg szar módon kezelsz le, az már a te problémád.)
A warning-ok között is figyelmen kívül lehet hagyni párat, pont ezért warning, hogy rákérdez, biztos ezt akarod-e, mert nem feltétlen szabályos. A nem szabályos != nem jó -val,
Bár ha melóhelyen ezzel foglalkozol, akkor nem is értem miért nekem kéne meggyőznöm téged arról, hogy ha valamit favágó módszerrel csinálsz az nem a fordító hibája.
Szerintem a warning egy jófejség a fordító részéről, hogy fejlesztés közben a szar kódot is lehessen futtatni, ettől függetlenül majdnem ugyanannyira gáz, mint az error. Ha az ember biztos benne, hogy egy warning false positive, akkor #pragma warning disable vagy ilyesmi, de figyelmen kívül hagyni semmiképp se nyerő.
--
joco voltam szevasz
de a warning nem error. Lehet, sőt, néha kell is olyan kódot írni amire minden fordító magábaroskad és felsír, közben csak trükközöl isten (és a fejlesztők) adta lehetőségeiddel.
-Werror :-)
--
;D
És akkor mi van, ha a ciklusváltozó int (nem véletlenül mondjuk), és valami tároló méretéig akarok menni, ami ugye valami unsigned típus, ekkor warning lesz, de mégsem hiba, sőt.
Amúgy a void main csak nekem csípi a szemem?
----
Hülye pelikán
(int)sizeof(bizbaz)
volt warning, nincs warning! VARAZSLAT! MAGIA!
--
|8]
Igen, azt írtam, hogy nem létezik rá megoldás, valóban.
Igen, én is tudom, hogy lehetséges megoldani, csak felvetettem, hogy ilyen esetben például a warning nem jelez semmiféle hibát, pontosan tudom, hogy mit csinálok, és hogy előbb telik meg a memória, minthogy a signed-unsigned összehasonlítás miatt gond legyen. De okoskodj még légyszíves.
----
Hülye pelikán
Mivel -Werror-rol volt szo, es ezt irtad ra:
> És akkor mi van, ha a ciklusváltozó int (nem véletlenül mondjuk), és valami tároló méretéig akarok menni, ami ugye valami unsigned típus, ekkor warning lesz, de mégsem hiba, sőt.
Felteteleztem, hogy az a gondod, hogy warningol (ill errort csinal belole), pedig te tudod mit csinalsz, es tudod, hogy nem lehet overflow. Erre gyogyir a cast.
Ha az a gondod, hogy int i = (unsigned)j -re nem warningol a fordito, arra is van -W kapcsolo: -Wsign-conversion, es maris sirni fog.
--
|8]
nekem az ilyesmitol van tele a hocipom
int xxx(int yyy, int zzz)
{
#if defined(some_funky_feature)
yyy = zzz;
#endif
q(yyy);
}
Warning: zzz not used used in function xxx.
Error: all warnings treated as errors.
Blah
Van valami gcc hint ehhez, hogy ne nyuglodjon miatta, __attribute__(unused) vagy vmi nagyon hasonlo.
--
pontosabban:
int xxx(int yyy, int zzz __attribute__((unused)))
vagy pl.:
#if defined(some_funky_feature)
yyy = zzz;
#else
(void)zzz;
#endif
> És akkor mi van, ha a ciklusváltozó int (nem véletlenül mondjuk)
Nálam ilyenkor az van, hogy elgondolkodok: akármennyire okénak tűnik, hogy int, biztos minden szempontból jó-e ez nekem. Nem kell-e valamit magasabb szinten újragondolni.
Ha tuti, akkor jöhet a cast, ahogy mondták.
Gondolom azért, mert a linker számolgatja a stack-et...
Mint lejjebb kiderült állítani is lehet amiről a gcc nem is tud, tehát nehezen tudna warningot adni...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
Szerintem de fixme a linker nem szamolgatja a stacket. Azt elhiszem hogy mikor ooszerakja a binarist, beleir vmi default meretet amekkora stacket gondol hozza. A gcc generalja azt a kodot ami a stackpointer megakkal oddabb rugja. Uh minden lehetosege megvolt a warningra.
A lényeg az, hogy a gcc számára nincs olyan, hogy túl nagy a stack (a címzési maximumot leszámítva), max azt mondhatná a warningban, hogy "figyelj, mert nagyobb stack kell, mint a default". Kb ezt mondja egyébként a valgrind is...
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
+1
valgrind kimenete:
Lehet hogy hülye vagyok a linux-os C-hez de ez nem a stack-en fogja lefoglalni a memóriát, hiszen nem "new"-val foglalódik
le a hely?
Szerk... bocs tovább olvastam... :-)
Bocs, hogy off vagyok, de elegge indentalatlan a kod. Amugy miert akarod eltarolni az osszes dobas eredmenyet?
< code > elb@sszsa az indentalast az elso kopipesztnel
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
A <pre> is?
Sracok, a formazasi lehetosegeknel meg van emlitve a [ code ] hasznalata, annal tobbet senki se tehet.
--
Ilyen indentalatlan kodot at nem nezek, inkabb tippet adok: nezd meg gdb-vel.
--
|8]
http://hup.hu/filter/tips/4#filter-bbcode-0
Különös tekintettel a "Fix szélességű szöveg és blokk formázás" részre.
Szép meg jó, csak nem így működik. A code pl nem úgy kezeli a <-t, mint ahogy ott írva vagyon...
- Megnézem a dinamikus memóriakezelést. Nem vagyok c programozó (semmilyen se), akkor írok meg pár soros dolgokat c-ben, ha számít a sebesség.
- Geditben írtam és átrakva elvész az indendálást, pedig valahol azt olvastam, hogy nem kéne neki. Aztán gondoltam, ennél a pár sornál nem nagy gond. Ezek szerint mégis. Egyébként most először írtam ide programkódot. Olvasgattam a belinkelt formázási útmutatót, de abból nekem nem jött le, hogy lehetne szépen megoldani. Pedig több mindent kipróbáltam. Sajnálom, én már csak ilyen gyenge képességű vagyok.
- Azért tároltam a dobások eredményét, mert így egyszerűbb volt szórást számolni. Nem gondoltam, hogy probléma lesz vele. Igen, ez lesz a legegyszerűbb, az egyes eredmények tárolása nélkül is ki lehet számolni a szórást és feltehetőleg ezzel meg is oldódott a mizéria.
- A változónevekről: v: várható érték, d:szórás, s: összeg, a többi jellegtelen. Egy ilyen rövid programnál nem gondoltam, hogy lesz valaki, akinek ez nem tetszik.
Köszönöm a hozzászólásokat!
Arra vigyázz, hogy amit számítógépen kimutatsz, az nem feltétlenül a véletlenről szól, hanem sokkal inkább a véletlen-generátorról, amit használsz.
Például ebben a programban - ha elegendően nagy n-re futtatod, akkor egy idő után periodikus lesz a "véletlen" forrásod, mert az alap véletlen generátorok periodikusak.
Technikai segítség: forráskódot pastebin-ben szoktak posztolni. Megtartja az indentálást, sőt még színezi is a kódot, ha megadot a nyelvet. http://pastebin.com
Igen, ezért választottam ezt az időtől függő generálást, de valóban, így sem tudhatom, hogy mennyire véletlen így a véletlen.
Végül is így módosítottam, így nem kellett a memóriával izélni, menet közben számolok. A változó típusokat így már nagyobbra kellett állítani itt-ott. http://pastebin.com/X7kSGGVx
Köszönöm a segítséget!
Amikor a sztatisztikat szamolod, tobb gond is van szerintem
s=q;
kell s++; helyett. Gyakorlatilag az s valtozo kihagyhato.
Valamint n helyett kesobb epp azt az s-et kellene hasznalnod ami eddig volt, mert a while ciklus nem megy vegig. Sot, ezt a for ciklust is jo lenne lecserelni egy while-ra.
Nehany modositas:
Az elejen "int my_n = 0;"
A cikluson belulre
my_n ++;
v+=q;
d+=q*q;
es a legvegen
v=v/my_n;
d=sqrt( d/(my_n*my_n) - v*v );
// de nekem ugy remlik, hogy szigma = szum ( q_i*q_i - q_atlag*q_atlag) / (my_n - 1) kell! ,
// vagyis
v = v/(double)my_n;
q = sqrt( ( d + v*v*(double)my_n )/( (double)my_n -1.0) ));
// vigyazni kell, ha integert hasznalsz a kepletben, mert a fordito ugy dont neha, hogy kerekiti a szamot
Félreérted, nem a dobásokból számolok statisztikát, hanem a dobások számából ezért kell egy számláló változó, ez az s. Nem mértem miket írsz.
A másik, hogy Te korrigált tapasztalati szórást javasolsz tapasztalati szórás helyett, egyrészt nem tudom miért, másrészt nagy n-ekre ezek aszimptotikusan egyenlők, sokkal kiesebb n-ekre sincs jelentősége, hogy melyikkel számolunk.
"vigyazni kell, ha integert hasznalsz a kepletben, mert a fordito ugy dont neha, hogy kerekiti a szamot" Ezt hogy érted?
hát pl
int i=1/3;
printf("%d\n",i);
kimenete 0 lesz.
Hú, mekkorákat lehet szívni ezen! Fordítófüggő, hogy mi történik!
> Sol omnibus lucet.
Én nem tudok olyan használatban lévő és ENNYIRE nem szabványkövető fordítóról, aminél ne 0 lenne az eredmény...
Melyik fordító ilyen?
A float->int konverzió tényleg fordítófüggő, de itt nem az van..
igen, es pont 1/int volt a programban is.
Hát meg nem mondom már milyen két típus volt egy kifejezésben
(talán valóban float és int), ami az egyik gcc-vel a számomra
várt módon működött, a másikkal pedig nem. Valamelyik tagot meg
kellett cast-olni, hogy jó legyen.
> Sol omnibus lucet.
No, megtaláltam:
(int)=(int)/(unsigned int)
A két (int) előjeles kellett, hogy legyen, az (unsigned int)
pedig egy számláló volt, ami természetesen előjeltelen. Az egyik
fordító jól csinálta a dolgot, a másik (az újabb) nem. Az unsigned
adatot castolni kellett (int)-re, és akkor jó lett.
Benne van ansi C szabvanyban. Ugyanolyan szelessegu inteknel ha egyik signed, masik unsigned, akkor unsigned-ra kasztol.
Köszi, ezt nem tudtam. A probléma ezen túl az, hogy két fordító
két különböző módon reagált.
> Sol omnibus lucet.
Akkor az egyik forditot el kell dobni.
--
Lezárom azt a két code tag-et amit nyitva hagytál, ha nem baj. :)
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
Kösz, a második lezáró akart lenni.
OMG facepalm de hülye ez a drupal! :S
Csak remélni merem, hogy sokan nem olyan minőségben programoznak, ahogy a html tageket írják.
--
trey @ gépház
Megnyugtatlak, tenyleg nem. Sokkal rosszabbul.
--
|x]
Azért van gond itt a motorral is. Pl:
Ennek a kódnak: [index]
Ez az eredménye:
Vagy ennek: <index>
Ez:
Valljuk be, hogy nem kényelmes így. Szerencsésebb lenne, ha code html elemek között nem oldaná fel a BBCode-ot és a html kódot sem (kivéve nyilván a lezáró </code>-ot). Szerintem.
--
http://www.naszta.hu
Az egyáltalán nem kerekítés, hanem implicit cast,
illetve nem néha dönt úgy, hanem akkor, amikor amikor a típusok azt indokolják..
1/2 == 0
1.0/2 == 0.5
1/2.0 == 0.5
Ugy tudom epp az 1.0/2 az, ami forditofuggo. Ha van meg nehany tag a kepletben, akkor neha maskepp rendezgeti, es siman elkezd castolgatni.
Pont a double osztast nem lehet megtoszojni hatulrol. A 2-t egyszeruen muszaly double-ra castolni, mert a double int-re castolasaval informacioveszteseg jonne letre. Raadasul az osztas pont nem atrendezheto.
--
lyully
t
;-)
- A fordító nem csinálhat olyan átrendezést, ami megváltoztatja az eredményt.
- Ha van double a képletben, akkor az addigi _részeredmény_ is double-re castolódik, mert fordított esetben információvesztés van.
Ami meglepő lehet az az, hogy:
De ez nem a fordító (vagy a nyelv) hülyesége.
az ugye két egész, a művelet a maradékos osztás, az eredmény egész, azaz 0.
az egy egész és egy "valós", a művelet az osztás (két valós), konverzió kell egész->valós. (Maradékos osztás most nem játszik, mert ahhoz egész számok kellenek, és a valós -> egész konverzió információvesztéssel járhat, így implicit nem megengedett.)
"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee." -- Ted Ts'o
Az egesz switch-case helyett eleg lenne ennyi: w[q]=1;
Ha 255 dobasbol nem jon ki a 6 kulonbozo ertek, tulcsordul a szamlalo es 0rol ujrakezdi.
Ja, a swich-case jogos. A másikat nem értem. Itt arról lenne szó, hogy statisztikát készítünk arról, hogy hány dobásra lesz ki a 6 különböző érték. Azért kell ekkorákat nézni, mert még így is nagy az ingadozás.
egyebkent szerintem ne csak statisztikat csinalj, hanem komplett hisztogrammot. valoszinuleg az e-nek az eloszlasa nem pont gauss-szeru, igy ez az atlag-szoras pa'r nem annyira jol jellemzi. persze ha az alap-feladat igy szolt, az mas kerdes, de mint problema tenyleg erdekes.
Ezt en is akartam irni, meg tegnap este, de surgosebb dolgom lett. ;)
A w[] tombot fel lehet erre hasznalni, w[q] = 1 -ek helyett w[q] ++ kell, utana pedig mar egyszeru a statisztikat is szamolni es nem kell vegigporgetni az osszes esemenyen, mint az eredeti kodban. (de azota mar van egy masik, mukodo megoldas)
Értem már, köszönöm!
Egy kis adalek, azon kivul, hogy termeszesetesen feloldottak a problemad forrasat.
Linkernek atadhato az informacio, ha nagyobb stack meretet szeretnel.
gcc -Wl,-stack_size,0x10000000 foo.c -o foo
gcc -Wl,-stack,0x10000000 foo.c -o foo
Ld-tol fuggoen.
Már elhangzott, hogy az s tömböt jobb dinamikusan foglalni, és ez meg is szüntette a segfaultot.
A segfaultot dinamikusmemória-foglalás nélkül is meg lehet szüntetni a stack limit megnövelésével, pl.
ulimit -S 12345
paranccsal kb. 12.345 MB-ra növelheted a főszál vermének maximális méretét -- tehát ha ennyi adatmennyiség alatt van az összes aktív függvény lokális változóinak és argumentumainak összmérete, akkor még nem segfaultol. A méretnövelés az aktuális shellben és a belőle indított programokban jut érvényre.
Az indentalas ott van, jelold ki, nezd meg a forrast.
<code> taget hasznaltal, na az ezt csinalja.
1
2
mig peldaul a [code] ezt csinalja:
Meg tudod editalni (szerkeszteni) atopicindito hozzaszolast, ott csereld ki a <> jeleket [] -re, es mindenki jol jar.
Ha program által elfoglalt statikus terület elér egy bizonyos
méretet (64 MB?), akkor segfault. Valahol állítható ez a limit,
de nem tudom hol.
Fanyalgóknak: sajnos valóban előfordulnak olyan esetek, amikor
nagy-nagy statikusan foglalt memóriára van szükség. Sok statikus
memóriát lehet azonban spórolni ügyes algoritmussal, feladat
párhuzamosítással, megosztott memória használattal, overlay-
technikákkal, de ezek haladó témák.
> Sol omnibus lucet.
Ha jól értelmezem a kérdés az:
Hányat kell dobni a dobókockával ahhoz, hogy mind a hat szám előforduljon.
Ehhez viszont nem kell programozni:
http://en.wikipedia.org/wiki/Coupon_collector's_problem
szerk: Ebben az esetben
várható érték: 6*H(6) = 147/10 azaz pontosan 14.7
variancia: 6*Pi^2= 59.2176 szórás:7.69
Ha jól számoltam...
Köszi a linket, nem ismertem. (A varianciánál a felső becslést nézted, de ott a pontos értéket szolgáltató képlet is.)
Ha a fordító tud C++-t is, akkor így definiáld a nagy tömbödet:
Ja, ez az alak azért is jó (szerencsés is hozzászokni), mert bárhol lépsz is ki a programból/függvényből stb., fel lesz szabadítva. Míg ha magad allokálód, akkor az nem biztos.
Azért lett at a függvény, mert nem találtam a szögletes zárójel kódját. (Az oldal egyébként benyeli.)
--
http://www.naszta.hu
ebben csak kicsikre kell kiszámolni :)
http://www.spoj.pl/problems/FAVDICE/
én mint nemprogramozó: ilyen egyszerű feladatoknál (1 fájlos...) először a nagy tömböket kirakom globálisba. tesztelgetés fejvakargatás után ha minden rendben - beburkolom egy struct-ba, amiben már dinamikusan van foglalva - felszabaditva a mem., és
lokális lesz a név. biztos van hátránya ennek de a konyhában beválthat.
üdv,ncs
"ebben csak kicsikre kell kiszámolni :)"
Miért, az senkit nem érdekel mennyi 1 billió oldalú dobókockára? (28208236780830.58 dobás egyébként, leellenőrizheted az okos tömbös módszereddel ;P)
kedves szemet,
1. nem mondta senki hogy érdektelen 1 billió oldalú kockára a kérdés, a fenti feladatot azért írtam be mert a topicnyitót láthatóan érdeklik a hasonló problémák.
2. ha az Euler konstans megfelelő sok jegye rendelkezésre áll akkor nem gond kiszámolni 1 billió-ra sem :), de ekkor a feladat egy gyorsan konvergáló gamma közelítés keresése lesz,
az eredeti feladat pedig középiskolás szintű...
3. "leellenőrizheted az okos tömbös módszereddel" ezt nem értem mire írtad. a globális tömbök használatát én általában javasoltam a topicnyitónak, ahelyett hogy a nyelvi eszközökkel foglalkozik (malloc,new,vector), főleg ha nem nyelvi problémák is vannak a megoldásában.
Tul nagy tombot hoztal letre a stacken.
Meg mindig csunyan, de legalabb heapen hozod letre igy: (nem inicilalizalt data .bss, gyakran nullaval toltodik ki de erre tilos epiteni)
/*Addig dobalunk a kockaval, amig meg nem dobjuk mind a hat lehetoseget*/
#define n 10475400
unsigned long x;
unsigned char a,e,q,w[6],s[n];
void main() // a main elott van tomb letre hozas , vagyis fugvenyen kivuli , "globalis" valtozo
{
float v,d;
srand(time(NULL));
FYI:
$ ulimit -a val megnezheted a max stack meretet
mondjuk:
$ ulimit -s 16000 # -al megnovelheted a max stacket.
Nem szokas megnovelni a stacket, mar az alap ertek is normalis esetben nagyon nagy.
Amit nem lehet megirni assemblyben, azt nem lehet megirni.
A nagy egy relativ fogalom. Nekem van itthon egy hati taskam, amit en "nagy"-kent definialok, tekintve, hogy tenyleg nagy, de egy elefant szallitasara momentan alkalmatlan. Mert az meg nagyon-nagyon nagy.
--
Jó nagy zavar van C szabvánnyal kapcsolatban, pedig jelenleg már kb. minden fordító elég tisztességesen követi. Valahogy mindig ellentétesen kezelik: használnak olyan funkciót ami szabvány szerint nem feltétlen úgy van, és kerülnek olyat amit pedig a szabvány rögzít...
"gyakran nullaval toltodik ki de erre tilos epiteni"
A szabvány pedig kimondja:
"If an object that has static storage duration is not initialized explicitly,
then:
- if it has pointer type, it is initialized to a null pointer;
- if it has arithmetic type, it is initialized to (positive or unsigned) zero;
- if it is an aggregate, every member is initialized (recursively) according to these rules;
- if it is a union, the first named member is initialized (recursively) according to these rules."
Jogos.
Akkor szabad ra epiteni.
Amit nem lehet megirni assemblyben, azt nem lehet megirni.