Monday 23 October 2017

Pseudo Kode Moving Average


Tidsserieanalyse og dens applikasjoner: Med R Eksempler Kode Brukes I Tredje Utgave Eksempler Nedenfor er koden som brukes for hvert numerisk eksempel i teksten. Disse tingene vil ikke fungere med mindre du har lastet astsa og datafilene ved starten av sesjonen. Hvis dette er første gang her, vil du kanskje lese astsa-pakken notater siden for ytterligere informasjon. Kapittel 1 Eksempel 1.1 Eksempel 1.2 Eksempel 1.6 Eksempel 1.6 Eksempel 1.7 Eksempel 1.9 Eksempel 1.10 Eksempel 1.11 Eksempel 1.12 Eksempel 1.24 Eksempel 1.25 Eksempel 1.26 Eksempel 1.27 Kapittel 2 Eksempel 2.1 Eksempel 2.2 Eksempler 2.3 Eksempler 2.4 og 2.5 Eksempel 2.6 Eksempel 2.7 Eksempel 2,8 Eksempel 2.9 Eksempel 2.12 Eksempel 2.13 Eksempel 2.14 Eksempel 2.15 Kapittel 3 Eksempel 3.1 Eksempel 3.4 Eksempel 3.10 Eksempel 3.11 Eksempel 3.15 Eksempel 3.17 Eksempel 3.24 Eksempel 3.27 Eksempel 3.28 Eksempel 3.29 Eksempel 3.35 Eksempel 3.37 Eksempel 3.38 Eksempel 3.40 Eksempel 3.44 Eksempel 3.46 Kapittel 4 Eksempel 4.11 Eksempel 4.14 Eksempel 4.15 Eksempel 4.18 Eksempel 4.19 Eksempel 4.21 Eksempel 4.22 Eksempel 4.23 Eksempel 4.24 Eksempel 4.25 Eksempel 4.26 Kapittel 5 Eksempel 5.1 Eksempel 5.2 Eksempel 5.3 Eksempel 5.4 Eksempel 5.5 Eksempel 5.6 Eksempel 5.7 Eksempel 5.8 Eksempel 5.9 Eksempel 5.10 Eksempel 5.11 Kap ter 6 Eksempel 6 Eksempel 6 Eksempel 6 Eksempel 6 Eksempel 6.10 Eksempel 6.10 Eksempel 6.10 Eksempel 6.13 Eksempel 6.17 Eksempel 6.18 Eksempel 6.19 Eksempel 6.23 Kapittel 7 Kode i Introduksjon Eksempel 7.1 Eksempel 7.2 Eksempel 7.4 Eksempel 7.6 Eksempel 7.7 Eksempel 7.8 Eksempel 7.9 Eksempel 7.8 Eksempel 7.9 Eksempel 7.10 Eksempel 7.11 Eksempel 7.12 Eksempel 7.13 Eksempel 7.14 Eksempel 7.15 Eksempel 7.16 Eksempel 7.18 Eksempel 7.19 Eksempel 7.20MOVING FORTH Del 1: Designbeslutninger i den fremre kjernen av Brad Rodriguez Denne artikkelen ble først oppført i The Computer Journal 59 (januar februar 1993). INNLEDNING Alle i Forth samfunn snakker om hvor lett det er å porten Forth til en ny CPU. Men som mange quoteasyquot - og quotobviousquot-oppgaver, er det ikke skrevet mye om hvordan å gjøre det. Så, da Bill Kibler foreslo dette emnet for en artikkel, bestemte jeg meg for å bryte med den store muntlige tradisjonen til Forthwrights, og dokumentere prosessen i svart og hvitt. I løpet av disse artiklene vil jeg utvikle Forths for 6809, 8051 og Z80. Jeg gjør 6809 for å illustrere en enkel og konvensjonell Forth-modell pluss, Ive har allerede publisert en 6809 assembler ROD91, ROD92, og jeg trenger en 6809 Forth for fremtidige TCJ-prosjekter. Jeg gjør 8051 Forth for et universitetsprosjekt, men det illustrerer også noen ganske forskjellige designbeslutninger. Z80 Forth er for alle CPM-leserne til TCJ, og for noen venner med TRS-80s som samler støv. ESSENTIAL HARDWARE Du må velge en CPU. Jeg vil ikke dykke inn i fordelene til en CPU over en annen for Forth, siden en CPU-valg vanligvis blir tvunget på deg av andre hensyn. Dessuten er gjenstanden for denne artikkelen å vise hvordan man beveger seg frem til hvilken som helst CPU. Du kan forvente den vanlige 16-biters fremre kjernen (se nedenfor) for å oppta omtrent 8K byte av programplass. For en full kjerne som kan kompilere Forth-definisjoner, bør du tillate minst 1 K byte RAM. For å bruke Forhånds blokkeringssystem for diskoppbevaring, bør du legge til 3 Kbytes eller mer for buffere. For en 32-biters Forth-modell, doble disse tallene. Dette er minimumene for å få en kjerne fremover. Hvis du vil kjøre et program på maskinvaren din, bør du øke PROM og RAM-størrelsen som passer. 16 ELLER 32 BIT Ordstørrelsen som brukes av Forth, er ikke nødvendigvis den samme som for CPU. Den minste praktiske Forth er en 16-biters modell, dvs. en som bruker 16-biters heltall og 16-biters adresser. Det fremre samfunnet kaller dette kvotcellquot-størrelsen, siden quotwordquot refererer til en videre definisjon. 8-bits CPUer støtter nesten alltid 16-biters fremover. Dette krever vanligvis eksplisitt koding av dobbeltbyte-aritmetikk, selv om noen 8-biters CPUer har noen 16-biters operasjoner. 16-biters CPUer kjører vanligvis 16-biters fremover, selv om de samme dobbelte presisjonsteknikkene kan brukes til å skrive en 32-biters fremover på en 16-biters CPU. Minst en 32-biters Forth har blitt skrevet for 80868088. 32-bits CPUer kjører normalt 32-biters Forths. En mindre Forth-modell sparer sjelden kodenes lengde eller prosessortiden. Imidlertid vet jeg om minst en 16-bit Forth skrevet for 68000. Dette krymper programkodestørrelsen med en faktor på to, siden høydefinisjoner Forth definisjoner blir en streng med 16-biters adresser i stedet for en streng på 32- bit adresser. (Dette kommer snart til syne.) De fleste 68000-er har nok RAM. Alle eksemplene som er beskrevet i denne artikkelen, er 16-biters fremover som kjører på 8-bits CPUer. THREADING TECHNIQUE quotedread codequot er kjennetegnet for Forth. En videre quotthreadquot er bare en liste over adresser til rutiner som skal utføres. Du kan tenke på dette som en liste over subrutineanrop, med CALL-instruksjonene fjernet. Gjennom årene har mange trekkvariasjoner blitt utarbeidet, og hvilken som er best avhenger av CPU og applikasjonen. For å ta en avgjørelse må du forstå hvordan de fungerer, og deres avvik. Indirekte trådkode (ITC) Dette er den klassiske Forth-trekkteknikken, brukt i fig. Forth og F83, og beskrevet i de fleste bøkene på Forth. Alle de andre threading ordninger er quotimprovementsquot på dette, så du må forstå ITC å sette pris på de andre. La oss se på definisjonen av et forutgående ord SQUARE: I en typisk ITC Forth vil dette vises i minnet som vist i Figur 1. (Overskriften vil bli diskutert i en fremtidig artikkel, den inneholder housekeeping-informasjon som brukes til kompilering, og er ikke involvert i tråder .) Anta at SQUARE oppstår mens du utfører et annet fremtidsord. Forward Interpreter Pointer (IP) vil peke til en celle i minnet - som er inneholdt i det kvoterende ordet - som inneholder adressen til ordet SQUARE. (For å være presis, inneholder cellen en adresse til SQUAREs Code Field.) Tolken henter den adressen, og bruker den til å hente innholdet i SQUAREs Code Field. Disse innholdene er enda en adresse - adressen til en maskinsprogsunderrutine som utfører ordet SQUARE. I pseudokode er dette: Dette illustrerer et viktig, men sjelden uttalt prinsipp: Adressen til det fremre ordet som nettopp er skrevet inn, holdes i W. CODE-ord, trenger ikke denne informasjonen, men alle andre typer fremtredende ord gjør det. Hvis SQUARE ble skrevet i maskinskode, ville dette være slutten på historien: den lille maskinkoden ville bli utført, og deretter hoppe tilbake til Fortholken - som, siden IP ble økt, peker på neste ord til utføres. Det er derfor den fremre tolken vanligvis kalles NESTE. Men, SQUARE er et høyt nivå kvotekvot definisjon - den inneholder en quotthreadquot, en liste over adresser. For å utføre denne definisjonen, må Forth-tolken bli startet på nytt på et nytt sted: Parameterfeltet for SQUARE. Selvfølgelig må tolkernes gamle plassering bli lagret, for å gjenoppta kvoterkvoten Fortsatt ord når SQUARE er ferdig. Dette er akkurat som en subrutine-anrop Maskinens språkhandling av SQUARE er ganske enkelt å trykke den gamle IP-en, sette IP til et nytt sted, kjøre tolken, og når SQUARE er ferdig, trykk IP. (Som du ser, er IP-kvoten mot kvoten på høyt nivå Forth.) Dette kalles DOCOLON eller ENTER i ulike Forths: Dette identiske kodefragmentet brukes av alle høyt nivåer (dvs. gjenget) Forth definitions Thats hvorfor en peker til dette kodefragmentet, ikke selve fragmentet, er inkludert i den forrige definisjonen. Over hundrevis av definisjoner, legger besparelsene opp Og dette er grunnen til at det kalles Indirekte tråder. Kvoturnetten fra subroutinequot er ordet EXIT, som blir kompilert når Forth ser. (Noen fremover kaller det S i stedet for EXIT.) EXIT utfører bare en maskinsprogrutine som gjør følgende: Gå gjennom et par nestede Forth definisjoner, for å forsikre deg selv om at dette fungerer. Legg merke til egenskapene til ITC: hvert fremre ord har et en-celle kodefelt. Kolondefinisjoner kompilere en celle for hvert ord som brukes i definisjonen. Og den fremre tolken må faktisk utføre en dobbelt indireksjon for å få adressen til den neste maskinkoden å løpe (først gjennom IP, deretter gjennom W). ITC er hverken den minste eller den raskeste gjengeteknikken. Det kan være den enkleste, selv om DTC (beskrevet neste) egentlig ikke er mer komplisert. Så hvorfor er så mange Forths indirekte-threaded Hovedsakelig fordi tidligere Forths, brukt som modeller, var indirekte-threaded. I disse dager blir DTC blitt mer populært. Så når skal ITC bli brukt Av de ulike teknikkene produserer ITC de reneste og mest elegante definisjonene - ingenting annet enn adresser. Hvis du er avhengig av slike hensyn, kan ITC appellere til deg. Hvis koden fins rundt med innsiden av definisjonene, kan enkelheten og ensartetheten av ITC-representasjonen øke overførbarheten. ITC er den klassiske Forth-modellen, så det kan være foretrukket for utdanning. Til slutt, på CPUer som mangler en subrutine-anropsinstruksjon - for eksempel 1802 - ITC er ofte mer effektiv enn DTC. Direct Threaded Code (DTC) Direct Threaded Code er forskjellig fra ITC i bare én respekt: ​​i stedet for kodefeltet som inneholder adressen til en maskinkode, inneholder kodefeltet selve maskinskoden selv. Jeg sier ikke at den komplette koden for ENTER er inneholdt i hver kolondefinisjon I quothigh-levelquot Frem ord, vil kodefeltet inneholde et subrutineanrop. som vist i figur 2. Kolondefinisjoner, for eksempel, vil inneholde et anrop til ENTER-rutinen. NESTE pseudo-koden for direkte tråder er rett og slett: Dette gir hastighet: tolken utfører nå bare en enkelt indireksjon. På Z80 reduserer dette NEXT-rutinen - det mest brukte kodefragmentet i den fremre kjernen - fra elleve instruksjoner til syv. Dette koster plass: hver høydefinisjonsdefinisjon i en Z80 Forth (for eksempel) er nå en byte lenger, siden en 2-byte-adresse er erstattet av et 3-byte-anrop. Men dette er ikke helt sant. En 32-bit 68000 Forth kan erstatte en 4-byte-adresse med en 4-byte BSR-instruksjon, uten tap av nett. Og på Zilog Super8, som har maskininstruksjoner for DTC Forth, erstattes 2-byte-adressen med en 1-byte ENTER-instruksjon, noe som gjør DTC Forth mindre på Super8 Selvfølgelig er DTC CODE-definisjonene to byte kortere, siden de Jeg trengte ikke lenger en pointer. Jeg pleide å tro at definisjoner på høyt nivå i DTC Forths krevde bruk av et subrutineanrop i kodefeltet. Frank Sergeants Pygmy Forth SER90 demonstrerer at et enkelt hopp kan brukes like enkelt, og vil vanligvis være raskere. Guy Kelly har samlet en flott gjennomgang av Forth-implementeringer for IBM PC KEL92, som jeg sterkt anbefaler til alle kjerneforfattere. Av 19 Forths studerte han, brukte 10 DTC, 7 brukte ITC og 2 brukte subrutine-tråder (diskuteres neste). Jeg anbefaler bruk av Direct-Threaded Code over Indirect-Threaded Code for alle nye Forth-kjerner. Hopp til NEXT, eller kodes det in-line Den fremre indre tolk, NEXT, er en felles rutine for alle CODE-definisjoner. Du kan bare beholde en kopi av denne vanlige rutinen, og få alle CODE-ordene til å hoppe over det. (Merk at du hopper til NEXT en subrutine Ring er ikke nødvendig.) Hastigheten til NEXT er imidlertid avgjørende for hastigheten til hele Forth-systemet. Også på mange CPUer er NEXT-rutinen ganske kort, ofte bare to eller tre instruksjoner. Så det kan være å foretrekke å kode NEXT in-line, uansett hvor det er brukt. Dette gjøres ofte ved å lage NEXT en assembler-makro. Dette er en enkel hastighet versus plassbeslutning: in-line NEXT er alltid raskere, men nesten alltid større. Den totale størrelsesøkningen er antall ekstra byte som kreves for utvidelse i linje, ganger antall CODE-ord i systemet. Noen ganger er det ingen bytte i det hele tatt: i en 6809 DTC Forth, er en in-line NEXT kortere enn en Jump Instruction Subroutine Threaded Code (STC). En høydefinisjon på forhånd er ingenting annet enn en liste over underrutiner som skal utføres. Du trenger ikke tolker for å oppnå dette, men du kan få samme effekt ved å bare stryke en liste over subrutine samtaler sammen: Se figur 3. Denne representasjonen av Forth-ord har blitt brukt som utgangspunkt for å forklare Forth threading teknikker til montering språk programmerere KOG82. STC er en elegant representasjon kolon definisjoner og CODE ord er nå identiske. quotDefined wordsquot (VARIABLEs, CONSTANTs og lignende) håndteres på samme måte som i DTC - kodefeltet begynner med et hopp eller ring til noen maskinkode andre steder. Den største ulempen er at subrutineanrop vanligvis er større enn enkle adresser. På Z80, for eksempel, øker størrelsen på kolondefinisjonene med 50 - og det meste av søknaden er kolondefinisjoner Kontrarivis, på 32-biters 68000 kan det ikke være noen størrelsesøkning i det hele tatt når 4-byte-adresser erstattes med 4-byte BSRer. (Men hvis kodestørrelsen overskrider 64K, må noen av disse adressene byttes ut med 6-bytes JSR.) Subroutine-tråden kan være raskere enn direkte tråder. Du sparer tid ved ikke å ha tolk, men du mister tid fordi alle henvisninger til et fremtidsord innebærer en trykk og pop på en returadresse. I en DTC Forth, forårsaker kun høyt nivå ord på aktivitet på returbunken. På 6809 eller Zilog Super8 er DTC raskere enn STC. Det er en annen fordel for STC: den dispenserer med IP-registeret. Noen prosessorer - som 8051 - er desperat kort for å adressere registre. Å eliminere IP kan virkelig forenkle og øke hastigheten på kjernen. Den eneste måten å vite, er å skrive eksempelkode. Dette er nært involvert med registervalg, diskutert i neste avsnitt. STC med direkte ekspansjonsoptimalisering på eldre og 8-bits CPUer, omfatter nesten alle tidligere primitive flere maskininstruksjoner. Men på mer kraftige CPUer, er mange tidligere primitiver skrevet i en enkelt instruksjon. For eksempel på 32-bit 68000 er DROP ganske enkelt I en subrutin-threaded Forth, ved å bruke DROP i et kolon definisjon vil resultere i sekvensen ADDQ er en tobyte instruksjon. Hvorfor skrive en firebyte-subrutineanrop til en tobyte-instruksjon Uansett hvor mange ganger DROP er brukt, er det ingen besparelser Koden er mindre og raskere hvis ADDQ er kodet direkte inn i strømmen av BSRer. Noen fremtredende kompilatorer gjør dette kvote-line expansionskvoten av CODE-ordene CUR93a. Ulempen med in-line ekspansjon er at dekompilering tilbake til den opprinnelige kildekoden blir svært vanskelig. Så lenge subroutine-anrop brukes, har du fremdeles pekere (subrutinadressene) til de fremre ordene som omfatter tråden. Med pekere til ordene, kan du få navnene sine. Men når et ord er utvidet til in-line-kode, er all kunnskap om hvor den koden kommer fra, tapt. Fordelen med in-line ekspansjon - bortsett fra hastighet og størrelse - er potensialet for kodeoptimalisering. For eksempel vil Forth-sekvensen bli kompilert i 68000 STC som, men kunne utvides i tråd som en enkelt maskininstruksjon. Optimering Forth compilers er for bredt et emne for denne artikkelen. Dette er et aktivt område av Forth språkforskning se for eksempel SCO89 og CUR93b. Den endelige kulminasjonen av optimalisert STC er en Forth som kompilerer til quotpurequot maskinkode, akkurat som en C - eller Fortran-kompilator. Token trådkode (TTC) DTC og STC tar sikte på å forbedre hastigheten på fremtidige programmer, til en viss pris i minnet. Nå kan vi flytte den andre retningen fra ITC, mot noe langsommere men mindre. Formålet med en videre tråd er å spesifisere en liste over fremtredende ord (subrutiner) som skal utføres. Anta at et 16-biters Forth-system bare hadde maksimalt 256 forskjellige ord. Deretter kunne hvert ord unikt identifiseres med et 8-biters tall. I stedet for en liste over 16-biters adresser, vil du ha en liste over 8-biters identifikatorer eller quottokens, og kvadratstørrelsenes definisjoner vil bli halvert. En token-threaded Forth beholder en tabell med adresser på alle fremtredende ord, som vist i figur 4. Tollverdien brukes deretter til å indeksere i denne tabellen for å finne fremre ord som svarer til et gitt token. Dette legger til et nivå av indireksjon til den fremre tolken, så det er tregere enn en kvadratkryss-threadedquot Forth. Hovedfordelen ved token-threaded Forths er liten størrelse. TTC er mest sett i håndholdte datamaskiner og andre alvorlige størrelsesbegrensede applikasjoner. Dessuten kan tabellen med quotentrypoints i alle Forth-ordene forenkle sammenkobling av separatutviklede moduler. Ulempen med TTC er hastighet: TTC gjør den tregeste fremtiden. TTC-kompilatoren er også litt mer kompleks. Hvis du trenger mer enn 256 Forth-ord, er det nødvendig å ha en åpen kodingsordning for å blande 8-biters og større tokens. Jeg kan forestille en 32-biters Forth ved hjelp av 16-biters tokens, men hvor mange 32-biters systemer er størrelsesbegrenset Segment Threaded Code Siden det er så mange 8086-derivater i verden, fortjener segmenttråden en kort omtale. I stedet for å bruke quotumormalquot byte-adresser i et 64K-segment, brukes avsnittadresser. (En kvotestilling er 16 byte i 8086.) Så kan tolken laste disse adressene inn i segmentregistre, i stedet for å inn i de vanlige adressene. Dette tillater en 16-biters Forth-modell for effektivt å få tilgang til hele megabyte 8086-minnet. Den viktigste ulempen ved segmenttråden er 16-byte kvadratkvotalitetskvoten i minnet. Hvert fremre ord må være justert til en 16-byte grense. Hvis Forth ord har tilfeldige lengder, vil et gjennomsnitt på 8 byte bli bortkastet per Forth ord. REGISTRERING AV TILDELING Ved siden av gjengeteknikken er bruk av CPU-registre den mest avgjørende designbeslutningen. Det er sannsynligvis det vanskeligste. Tilgjengeligheten av CPU-registre kan avgjøre hvilken trådeteknikk som kan brukes, og til og med hva minnekortet vil være De klassiske fremkallingsregistrene Den klassiske Forth-modellen har fem kvotetiske registers. quot Disse er abstrakte enheter som brukes i primitive operasjoner av Forth. NEXT, ENTER og EXIT ble tidligere definert i form av disse abstrakte registre. Hver av disse er en cellevidde - det vil si i 16-biters Forth, disse er 16-biters register. (Det er unntak fra denne regelen, som du vil se senere.) Disse er kanskje ikke alle CPU-registre. Hvis CPUen ikke har nok register, kan noen av disse lagres i minnet. Jeg beskriver dem i rekkefølgen av deres betydning, dvs. bunnen av denne listen er de beste kandidatene som skal lagres i minnet. W er arbeidsregisteret. Den brukes til mange ting, inkludert minne referanse, så det skal være et adresseregister, dvs. du må kunne hente og lagre minne ved hjelp av innholdet i W som adresse. Du må også kunne gjøre aritmetikk på W. (I DTC Forths må du også kunne hoppe indirekte ved hjelp av W.) W brukes av tolken i hvert forutgående ord. I en CPU som bare har ett register, vil du bruke det til W og beholde alt annet i minnet (og systemet vil være utrolig sakte). IP er tolkpointeren. Dette brukes av hvert forkortet ord (gjennom NEXT, ENTER eller EXIT). IP må være et adresseregister. Du må også kunne øke IP. Subroutine threaded Forths trenger ikke dette registret. PSP er Parameter Stack (eller quotdata stackquot) Pointer, noen ganger kalt bare SP. Jeg foretrekker PSP fordi SP ofte er navnet på et CPU-register, og de bør ikke forveksles. De fleste CODE-ord bruker dette. PSP må være en stabelpeker eller et adresseregister som kan økes og dekrementeres. Det er også et pluss hvis du kan gjøre indeksert adressering fra PSP. RSP er Return Stack Pointer, noen ganger kalt bare RP. Dette brukes av kolondefinisjoner i ITC og DTC Forths, og av alle ord i STC Forths. RSP må være en stabelpeker, eller et adresseregister som kan økes og dekrementeres. Hvis i det hele tatt mulig. sett W, IP, PSP, og RSP i registre. De virtuelle registre som følger kan holdes i minnet, men det er vanligvis en rask fordel å holde dem i CPU-registre. X er et arbeidsregister, ikke betraktet som et av kvoteklassifiseringen Forth-register, selv om den klassiske ITC Forths trenger det for den andre indireksjonen. I ITC må du kunne hoppe indirekte ved hjelp av X. X kan også brukes av noen CODE-ord for å gjøre aritmetiske og lignende. Dette er spesielt viktig på prosessorer som ikke kan bruke minne som operand. For eksempel kan ADD på en Z80 være (i pseudokode) Noen ganger er et annet arbeidsregister, Y, også definert. UP er brukerpekeren, og holder basen til oppgavens brukerområde. UP er vanligvis lagt til en forskyvning, og brukes av høyt nivå fremkodskode, så det kan bare lagres et sted. Men hvis CPUen kan gjøre indeksert adressering fra UP-registeret, kan CODE-ordene lettere og raskt få tilgang til brukervariabler. Hvis du har et overskudd av adresseregister, bruk en for UP. Enkeltoppgave fremover trenger ikke opp. X - om nødvendig - er viktigere å være i register enn UP. UP er det enkleste av de fremre virtuelle registre for å flytte inn i minnet. Bruk av maskinvarestabletten De fleste CPUer har en stabelpeker som en del av maskinvaren, som brukes av interrupts og subroutine-samtaler. Hvordan går dette kartet inn i Forth-registerene Skulle det være PSP eller RSP Det korte svaret er, det avhenger. Det sies at PSP brukes mer enn RSP i ITC og DTC Forths. Hvis CPUen har få adresseregister, og PUSH og POP er raskere enn eksplisitt referanse, bruker du maskinvarebunken som Parameter Stack. På den annen side, hvis CPUen er rik på adressemoduser - og tillater indeksert adressering - er det et pluss å ha PSP som et generelt adresseliste. I dette tilfellet bruker du maskinvarebunken som Return Stack. Noen ganger gjør du heller ikke TMS320C25s maskinvarebunke er bare åtte celler dyp - alt annet enn ubrukelig for Forth. Derfor er maskinvarebunken bare brukt for avbrudd, og både PSP og RSP er adresseregister med generelle formål. (ANS Forth angir minst 32 celler av Parameter Stack og 24 celler av Return Stack Jeg foretrekker 64 celler av hver.) Du vil av og til støte på dogmaen som maskinvarebunken kvitterer for Parameter Stack, eller du kan få tilbake Return Stack. I stedet kodes noen eksempler fremfor primitive, for eksempel og se hvilken tilnærming som er mindre eller raskere. (DUP og DROP, forresten, er ingen test - de er vanligvis trivielle.) Noen ganger når du underlige konklusjoner Gary Bergstrom har påpekt at en 6809 DTC Forth kan gjøres noen få sykluser raskere ved å bruke 6809 brukerstabelpekeren som IP NEXT blir en POP. Han bruker et indeksregister for en av Forths stabler. Top-Of-Stack in Register Fremtidig ytelse kan forbedres betraktelig ved å holde toppelementet i Parameter Stack i et register. Mange Utgående ord (for eksempel 0) trenger ikke å bruke stakken. Andre ord gjør fortsatt det samme antallet pushes og pops, bare på et annet sted i koden. Bare noen få Forth ord (DROP og 2DROP) blir mer komplisert, siden du ikke lenger kan justere stakkpekeren - du må også oppdatere TOS-registeret også. Det er noen regler når du skriver CODE-ord: Et ord som fjerner elementer fra stakken må legge til quotnewquot-TOS i sitt register. Et ord som legger til elementer i stabelen, må skyve quotoetquot-TOS på bunken (med mindre det forbruker av ordet). Hvis du har minst seks CPU-registre i celleformat, anbefaler jeg at du holder TOS i et register. Jeg anser TOS mer viktig enn UP å ha i register, men mindre viktig enn W, IP, PSP og RSP. (TOS i register utfører mange av funksjonene i X-registret.) Det er nyttig hvis dette registeret kan utføre minneadressering. PDP-11s, Z8s og 68000s er gode kandidater. Ni av de 19 IBM PC Forths studert av Guy Kelly KEL92 holder TOS i register. Jeg tror at denne innovasjonen har blitt motstått på grunn av den falske oppfatningen at a) den legger til instruksjoner, og b) toppstakkelementet må være tilgjengelig som minne. Det viser seg at selv slike ord som PICK, ROLL og DEPTH blir trivielt modifisert for TOS-in-register. Hva med å buffere to stakkelementer i registre Når du holder toppen av stabelen i et register, blir det totale antallet operasjoner som utføres, stort sett det samme. Et trykk er et trykk, uansett om det er før eller etter operasjonen du utfører. På den annen side legger buffering av to stakkelementer i registre et stort antall instruksjoner - et trykk blir et trykk etterfulgt av et trekk. Bare dedikerte Forth-prosessorer som RTX2000 og utrolig smart optimaliserende kompilatorer kan dra nytte av å buffere to stablingselementer i registre. Noen eksempler Her er registeroppdragene laget av Forths for en rekke forskjellige CPUer. Prøv å utlede designbeslutningen fra forfatterne fra denne listen. quotSPquot refererer til harddiskpekeren. quotZpagequot refererer til verdier som holdes på 6502s minne side null, som er nesten like nyttige som - noen ganger mer nyttige enn - verdier holdt i registre, f. eks. de kan brukes til minneadressering. quotFixedquot betyr at Paynes 8051 Forth har et enkelt, ubrukelig brukerområde, og UP er en hardkodet konstant. Smalregistreringer Merk noe som er ukjent i forrige liste 6502 Forth - en 16-biters modell - bruker 8-biters stavepoints Det er mulig å lage PSP, RSP og UP mindre enn cellens størrelse på Forth. Dette skyldes at stablene og brukerområdet begge er relativt små områder av minnet. Hver stabel kan være så liten som 64 celler i lengde, og brukerområdet overskrider sjelden 128 celler. Du trenger bare å sikre at enten a) disse dataområdene er begrenset til et lite område med minne, så en kort adresse kan brukes, eller b) de høye adressebitene er gitt på en annen måte, f. eks. velg en minneside. I 6502 er maskinvarebunken begrenset til side 1 av RAM (adresser 01xxh) ved utformingen av CPU. 8-punkts pekepekeren kan brukes til Return Stack. Parameterstakken holdes på siden null for RAM, som kan indirekte nås av 8-biters indeksregister X. (Spørsmål til den avanserte studenten: hvorfor bruk 6502s X, og ikke Y Hint: se på adresseringsmodusene som er tilgjengelige. ) I 8051 kan du bruke 8-bitregistrene R0 og R1 til å adressere eksternt RAM, forutsatt at du eksplisitt sender ut de høye 8 bitene til adressen til port 2. Dette tillater en kvote seleksjon for to stabler. UP er forskjellig fra PSP og RSP: det gir bare en basisadresse, den blir aldri økt eller redusert. Så det er praktisk å levere kun de høye biter av dette virtuelle registeret. De lave bitene må da leveres med hvilken indeksert adresseringsteknikk som benyttes. For eksempel på 6809 kan du bruke DP-registeret til å holde de høye 8 bitene av UP, og deretter bruke Direct Page adressering for å få tilgang til noen av de 256 stedene på denne siden. Dette tvinger alle brukerområdene til å begynne på en adresse xx00h, noe som ikke er stor motgang, og begrenser brukerområdet til 128 celler i lengde. På 8086 kan du tenkelig bruke et segmentregister for å angi basisadressen til brukerområdet. REFERANSER CUR93a Curley, Charles, quotLife i FastForth Lane, citerer venter på publikasjon i Forth Dimensions. Beskrivelse av en 68000 subrutin-gjenget Forth. CUR93b Curley, Charles, quotOptimizing i en BSRJSR Threaded Forth, quote venter publikasjon i Forth Dimensions. Enkeltpass kodeoptimalisering for FastForth, i bare fem skjermbilder med kode Inkluderer notering. KEL92 Kelly, Guy M. quotForth Systems Comparisons, quot. Forth Dimensions XIII: 6 (MarApr 1992). Også publisert i 1991 FORML Conference Proceedings. Begge er tilgjengelige fra Forth Interest Group, P. O. Box 2154, Oakland, CA 94621. Illustrerer designavvik fra mange 8086 Forths med kodefragmenter og benchmarks - sterkt anbefalt KOG82 Kogge, Peter M. quotAn Architectural Trail til Threaded Code Systems, citerer IEEE Computer, vol. 15 nr. 3 (mar 1982). Fortsetter den endelige beskrivelsen av ulike gjengeteknikker. ROD91 Rodriguez, B. J. quotB. Y.O. Assembler, sitat Del 1, The Computer Journal 52 (SepOct 1991). Generelle prinsipper for skriving Forth assemblers. ROD92 Rodriguez, B. J. quot. B.Y. O. Assembler, sitat Del 2, The Computer Journal 54 (JanFeb 1992). En 6809 assembler i Forth. SCO89 Scott, Andrew, quotAn Extensible Optimizer for Compiling Forward, citerer 1989 FORML Conference Proceedings. Forth Interest Group, P. O. Box 2154, Oakland, CA 94621. God beskrivelse av en 68000 optimaliserer ingen kode som er oppgitt. CUR86 Curley, Charles, Real-Forth for 68000. privat distribuert (1986). JAM80 James, John S. fig-Forth for PDP-11. Forth Interest Group (1980). KUN81 Kuntze, Robert E. MVP-Forth for Apple II. Mountain View Press (1981). LAX84 Laxen, H. og Perry, M. F83 for IBM PC. versjon 2.1.0 (1984). Distribuert av forfatterne, tilgjengelig fra Forth Interest Group eller GEnie. LOE81 Loeliger, R. G. Gjengetolkende språk. BYTE Publikasjoner (1981), ISBN 0-07-038360-X. Kan være den eneste boken som er skrevet om emnet for å skape en fremkalt kjernekode (eksempelet som brukes er Z80). Verdt det hvis du finner en kopi. MPE92 MicroProcessor Engineering Ltd MPE Z8Super8 PowerForth Mål. MPE Ltd. 133 Hill Lane, Shirley, Southampton, S01 5AF, U. K. (juni 1992). Et kommersielt produkt. PAY90 Payne, William H. Embedded Controller FORTH for 8051-familien. Academic Press (1990), ISBN 0-12-547570-5. Dette er en komplett kvotekvot for en 8051 Forth, inkludert en metakompiler for IBM PC. Hardcopy-filer kan lastes ned fra GEnie. Ikke for nybegynner SER90 Sergeant, Frank, Pygmy Forth for IBM PC. versjon 1.3 (1990). Distribuert av forfatteren, tilgjengelig fra Forth Interest Group. Versjon 1.4 er nå tilgjengelig på GEnie, og verdt den ekstra innsatsen å skaffe. TAL80 Talbot, R. J. fig-Forth for 6809. Forth Interest Group (1980). Forfattere notat for webpublisering: Filene som tidligere var tilgjengelige på GEnie online-tjenesten, er nå tilgjengelig fra FTP-serveren Forth Interest Group, ftp: ftp. forth. orgpubForth. KODETS NATUR Kodenes natur Innledning Jeg er to med naturen. Woody Allen Her er vi: begynnelsen. Vel, nesten begynnelsen. Hvis det har vært en stund siden du har gjort noen programmering i Prosessering (eller hvilken som helst matte, for det saks skyld), vil denne introduksjonen få deg til å tenke på beregningstanker før vi nærmer deg noe av det vanskeligste og komplekse materialet. I kapittel 1 skulle vi snakke om begrepet vektor og hvordan det vil fungere som byggestein for å simulere bevegelse gjennom hele denne boken. Men før vi tar det trinnet, kan vi tenke på hva det betyr for noe å bare flytte rundt på skjermen. La oss begynne med en av de mest kjente og enkleste simuleringene av bevegelse av tilfeldig gange. I.1 Tilfeldige turer Tenk deg at du står midt i en balanse. Hvert tiende sekund spretter du en mynt. Hodet, ta et skritt fremover. Haler, ta et skritt bakover. Dette er en tilfeldig walka-sti definert som en rekke tilfeldige trinn. Når du drar av denne balansen og på gulvet, kan du utføre en tilfeldig tur i to dimensjoner ved å bla den samme mynt to ganger med følgende resultater: Ja, dette kan virke som en spesielt usofistikert algoritme. Likevel kan tilfeldige turer brukes til å modellere fenomener som oppstår i den virkelige verden, fra bevegelsene til molekyler i en gass til at en gambler oppfører seg en dag på kasinoet. Som for oss begynner vi denne boken å studere en tilfeldig tur med tre mål i tankene. Vi må gjennomgå et programmeringsbegrep sentralt i denne bokobjektorienterte programmeringen. Den tilfeldige walker vil fungere som en mal for hvordan vi skal bruke objektorientert design for å lage ting som beveger seg rundt et behandlingsvindu. Den tilfeldige spaserturen ansporer de to spørsmålene som vi vil spørre om og om igjen i denne boken: Hvordan definerer vi reglene som styrer oppførselen til våre objekter og deretter Hvordan implementerer vi disse reglene i Behandling Gjennom boken, må du regelmessig trenge en grunnleggende forståelse av tilfeldighet, sannsynlighet og Perlin-støy. Den tilfeldige turen vil gjøre det mulig for oss å demonstrere noen få viktige punkter som kommer til nytte senere. I.2 Random Walker Class Lets gjennomgå litt objektorientert programmering (OOP) først ved å bygge et Walker objekt. Dette vil bare være en oversiktlig gjennomgang. Hvis du aldri har jobbet med OOP før, kan det hende du vil ha noe mer omfattende ID, foreslår at du stopper her og vurderer det grunnleggende på Processing-nettstedet før du fortsetter. Et objekt i Behandling er en enhet som har både data og funksjonalitet. Vi ser på å designe et Walker-objekt som både holder oversikt over dataene (hvor det finnes på skjermen) og har mulighet til å utføre bestemte handlinger (som å trekke seg selv eller ta et skritt). En klasse er malen for å bygge faktiske forekomster av objekter. Tenk på en klasse som cookie cutter objektene er informasjonskapslene selv. La oss begynne med å definere Walker-klassen hva det betyr å være et Walker-objekt. Walker trenger bare to deler data-nummer for sin x-plassering og en for sin y-plassering. Objekter har data. Siden vi bare tegner bakgrunnen en gang i oppsettet (). heller enn å rydde det kontinuerlig hver gang gjennom tegning (). Vi ser sporet av den tilfeldige spaserturen i Behandlingsvinduet. Nettleseren din støtter ikke lerretet. Det er et par forbedringer vi kunne gjøre til tilfeldig walker. For en, er denne Walker s trinn valg begrenset til fire opsjoner, ned, venstre og høyre. Men en hvilken som helst piksel i vinduet har åtte mulige naboer, og en niende mulighet er å forbli på samme sted. For å implementere et Walker-objekt som kan gå til en nabobilde (eller bli satt), kan vi velge et tall mellom 0 og 8 (ni mulige valg). En mer effektiv måte å skrive koden på ville imidlertid være å velge mellom tre mulige trinn langs x-aksen (-1, 0 eller 1) og tre mulige trinn langs y-aksen. Utbytter -1, 0 eller 1 Alle disse variasjonene på den tradisjonelle tilfeldige gangen har en ting til felles: Sannsynligheten for at Walker vil ta et skritt i en gitt retning, til enhver tid er lik sannsynligheten for at Walker vil ta et skritt i hvilken som helst retning. Med andre ord, hvis det er fire mulige trinn, er det en 1 til 4 (eller 25) sjanse for at Walker vil ta et gitt skritt. Med ni mulige trinn er det en 1 i 9 (eller 11.1) sjanse. Praktisk, slik fungerer tilfeldig () - funksjonen. Behandler random number generator (som opererer bak kulissene) produserer det som er kjent som en jevn fordeling av tall. Vi kan teste denne distribusjonen med en behandlingsskisse som teller hver gang et tilfeldig tall blir plukket og graver det som høyden på et rektangel. Nettleseren din støtter ikke lerretet. Eksempel I.2: Tilfeldig nummerfordeling Et array for å holde oversikt over hvor ofte tilfeldige tall blir plukket. Velg et tilfeldig tall og øk antallet. Grafering av resultatene Skjermbildet ovenfor viser resultatet av skissen som kjører i noen få minutter. Legg merke til hvordan hver linje av grafen varierer i høyde. Vår utvalgsstørrelse (dvs. antall tilfeldige tall vi har plukket) er ganske liten, og det er noen sporadiske avvik, hvor enkelte numre blir plukket oftere. Over tid, med en god tilfeldig talgenerator, ville dette til og med ut. Pseudo-tilfeldige tall De tilfeldige tallene vi får fra random () - funksjonen er ikke helt tilfeldige, derfor er de kjent som pseudo-tilfeldig. De er resultatet av en matematisk funksjon som simulerer tilfeldighet. Denne funksjonen vil gi et mønster over tid, men den tidsperioden er så lang at for oss er det like bra som ren tilfeldighet. Øvelse I.1 Opprett en tilfeldig rullator som har en tendens til å bevege seg ned og til høyre. (Vel se løsningen på dette i neste avsnitt.) I.3 Sannsynlighet og ikke-ensartede distribusjoner Husk når du begynte programmering i prosessering Kanskje du ønsket å tegne mange sirkler på skjermen. Så sa du til deg selv: Å, jeg vet det. Jeg tegner alle disse kretsene på tilfeldige steder, med tilfeldige størrelser og tilfeldige farger. I et datagrafikksystem er det ofte enklest å frøke et system med tilfeldighet. I denne boken var imidlertid ute på å bygge systemer modellert på det vi ser i naturen. Forsinkelse til tilfeldighet er ikke en spesielt gjennomtenkt løsning på et designproblem spesielt, det slags problem som innebærer å skape en organisk eller naturlig utseende simulering. Med noen få triks kan vi endre måten vi bruker tilfeldig () til å produsere ujevne distribusjoner av tilfeldige tall. Dette vil komme til nytte gjennom hele boken, da vi ser på en rekke forskjellige scenarier. Når vi undersøker genetiske algoritmer, for eksempel, trenger vi en metode for å utføre utvalg som medlemmer av vår befolkning bør velges for å videresende deres DNA til neste generasjon. Husk konseptet om overlevelse av de hardeste. Vi sier at vi har en populasjon av aper som utvikler seg. Ikke hver ape vil ha en like sjanse til å reprodusere. For å simulere Darwinian evolusjon kan vi ikke velge to tilfeldige aper for å være foreldre. Vi trenger de mer passende som er mer sannsynlig å bli valgt. Vi må definere sannsynligheten for de fitteste. For eksempel kan en spesielt rask og sterk ape ha 90 sjanser til å vokse, mens en svakere har bare 10 sjanser. Lar pause her og ta en titt på sannsynligheter grunnprinsipper. Først bør du undersøke enkelthendelsessannsynlighet, det vil si sannsynligheten for at en gitt hendelse vil oppstå. Hvis du har et system med et visst antall mulige utfall, er sannsynligheten for forekomsten av en gitt hendelse lik antall utfall som kvalifiserer som den hendelsen delt på det totale antallet av alle mulige utfall. En myntkast er et enkelt eksempel, har bare to mulige utfall, hoder eller haler. Det er bare en måte å svinge hoder på. Sannsynligheten for at mynten vil slå opp hodene er derfor en delt med to: 12 eller 50. Ta et kort med to og femti kort. Sannsynligheten for å tegne et ess fra det dekket er: Antall ess Antall kort 4 52 0,077 Sannsynligheten for å tegne en diamant er: Antall diamanter Antall kort 13 52 0,25 25 Vi kan også beregne sannsynligheten for at flere hendelser forekommer i rekkefølge . For å gjøre dette, mangler vi bare de individuelle sannsynlighetene for hver hendelse. Sannsynligheten for at en mynt setter opp hodene tre ganger på rad, er: (12) (12) (12) 18 (eller 0,125) som betyr at en mynt vil skru opp hodene tre ganger på rad en av åtte ganger (hver gang å være tre kaster). Øvelse I.2 Hva er sannsynligheten for å tegne to ess på rad fra et kort på to og to kort. Det er et par måter der vi kan bruke tilfeldig () - funksjonen med sannsynlighet i kode. Én teknikk er å fylle en matrise med et utvalg av tallrike som gjentas, og velg tilfeldige tall fra det arrayet og generer hendelser basert på disse valgene. 1 lagres i gruppen to ganger, noe som gjør det mer sannsynlig å bli plukket. Øvelse I.3 Lag en tilfeldig rullator med dynamiske sannsynligheter. For eksempel kan du gi det en 50 sjanse til å bevege seg i retning av musen. I.4 En Normal Fordeling av tilfeldige tall Lar oss gå tilbake til den populasjonen av simulerte behandlingsapene. Programmet genererer tusen Monkey-objekter, hver med en høydeverdi mellom 200 og 300 (da dette er en verden av apekatter som har høyder mellom 200 og 300 piksler). Gjør dette nøyaktig avbildet høydene til virkelige vesener Tenk på en overfylt fortau i New York City. Velg noen personer utenfor gaten, og det kan se ut som at deres høyde er tilfeldig. Likevel er det ikke den typen tilfeldig som tilfeldig () produserer. Folkens høyder er ikke jevnt fordelt. Det er mye flere folk i gjennomsnittlig høyde enn det er svært høye eller svært korte. For å simulere naturen, vil vi kanskje ha det mer sannsynlig at våre aper er av gjennomsnittlig høyde (250 piksler), men likevel tillate at de til tider er svært korte eller svært høye. En fordeling av verdier som klynger rundt et gjennomsnitt (referert til som gjennomsnittet) er kjent som en normal fordeling. Det kalles også den gaussiske distribusjonen (oppkalt etter matematiker Carl Friedrich Gauss) eller, hvis du er fransk, den Laplacian-distribusjonen (oppkalt etter Pierre-Simon Laplace). Begge matematikere jobbet samtidig i begynnelsen av det nittende århundre på å definere en slik fordeling. Når du graverer fordelingen, får du noe som ser ut som følgende, uformelt kjent som en bellkurve: Kurven genereres av en matematisk funksjon som definerer sannsynligheten for at en gitt verdi forekommer som en funksjon av middelværdien (ofte skrevet som, det greske bokstaveret mu) og standardavviket (det greske bokstaven sigma). Gjennomsnittet er ganske enkelt å forstå. Når det gjelder våre høydeverdier mellom 200 og 300, har du sannsynligvis en intuitiv følelse av gjennomsnittet (dvs. gjennomsnittlig) som 250. Men hva om jeg skulle si at standardavviket er 3 eller 15 Hva betyr dette for det tall Grafene ovenfor skal gi oss et hint. Grafen til venstre viser oss fordelingen med en svært lav standardavvik, hvor de fleste verdiene klynges tett rundt gjennomsnittet. Grafen til høyre viser oss en høyere standardavvik, hvor verdiene er jevnere fordelt ut fra gjennomsnittet. Tallene trekker seg ut som følger: Gitt en befolkning, vil 68 av medlemmene av denne befolkningen ha verdier i størrelsesorden én standardavvik fra gjennomsnittet, 98 innen to standardavvik og 99,7 innen tre standardavvik. Gitt et standardavvik på 5 piksler, vil bare 0,3 av apenhøyder være mindre enn 235 piksler (tre standardavvik under gjennomsnittet 250) eller større enn 265 piksler (tre standardavvik over gjennomsnittet på 250). Beregning av gjennomsnittlig og standardavvik Vurdere en klasse på ti studenter som får følgende karakterer (ut av 100) på en test: 85, 82, 88, 86, 85, 93, 98, 40, 73, 83 Standardavviket beregnes som kvadratroten av gjennomsnittet av firkantene av avvik rundt gjennomsnittet. Med andre ord, ta forskjellen fra gjennomsnittet for hver person og kvadrat det (varians). Beregn gjennomsnittet av alle disse verdiene og ta kvadratroten som standardavviket. Standardavviket er kvadratroten av den gjennomsnittlige variansen: 15.13 Heldigvis for oss, for å bruke en normal fordeling av tilfeldige tall i en behandlingsskisse, trenger vi ikke å gjøre noen av disse beregningene selv. I stedet kan vi gjøre bruk av en klasse som kalles Tilfeldig. som vi får gratis som en del av standard Java-biblioteker importert til Behandling (se JavaDocs for mer informasjon). For å bruke Random-klassen må vi først deklarere en variabel av typen Tilfeldig og opprette tilfeldig objekt i oppsettet (). Vi bruker variabelnavngeneratoren fordi det vi har her kan tenkes som en tilfeldig talegenerator. Hvis vi ønsker å produsere et tilfeldig tall med en normal (eller Gaussisk) distribusjon hver gang vi går gjennom tegning (). det er like enkelt som å kalle funksjonen nextGaussian (). Be om et gaussisk tilfeldig nummer. (Merk nextGaussian () returnerer en dobbel og må konverteres til float.) Heres saken. Hva skal vi gjøre med denne verdien Hva om vi ønsket å bruke den, for eksempel å tildele x-stillingen til en form som vi tegner på skjermen NesteGaussian () - funksjonen returnerer en normal fordeling av tilfeldige tall med følgende parametere: et middel på null og en standardavvik av en. La oss si at vi vil ha et gjennomsnitt på 320 (den midterste horisontale piksel i et vindu med bredde 640) og en standardavvik på 60 piksler. Vi kan justere verdien til parametrene ved å multiplisere den med standardavviket og legge til gjennomsnittet. Nettleseren din støtter ikke lerretet. Eksempel I.4: Gaussisk distribusjon Merk at nextGaussian () returnerer en dobbel. Multipliser med standardavviket og legg til gjennomsnittet. Ved å tegne ellipser oppå hverandre med litt gjennomsiktighet, kan vi faktisk se fordelingen. Det lyseste stedet er nær sentrum, hvor de fleste verdiene er klynget, men så ofte sirkler trekkes lenger til høyre eller til venstre for sentrum. Øvelse I.4 Vurder en simulering av malingsklatter tegnet som en samling av farget prikker. De fleste maleklynger rundt en sentral plassering, men noen punkter spretter ut mot kantene. Kan du bruke en normal fordeling av tilfeldige tall for å generere plasseringene til punktene. Kan du også bruke en normal fordeling av tilfeldige tall for å generere en fargepalett. Øvelse I.5 En Gaussisk tilfeldig tur er definert som en hvor trinnstørrelsen (hvordan langt objektet beveger seg i en gitt retning) genereres med en normal fordeling. Implementer denne variasjonen av vår tilfeldige tur. I.5 En tilpasset distribusjon av tilfeldige tall Det kommer en tid i livet ditt når du ikke vil ha en jevn fordeling av tilfeldige verdier, eller en gaussisk. La oss forestille oss et øyeblikk at du er en tilfeldig walker på jakt etter mat. Å flytte tilfeldig rundt en plass virker som en rimelig strategi for å finne noe å spise. Tross alt vet du ikke hvor maten er, så du kan også søke tilfeldig til du finner den. Problemet, som du kanskje har lagt merke til, er at tilfeldige vandrere går tilbake til tidligere besøkte steder mange ganger (dette kalles oversampling). En strategi for å unngå et slikt problem er å, så ofte, ta et veldig stort skritt. Dette tillater walker å tilfeldig tilfeldig rundt et bestemt sted, mens du jevnlig hopper veldig langt unna for å redusere mengden oversampling. Denne variasjonen på tilfeldig spasertur (kjent som et Lvy-fly) krever et tilpasset sett med sannsynligheter. Selv om det ikke er en nøyaktig implementering av et Lvy-fly, kan vi angi sannsynlighetsfordelingen som følger: jo lengre trinnet, desto mindre sannsynlig er det å bli plukket desto kortere trinnet, jo mer sannsynlig. Tidligere i denne prologgen så vi at vi kunne generere tilpassede sannsynlighetsfordelinger ved å fylle en matrise med verdier (noen kopierte slik at de ble plukket oftere) eller ved å teste resultatet av tilfeldig (). Vi kunne implementere et Lvy-fly ved å si at det er en sjanse for at walkeren tar et stort skritt. En 1 sjanse til å ta et stort skritt Men dette reduserer sannsynlighetene til et fast antall alternativer. Hva hvis vi ønsket å gjøre en mer generell regjeringen høyere et tall, desto mer sannsynlig er det å bli plukket 3.145 ville være mer sannsynlig å bli plukket enn 3,144, selv om denne sannsynligheten bare er en liten bit større. Med andre ord, hvis x er tilfeldig tall, kan vi kartlegge sannsynligheten for y-aksen med y x. Hvis vi kan finne ut hvordan du genererer en distribusjon av tilfeldige tall i henhold til grafen ovenfor, vil vi kunne bruke samme metode til enhver kurve som vi har en formel for. En løsning er å velge to tilfeldige tall i stedet for en. Det første tilfeldige tallet er bare det, et tilfeldig tall. Den andre er imidlertid det som kaller en kvalifiserende tilfeldig verdi. Det vil fortelle oss om å bruke den første eller kaste den bort og velge en annen. Nummer som har en lettere kvalifisering vil bli plukket oftere, og tall som sjelden kvalifiseres, blir plukket sjelden. Her er trinnene (for nå kan vi bare vurdere tilfeldige verdier mellom 0 og 1): Velg et tilfeldig tall: R1 Beregn en sannsynlighet P at R1 skal kvalifisere. La oss prøve: P R1. Velg et annet tilfeldig nummer: R2 Hvis R2 er mindre enn P, har vi funnet nummeret vårt1 Hvis R2 ikke er mindre enn P, gå tilbake til trinn 1 og start over. Her sier vi at sannsynligheten for at en tilfeldig verdi vil kvalifisere er lik det tilfeldige tallet selv. La oss si at vi velger 0,1 for R1. Dette betyr at R1 vil ha en 10 sjanse til kvalifisering. Hvis vi velger 0.83 for R1 så vil det ha 83 sjanse for kvalifisering. Jo høyere tallet er, desto større er sannsynligheten for at vi faktisk skal bruke den. Her er en funksjon (oppkalt etter Monte Carlo-metoden, som ble oppkalt etter Monte Carlo kasinoet) som implementerer ovennevnte algoritme, og returnerer en tilfeldig verdi mellom 0 og 1. Vi gjør dette for alltid til vi finner en kvalifiserende tilfeldig verdi. Øvelse I.6 Bruk en tilpasset sannsynlighetsfordeling for å variere størrelsen på et trinn tatt av den tilfeldige walker. Trinnstørrelsen kan bestemmes ved å påvirke utvalgte verdier valgt. Kan du kartlegge sannsynligheten exponentiallyi. e. gjør sannsynligheten for at en verdi plukkes lik verdien kvadratet En jevn fordeling av trinnstørrelser. Endre dette (Se senere, se hvordan dette gjøres mer effektivt ved hjelp av vektorer.) I.6 Perlin Noise (En jevnere tilnærming) En god tilfeldig talgenerator produserer tall som ikke har noe forhold og viser ingen merkbar mønster. Som vi begynner å se, kan en liten tilfeldighet være en god ting når du programmerer organisk, livlig oppførsel. Imidlertid er tilfeldighet som det eneste ledende prinsippet ikke nødvendigvis naturlig. En algoritme kjent som Perlin-støy, oppkalt etter oppfinneren Ken Perlin, tar dette konseptet i betraktning. Perlin utviklet støyfunksjonen mens han jobbet på den originale Tron-filmen tidlig på 1980-tallet. Den ble designet for å skape prosessuelle teksturer for datorgenererte effekter. I 1997 fikk Perlin en Oscar i teknisk prestasjon for dette arbeidet. Perlin støy kan brukes til å generere ulike effekter med naturlige egenskaper, for eksempel skyer, landskap og mønstrede teksturer som marmor. Perlin støy har et mer organisk utseende fordi det produserer en naturlig bestilt (jevn) rekkefølge av pseudo-tilfeldige tall. Grafen til venstre nedenfor viser Perlin-støy over tid, med x-aksen som representerer tiden, merker kurvens glatthet. Grafen til høyre viser rene tilfeldige tall over tid. (Koden for generering av disse grafene er tilgjengelig i de vedlagte boknedlastingene.) Figur I.5: Støy Figur I.6: Tilfeldig behandling har en innebygd implementering av Perlin støyalgoritmen: Funksjonsstøyen (). Funksjonen støy () tar en, to eller tre argumenter, da støy beregnes i en, to eller tre dimensjoner. La oss starte med å se på endimensjonal støy. Støydetaljer Beregningsstøyreferansen forteller oss at støy er beregnet over flere oktaver. Å ringe funksjonen noiseDetail () vil endre både antall oktaver og deres betydning i forhold til hverandre. Dette endrer seg i sin tur hvordan lydfunksjonen oppfører seg. En online forelesning av Ken Perlin lar deg lære mer om hvordan støy virker fra Perlin selv. Vurder å tegne en sirkel i prosesseringsvinduet på en tilfeldig x-plassering. En tilfeldig x-plassering Nå, i stedet for en tilfeldig x-plassering, vil vi ha en Perlin støy x-plassering som er jevnere. Du tror kanskje at alt du trenger å gjøre er å erstatte tilfeldig () med støy (). det vil si en støy x-plassering Mens det er konseptuelt, er dette akkurat det vi vil dokumentere en x-verdi som varierer mellom 0 og bredden i henhold til Perlin noisethis, er ikke riktig implementering. Mens argumentene til tilfeldig () - funksjonen angir en rekke verdier mellom minimum og maksimum, virker støy () ikke slik. I stedet er utdataområdet fast, og returnerer alltid en verdi mellom 0 og 1. Vel, se på et øyeblikk at vi lett kan komme seg rundt dette med prosesskart () - funksjonen, men først må vi undersøke hva nøyaktig støy () forventer at vi skal passere som et argument. Vi kan tenke på endimensjonal Perlin-støy som en lineær sekvens av verdier over tid. For eksempel: Hvor raskt vi øker t, påvirker også støynivået. Hvis vi lager store hopp i tide, hopper vi fremover og verdiene blir mer tilfeldige. Prøv å kjøre koden flere ganger, øke t med 0,01, 0,02, 0,05, 0,1, 0,0001, og du vil se forskjellige resultater. Mapping Noise Nå var klar til å svare på spørsmålet om hva du skal gjøre med støyverdien. Når vi har verdien med et område mellom 0 og 1, er det opp til oss å kartlegge dette området til det vi ønsker. Den enkleste måten å gjøre dette på er med Behandlingskart () - funksjonen. Kart () - funksjonen tar fem argumenter. Først opp er verdien vi ønsker å kartlegge, i dette tilfellet n. Da må vi gi det verdiene nåværende rekkevidde (minimum og maksimum), etterfulgt av vårt ønskede område. I dette tilfellet vet vi at støy har en rekkevidde mellom 0 og 1, men vi liker å tegne vår sirkel med et område mellom 0 og Windows-bredden. Legg merke til hvordan eksemplet ovenfor krever et ekstra par variabler: tx og ty. Dette skyldes at vi må holde styr på to tidsvariabler, en for x-plasseringen av Walker-objektet og en for y-stedet. Men det er noe litt rart om disse variablene. Hvorfor starter tx ved 0 og ty på 10 000 Selv om disse tallene er vilkårlig valg, har vi veldig spesifikt initialisert våre to-tidsvariabler med forskjellige verdier. Dette skyldes at støyfunksjonen er deterministisk: den gir deg det samme resultatet for en bestemt tid t hver gang. Hvis vi ba om støyverdien på samme tid t for både x og y. da vil x og y alltid være like, noe som betyr at Walker-objektet bare vil bevege seg langs en diagonal. I stedet bruker vi bare to forskjellige deler av støyrommet, starter ved 0 for x og 10 000 for y slik at x og y kan virke som uavhengig av hverandre. I sannhet er det ikke noe konkret tidsbegrep her. Det er en nyttig metafor for å hjelpe oss å forstå hvordan støyfunksjonen fungerer, men egentlig det vi har er plass, snarere enn tid. Grafen over viser en lineær sekvens av støyverdier i et endimensjonalt mellomrom, og vi kan be om en verdi på en bestemt x-plassering når vi vil. I eksempler vil du ofte se en variabel kalt xoff for å indikere x-offset langs støygrafen, i stedet for t for tid (som nevnt i diagrammet). Øvelse I.7 I ovennevnte tilfeldig ruller blir resultatet av støyfunksjonen kartlagt direkte til Walker s plassering. Opprett en tilfeldig rullator hvor du i stedet kartlegger resultatet av støyfunksjonen () til en Walker s trinnstørrelse. To-dimensjonal støy Denne ideen om støyverdier som lever i et endimensjonalt rom er viktig fordi det fører oss rett inn i en diskusjon av todimensjonalt rom. La oss tenke på dette for et øyeblikk. Med endimensjonal støy har vi en sekvens av verdier hvor en gitt verdi ligner naboen. Fordi verdien er i en dimensjon, har den bare to naboer: en verdi som kommer før den (til venstre på grafen) og en som kommer etter den (til høyre). Figur I.10: 1D Støy Figur I.11: 2D Støy Todimensjonal støy fungerer nøyaktig på samme måte konseptuelt. Forskjellen er selvsagt at vi ikke ser på verdier langs en lineær bane, men verdier som sitter på et rutenett. Tenk på et stykke grafpapir med tall skrevet inn i hver celle. En gitt verdi vil lignes på alle naboene: over, under, til høyre, til venstre og langs alle diagonaler. Hvis du skulle visualisere dette grafpapiret med hver verdi som er kartlagt til lysstyrken på en farge, vil du få noe som ser ut som skyer. Hvit sitter ved siden av grått, som sitter ved siden av grått, som sitter ved siden av mørkegrå, som sitter ved siden av svart, som sitter ved siden av mørkegrå, etc. Dette er grunnen til at støyen opprinnelig ble oppfunnet. Du justerer parametrene litt eller spiller med farge for å få det resulterende bildet til å se ut som marmor eller tre eller annen organisk tekstur. La oss ta en rask titt på hvordan du implementerer todimensjonal støy i Behandling. Hvis du vil farge hver piksel av et vindu tilfeldig, vil du trenge en nestet sløyfe, en som har tilgang til hver piksel og plukket en tilfeldig lysstyrke. En tilfeldig lysstyrke Hvis du vil fargelegge hver piksel i henhold til støyfunksjonen (), gjør du akkurat det samme, bare i stedet for å ringe tilfeldig () vel ringestøy (). En Perlin støyens lysstyrke Dette er en fin start konseptuelt gir deg en støyverdi for hver (x, y) plassering i vårt todimensjonale rom. Problemet er at dette ikke vil ha den skyige kvaliteten vi ønsker. Hopping fra piksel 200 til piksel 201 er for stor av et hopp gjennom støy. Husk at når vi jobbet med endimensjonal støy, økte vi vår tidsvariabel med 0,01 hver ramme, ikke med 1 En ganske god løsning på dette problemet er å bare bruke forskjellige variabler for støyargumentene. For eksempel kan vi øke en variabel som heter xoff hver gang vi beveger seg horisontalt, og en yoff-variabel hver gang vi beveger seg vertikalt gjennom de nestede løkkene. Eksempel I.6: 2D Perlin støy Start xoff ved 0. For hver xoff, start yoff ved 0.

No comments:

Post a Comment