Avatar billede knaste Nybegynder
02. oktober 2006 - 22:09 Der 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.

Eksempel foer:
3,6,3,4,5,2

Eksempel efter:
9,3,6,3,4,5


Tak for evt. hjaelp.
Avatar billede kroning Nybegynder
02. oktober 2006 - 22:28 #1
Brug move;

var
    t : array(.1..5.) of byte;
begin
    fillchar(t,5,0);
    t[1]:=1;
  t[2]:=5;
  t[3]:=10;
    move(t[1],t[2],4);
  t[1]:=3;
end;

Bemærk: No range checking is performed
Avatar billede knaste Nybegynder
02. oktober 2006 - 23:37 #2
Kan du forklare linierne
fillchar(t,5,0); og
move(t[1],t[2],4);
Avatar billede kroning Nybegynder
03. oktober 2006 - 11:32 #3
Det kan jeg da godt men jeg tror ikke jeg kan gøre det bedre end som hjælpen i Delphi
Avatar billede knaste Nybegynder
03. oktober 2006 - 12:52 #4
Jeg har fundet forklaringen paa fillchar - sorry,
men forklaring paa move med 3 parameter kan jeg ikke finde - kun med 2 parameter.
Avatar billede kroning Nybegynder
03. oktober 2006 - 19:47 #5
Den kommer så lige her:

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.
Avatar billede knaste Nybegynder
04. oktober 2006 - 11:03 #6
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;
Avatar billede hrc Mester
04. oktober 2006 - 13:24 #7
Overvej at bruge TQueue. Det ligner jo noget der kan poppes og pushes.

Kronings forslag kan drage nytte af SizeOf funktionen så den var lidt mere tolerant overfor at man skiftede datatype:

var
  i : integer;
  t : array[1..5] of integer;
begin
  // Nulstil tabellen (redundant, da hele listen initialiseres nedenfor)
  fillchar(t,5,0);

  // Fyld tilfældige værdier ind i tabellen
  for i := low(t) to high(t) do
    t[i] := random(100);

  // Ryk data en tand
  move(t[1],t[2],sizeof(integer) shl 2); // flyt 4 bytes * 4 pladser = 16 bytes

  // Indsæt endnu en værdi.
  t[1] := random(100);
end;
Avatar billede hrc Mester
04. oktober 2006 - 13:25 #8
fillchar(t,sizeof(integer) * 5,0); // .. eller (sizeof(integer) shl 2 + sizeof(integer)) :-)
Avatar billede kroning Nybegynder
05. oktober 2006 - 08:09 #9
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:

move(t1[0],t1[1],SizeOf(t1)-1);
Avatar billede hrc Mester
05. oktober 2006 - 08:27 #10
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:

  move(t1[0], t1[1], SizeOf(t1) - sizeof(t1[0]);

eller

  move(t1[0], t1[1], (length(t1) - 1) * sizeof(t1[0]);

men den involverer en multiplikator så den er tungere end den første

eller..
Avatar billede totaldata Nybegynder
09. oktober 2006 - 15:44 #11
Hej Knaste,
Nu skal du lære noget smart:

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
Avatar billede hrc Mester
09. oktober 2006 - 19:46 #12
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).
Avatar billede totaldata Nybegynder
12. oktober 2006 - 05:57 #13
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
Avatar billede totaldata Nybegynder
12. oktober 2006 - 06:07 #14
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
Avatar billede hrc Mester
12. oktober 2006 - 09:19 #15
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.
Avatar billede totaldata Nybegynder
12. oktober 2006 - 11:28 #16
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.

Men.. Nogle kan lide moderen - andre datteren.

mvh ib
Avatar billede hrc Mester
13. oktober 2006 - 09:43 #17
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;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    fBigArray : TBigArray;
  public
  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.
Avatar billede totaldata Nybegynder
13. oktober 2006 - 21:32 #18
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
Avatar billede knaste Nybegynder
13. oktober 2006 - 22:54 #19
Kroning og HRC, laegger I også lige svar, så pointene kan blive delt?
Tak for hjælpen og forklaringerne til alle!
Avatar billede kroning Nybegynder
14. oktober 2006 - 19:34 #20
ok
Avatar billede arne_v Ekspert
15. oktober 2006 - 04:51 #21
totaldata>

Pascal på RECAU's CDC Cyber maskine ?

:-)
Avatar billede hrc Mester
15. oktober 2006 - 15:27 #22
Indlæggene blev lige vel omstændige, men det er jo kronings svar - så han skal have pointsene.
Avatar billede totaldata Nybegynder
16. oktober 2006 - 20:46 #23
arne v
Nix, Recku, univac 1100
kh ib
Avatar billede hrc Mester
16. oktober 2006 - 22:55 #24
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.

I kan hente emulatoren her: http://members.iinet.net.au/~tom-hunter. Det kan være der findes en Oberon til den...

Hvad laver sådan et par gamle maskiner egentlig på AU? Wikipedia påstår at Univac'en er fra 70'erne: http://en.wikipedia.org/wiki/UNIVAC_1100/2200_series.

- 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.
Avatar billede arne_v Ekspert
17. oktober 2006 - 00:33 #25
RECAU var Århus, RECKU var København, NEUCC var DTU

de blev alle fusioneret ind i UNI*C

CDC'en i Århus blev skrottet omkring 1990 så vodt jeg husker

1100'en i København fik vist lov at eksistere nogle år mere

ingen af dem er Cray omend Seymour Cray arbejdede for CDC inden han startede hans
eget firma

jeg vidste ikke at 1100'en havde Pascal
Avatar billede totaldata Nybegynder
18. oktober 2006 - 08:42 #26
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
Avatar billede Ny bruger Nybegynder

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.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester