Postavite =VLOOKUP(A1,B:B,1) v celico v stolpcu B in Excel jo izračuna brez pritožbe. Ponudite isti delovni zvezek motorju ponovnega izračunavanja grafa odvisnosti in verjetno boste dobili napako krožne reference, ker formula obstaja na obseg, ki vsebuje formulo. HotXLS je poročal natanko to do v2.361.98. Popravek ni poseben primer za obsege celih stolpcev; je razlikovanje med dvema vrstama roba odvisnosti, ki ga motor preglednic potrebuje in ki ga navaden usmerjeni graf nima
Argument matrike iskanja družine iskanja, LOOKUP, MATCH, HLOOKUP, VLOOKUP, XLOOKUP in XMATCH, je zdaj označen kot referenca iskanja. Referenca iskanja še vedno seje umazanijo, tako da urejanje celice znotraj obsega ponovno izračuna formulo, ampak nikoli ne prispeva k zaznavanju ciklov ali urejanju vrednotenja. Pravi cikli so še vedno najdeni; lažni so odšli
Zakaj Excel dovoli, da obseg iskanja vsebuje formulo?
Ker ta argument ni porabljen na način, kot je aritmetični operand. Družina iskanja preišče obseg za predpomnjene vrednosti in vrne ujemanje; ne zahteva, da je bil obseg ovrednoten do zaključka najprej. Excel obravnava samoprekrivajoči se obseg iskanja kot branje karkoli te celice trenutno držijo, kar je ista semantika, ki jo aplicira na kateri koli neiterativni delovni zvezek: celice, ki niso bile ponovno izračunane v tem prehodu, prispevajo svojo zadnjo izračunano vrednost
Reference celih stolpcev naredijo to običajni primer in ne eksotičnega. B:B je idiomatski način pisanja »cela iskalna tabela« v listu, kamor se vrstice pripnejo, in vsaka formula, ki živi v stolpcu B, je nato znotraj svojega obsega iskanja. Finančni modeli, listi usklajevanja in delovni zvezki revizije to počnejo nenehno, običajno brez tega, da bi kdo opazil, da se obseg prekriva
Kaj graf odvisnosti naredi z isto formulo
HotXLS ponovno izračuna inkrementalno, kar zahteva pravi graf odvisnosti: vozlišča za celice, robove za reference, topološki vrstni red za vrednotenje in prehod močno povezanih komponent za razvrščanje ciklov. Ta mehanizem je opisan v članku o inkrementalnem ponovnem izračunavanju in je natanko razlog, zakaj se je pojavila lažna pozitivnost
Izvlecite odvisnosti iz =VLOOKUP(A1,B:B,1) v celici B7 in drugi argument da obseg, ki vsebuje B7 samo. Graf zdaj ima samozanko. Vhodna stopnja tega vozlišča nikoli ne doseže nič, tako da topološki prehod ne more nikoli razporediti njega, prehod komponent pa ga razvrsti kot cikel. Motor sklepa pravilno o grafu, ki mu je bil dan. Graf je napačni model, ker kodira en tip roba, kjer ima preglednica dva
Dva razreda robov, en graf
Sprememba doda zastavico zapisu razrešene reference, TXLSDepRange.LookupScan, ki ga izvlečevalnik odvisnosti nastavi, ko prehodi argument matrike iskanja ene od šestih funkcij. Nizvodno so robovi, izvor iz teh referenc, shranjeni narazen od običajnih robov: grafsko vozlišče obdrži sezname ScanDependents in ScanPrecedents ob svojih običajnih seznamih odvisnih in predhodnikov
Ločitev je tisto, kar naredi semantiko pravilno. Robovi iskanja so prečkani s strani širjenja umazanije, tako da urejanje kjer koli v B:B še vedno označi B7 umazanega in B7 ponovno izračuna. Robovi iskanja nikoli niso šteti v vhodno stopnjo in nikoli ne vstopijo v graditelja komponent, zato ne morejo ustvariti topološke zastoja in ne biti razvrščeni kot cikel. Obe implementaciji grafa v knjižnici, klasični graf na delovni zvezek in graf delovnega prostora čez delovne zvezke, ki nosi analizo komponent, sta bili spremenjeni skupaj; pustiti jih odmikati bi proizvedlo delovni zvezek, ki se ponovno izračuna drugače odvisno od tega, ali je bil odprt sam ali kot del delovnega prostora
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Ledger');
Sheet.Cells[1, 1].Value := 'ACC-4471';
Sheet.Cells[1, 2].Value := 1200.00;
// Obseg iskanja pokriva stolpec B in ta formula živi v njem
Sheet.Cells[7, 2].Formula := 'VLOOKUP(A1,B:B,1)';
case Book.Recalculate of
lxOk:
// Pred v2.361.98 je bila ta veja nedosegljiva za ta list
SaveReport(Book);
lxErrorRef:
LogWarning('Genuine circular reference - review model inputs');
end;
finally
Book.Free;
end;
end;
Kaj opustite z izključitvijo robov iskanja iz razvrščanja
Natanko eno stvar in vredna je jasnega izjavljanja namesto skrivanja. Ker robovi iskanja ne sodelujejo v topološkem vrstnem redu, je lahko formula iskanja ovrednotena v istem prehodu, preden so bile nekatere celice v njenem obsegu iskanja ponovno izračunane, in bo nato brala njihove prejšnje vrednosti. Rezultat konvergira ob naslednjem ponovnem izračunavanju
To je sprejemljivo, ker je to, kar Excel počne. Za delovni zvezek brez omogočenega iterativnega izračunavanja je lasten odgovor Excela za vrednost, še ne ponovno izračunano v trenutnem prehodu, zadnja izračunana vrednost, zato motor, ki reproducira to vedenje, ujema referenčno implementacijo in ne približuje nje. Če potrebujete resnično konvergiran odgovor nad samosklicujočim se modelom, je mehanizem za to iterativno izračunavanje z izrecno omejitvijo iteracij, pokrito v članku o iterativnem izračunavanju, in velja za prave cikle in ne za prekrivanja iskanja
Nevarnost regresije, ki se skriva znotraj popravka
Dodajanje LookupScan TXLSDepRange je uvedlo tveganje, ki nima ničesar z iskanji in vse z Pascalom. TXLSDepRange je neupravljani zapis, zato lokalna spremenljivka tega tipa ni ničelno inicializirana. Vsako mesto v kodni bazi, ki zgradi enega ročno, vključno z bloki odvisnosti podatkovne tabele in več pomočniki testov, je moralo biti posodobljeno, da nastavi novo polje izrecno. Zamudite enega in kateri koli bajt, ki se je slučajno nahajal na skladu, odloči, ali je ta referenca obravnavana kot rob iskanja, kar proizvede napako ponovnega izračunavanja, ki se pokaže in izgine z nepovezanimi spremembami kode
// Novo Boolean polje v neupravljanem zapisu naredi vsako ročno
// gradbeno mesto latentno napako. Dva varna idiom:
var
R: TXLSDepRange;
begin
FillChar(R, SizeOf(R), 0); // ničelajte vse, nato izpolnite
R.Sheet1 := SheetIndex;
R.Sheet2 := SheetIndex;
R.Row1 := Row; R.Col1 := Col;
R.Row2 := Row; R.Col2 := Col;
// ali nastavite vsako polje, vključno z novim, na vsakem mestu
R.LookupScan := False;
end;
Splošno pravilo, ki si ga je to prislužilo: dodajanje polja zapisu, ki je zgrajen na skladu na več kot peščici mest, je višje tvegana sprememba, kot izgleda, in prevajalnik vam ne bo pomagal najti mest. Če je zapis dosegljiv iz vroče poti, dajte prednost pomočniku, ki ga popolnoma inicializira, pred zaupanjem vsakemu mestu klica, da bo posodobljen
Razlikovanje pravega cikla od prekrivanja iskanja
Nič o tej spremembi ne oslabi zaznavanja ciklov. =B7+1 v B7 je še vedno cikel, veriga treh formul, ki se zapre na samo, je še vedno cikel, in oba sta še vedno poročana skozi rezultat ponovnega izračunavanja, člani cikla obdržijo svoje prejšnje predpomnjene vrednosti, medtem ko vse zunaj cikla ostane trenutno. Kar se je spremenilo, je samo to, da argument matrike iskanja ne izdeluje več ciklov, ki jih Excel ne vidi
Če revizirate delovni zvezek in želite vedeti, katere reference je motor dejansko razrešil in v kakšnem vrstnem redu, je sledilnik vrednotenja orodje zanjo; članek o sledilniku vrednotenja formul pokriva, kako brati njegov izhod. HotXLS je domača komponenta preglednic Delphi in C++Builder, ki bere in piše XLS, XLSX, ODS in CSV brez nameščenega Excela, motor ponovnega izračunavanja pa je isti na vsaki obliki; trenutna pokritost funkcij in motorja je navedena na strani produkta HotXLS Delphi spreadsheet component