02. oktober 2006 - 22:09Der er
24 kommentarer og 2 løsninger
Rykke alle felter i et array en plads?
Hej,
hvordan kan man effektivest (hurtigst) rykke alle felter i et array een plads, og saa indsaette in ny vaerdi (f.eks. 9) paa den foerste plads? Som i et skifteregister.
Delphi syntax: procedure Move(const Source; var Dest; Count: Integer);
Description Move copies Count bytes from Source to Dest. No range checking is performed. Move compensates for overlaps between the source and destination blocks.
Whenever possible, use the global SizeOf function (Delphi) or the sizeof operator (C++) to determine the count.
Er dette saa den rigtige maade at bruge move paa? Hvorfor bliver a sat til 10 (vaerdien, fra sidste linie) i andet gennemloeb af OnTimer?? Den sidste linie burde da ikke have noget med a at goere!
Har jeg maaske misforstaaet noget med move?
procedure TForm1.FormCreate(Sender: TObject); begin a:=0; end;
procedure TForm1.Timer1Timer(Sender: TObject); begin Label1.Caption := IntToStr(a); a := a+1; move(t1[0],t1[1],SizeOf(t1)); t1[0]:=StrToInt(edit1.Text); t1[100]:=10;
Som hjælpen skriver: No range checking is performed, dvs. at man skal være helt sikker på hvad man laver, jeg går ud fra at dit array indeholder elemener på 1 byte, så når du skriver:
move(t1[0],t1[1],SizeOf(t1));
så flytter du en byte for meget og hvor den sidste byte ender er vist lidt tilfældig, i dit tilfælle ender den nok med at overskrive a hvilket er grunden til at a pludselig indeholder 10 i stedet for 2. Så din move skal se således ud:
Kroning: Du har ret. Troede, uden at teste, at den ville returnere 4 som i pointerens størrelse, men det gjorde den ikke. Jeg arbejder ikke meget med records og arrays længere; det står i stedet i klasser og lister og der returneres pointerens størrelse. Du glemte i øvrigt lige den sidste ting i linjen:
type arraytypen = array[1..9] of integer; arr = record case boolean of true :( nn : arraytypen); false : (forskydning : integer; nn2 : arraytypen); end;
Rent fysisk ligger nn og nn2 samme sted i RAM, men nn2 er forskudt to bytes (Længden af forskydning) i forhold til nn
Hvis du definerer to variable
Var hererdata : arraytypen Temp : arr;
Kan du nemt forskyde hererdata arrayet på følgende måde:
temp.nn2 := hererdata; hererdata := temp.nn;
Voila - hererdata er nu forskudt, så den gamle hererdata[n] nu er i hererdata[n+1]. Jeg har testet at det virker i en delphi 6, så Borland har været "tro" mod det gamle pascalsprog. mvh ib
Hej Ib. Er du sikker på du ikke er C++ programmør? De skal jo gøre det besværligt for hinanden :-). Der er ikke mange der kender den gamle "case boolean of" (og der er sikkert meget få der nogensinde har brugt den).
Hej HRC Life is to short to C. Jeg har aldrig skrevet een linie kode i C, men har programmeret i Pascal siden 1976... øøøh 30 år. Faktisk tror jeg ikke engang at "record case boolean..." er beskrevet i Delphi, men liiige i dette tilfælde er det noget hurtigere end move, fillchar og alt det der. kh ib
UPS - Nysgerrighed fik mig lige til at checke dokumentationen for delhi, rent faktisk er definitionen beskrevet under overskriften "Variant parts in records" i delphi's hjælpetekst. Sorry ib
totaldata: Hvorved er din rutine hurtigere? Er der ikke stadigvæk tale om en skjult move-operation, bare pakket ind i noget eksotisk pascal-kode?
Man kan i øvrigt stadig bruge goe gamle "absolute" i Delphi (Det brugte jeg dengang jeg havde problemer med at forstå begrebet interface). Der er sikkert meget af Anders Hejlsberg (den slemme overløber) compiler-kerne der kører endnu.
Hrmf Det ser ud som om mit svar forsvandt. Så jeg prøver igen.
Jeg tror faktisk at jeg stødte på "select case" i Universitetet i 77 - Det er vist en Niklaus Wirth een ;-)
Jeg er ret sikker på at mit udtryk er en assembler move-kommando, men er du sikker på at din move er absolut kode? - Du kan finde move-proceduren i system.pas, hvor du kan se at den både kan være "hardcoded" i assembler og en almindelig procedure (afhænger af compilerswitch). Hvis din move ikke er hardcoded, er der en masse husholdning omkring lokale variable, returadresse og procedureparametre. I øvrigt er der en del "husholdning" i den assembler kode som din move i modsat fald producerer, bl.a. omkring push og pop af EDI og ESI, så rent faktisk tror jeg at min metode er hurtigere end din move.
Jeg kan lide dem begge men bruger kun den ene... Nu er PUREPASCAL flaget ikke sat - og så er det hurtigere. Jeg har svært ved at forstå at man skulle få brug for den alternative løsning.
Nu tager jeg så skridet fuldt ud og tester det:
type TBigArray = array[0..99999] of integer; TBigArrayRecord = record case boolean of true : (nn : TBigArray); false : (offset : integer; nn2 : TBigArray); end;
procedure TForm1.Button1Click(Sender: TObject); var Start : cardinal; i : integer; begin Screen.Cursor := crHourGlass; Application.ProcessMessages; Start := GetTickCount; try // Ryk data en tand for i := 0 to 1000 - 1 do begin move(fBigArray[0],fBigArray[1],(length(fBigArray) - 1) * sizeof(integer));
// Indsæt endnu en værdi. fBigArray[0] := -1; end; finally OutputDebugString(pchar(IntToStr(GetTickCount - Start))); Screen.Cursor := crDefault; end; end;
procedure TForm1.Button2Click(Sender: TObject); var i : integer; Start : cardinal; Temp : TBigArrayRecord; begin Screen.Cursor := crHourGlass; Application.ProcessMessages; Start := GetTickCount; try for i := 0 to 1000 - 1 do begin Temp.nn2 := fBigArray; fBigArray := temp.nn; fBigArray[0] := -1; end; finally OutputDebugString(pchar(IntToStr(GetTickCount - Start))); Screen.Cursor := crDefault; end; end;
procedure TForm1.FormCreate(Sender: TObject); var i : integer; begin for i := low(TBigArray) to high(TBigArray) do fBigArray[i] := i; end;
Resultat: 1. Gennemløbene tager 125ms og [172..188]ms for hhv. kronings og din rutine. 2. Din rutine fejler med stack overflow når man fodrer den et array på 1.000.000 felter.
Veredictum est: Kronings forslag er bedst. Den vinder også i overskuelighed.
Hej HRC, Ind imellem må man jo bide i græsset, og din test viser jo klart at kronings er over 30% hurtigere. Nu havde du jo været så flink at sætte din kode ind, og på min maskine var resultatet faktisk endnu værre. Det får jo een til at spekulere over hvad det er for en kode der bliver genereret på mit assignment... Det må jeg kigge på en dag.
Det med stackoverflow i punkt 2 er lidt underligt (vi er vist lidt ude på kanten af systemet). Egentlig tyder det på at min udgave medfører en række almindelige assignments i stedet for en move. Det er en lidt tåbeligt implementering, hvis det er rigtigt.
Men konklusionen (suk) kan jeg vist ikke løbe fra. kh ib
totaldata, arne_v: I strør' om jer med indforståede forkortelser - godt man så har google. Bruger man stadig de gamle Cray's? (er det ikke en stor opvarmet designer-sofa som man bl.a. kan se i "Sneakers"?) Hvad med at slukke for den og bruge emulatoren? Det må trods alt (windows) være hurtigere end en maskine fra 80'erne; så sparer man nok også lidt strøm.
- jeg kan i øvrigt også snakke med om de gamle dage i den utætte papkasse langs de øde vestjyske motorveje (de kaldes godt nok hovedveje derovre, men hastigheden er motervejenes); godt nok ikke i supercomputerklassen, men den første var en RC Piccolo (UNICOMAL). Pragtfuldt Cherry tastatur og en ret god gulbrun monochromskærm. Dog optog de 2 8" diskettedrev en del plads; de vejede hver 20kg. I øvrigt den eneste computer jeg har solgt med fortjenste - og den jeg (ynkelige nostalgiker) savner mest.
Hej HRC Jeg har nu godt nok heller ikke kørt på Cray, men den så da lidt hypersmart ud i forhold til de andre maskiner. Måske har vi krydset hinanden med Piccolo'en. Jeg lavede et administrativt system til den i Comal 80 der var med på nogle af de første IT-udstillinger i Bellacentret, og lavede også nogle integrerede systemer til kommunerne i grønland (suk, det var lidt den utætte pakkasse - Jah det var dengang man kunne klare sig med ........). kh ib
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.