Tekninen artikkeli

HotXLS:n lookup-skannaukset ja väärät kehäviittaukset

Laita =VLOOKUP(A1,B:B,1) soluun sarakkeessa B, ja Excel laskee sen valittamatta. Syötä sama työkirja riippuvuusgraafin uudelleenlaskentakoneelle, ja saat todennäköisesti kehäviittausvirheen, koska kaava riippuu alueesta, joka sisältää kaavan. HotXLS raportoi juuri tuota versioon v2.361.98 asti. Korjaus ei ole erikoistapaus kokonaissarakealueille; se on ero kahdenlaisen riippuvuusreunan välillä, jonka laskentataulukkokone tarvitsee ja jota tavallinen suunnattu graafi ei ole

Hakuperheen, LOOKUP, MATCH, HLOOKUP, VLOOKUP, XLOOKUP ja XMATCH, hakutaulukkoargumentti merkitään nyt skannausviittaukseksi. Skannausviittaus kylvää yhä likaisuuden, joten solun muokkaaminen alueen sisällä laskee kaavan uudelleen, mutta se ei koskaan osallistu kehätunnistukseen eikä arviointijärjestykseen. Oikeat kehat löytyvät yhä; väärät ovat poissa

Miksi Excel sallii hakualueen sisältää kaavan?

Koska kyseistä argumenttia ei kuluteta niin kuin aritmeettista operandia. Hakuperhe skannaa alueen välimuistitettujen arvojen varalta ja palauttaa osuman; se ei vaadi, että alue olisi arvioitu loppuun ensin. Excel käsittelee itsensä päällekkäin menevää hakualuetta niin, että se lukee, mitä kyseiset solut tällä hetkellä pitävät, mikä on sama semantiikka, jota se soveltaa mihin tahansa ei-iteratiiviseen työkirjaan: solut, joita ei ole laskettu uudelleen tässä ajossa, antavat viimeksi lasketun arvonsa

Kokonaissarakeviittaukset tekevät tästä tavallisen tapauksen eikä eksoottista. B:B on idiomattinen tapa kirjoittaa ”koko hakutaulukko” taulukkovälilehdessä, johon rivejä lisätään, ja mikä tahansa kaava, joka asuu sarakkeessa B, on sitten oman hakualueensa sisällä. Taloudelliset mallit, täsmäytyystaulukot ja auditointityökirjat tekevät tätä jatkuvasti, yleensä ilman että kukaan huomaa alueen päällekkäisyyttä

Solu B7 pitää kaavaa VLOOKUP(A1,B:B,1) omassa kokonaissarakehakualueessaan B:B, itsensä päällekkäisyydessä oleva päällekkäisyys, jonka Excel laskee välimuistiarvoista valittamatta
Kokonaissarakehakualueet tekevät itsensä päällekkäisyydestä tavallisen tapauksen taloudellisissa malleissa ja auditointityökirjoissa, eivät eksoottista nurkkaa

Mitä riippuvuusgraafi tekee samalla kaavalla

HotXLS laskee uudelleen inkrementaalisesti, mikä vaatii aidon riippuvuusgraafin: solmuja soluille, reunoja viittauksille, topologisen järjestyksen arviointiin ja vahvasti yhtenäisten komponenttien ajon kehien luokitteluun. Kyseinen koneisto on kuvattu artikkelissa inkrementaalinen uudelleenlaskenta, ja se on täsmälleen syy siihen, että väärä positiivinen ilmestyi

Poimi riippuvuudet kaavasta =VLOOKUP(A1,B:B,1) solussa B7, ja toinen argumentti tuottaa alueen, joka sisältää B7:n itsensä. Graafissa on nyt itseensäsilmukka. Kyseisen solmun saapuvien kaarien määrä ei koskaan saavuta nollaa, joten topologinen ajo ei koskaan voi aikatauluttaa sitä, ja komponenttiajo luokittelee sen kehäksi. Kone päättelee oikein graafista, jonka se sai. Graafi on väärä malli, koska se koodaa yhden reunatyypin siellä, missä laskentataulukossa on kaksi

B:B-hakualue antaa graafisolmulle B7 itseensäsilmukan, joten saapuvien kaarien määrä ei koskaan saavuta nollaa ja HotXLS ennen versiota v2.361.98 raportoi väärän kehäviittauksen
Uudelleenlaskentakone päättelee oikein graafista, jonka se sai; graafi oli väärä malli laskentataulukolle

Kaksi reunaluokkaa, yksi graafi

Muutos lisää lipun ratkaistun viittauksen tietueeseen, TXLSDepRange.LookupScan, jonka riippuvuuspoimija asettaa kulkiessaan yhden kuudesta funktiosta hakutaulukkoargumentin läpi. Alavirrassa kyseisistä viittauksista lähtöisin olevat reunat tallennetaan erilleen tavallisista reunoista: graafisolmu pitää luettelot ScanDependents ja ScanPrecedents tavallisten riippuvaisten ja edeltäjien luetteloidensa rinnalla

Ero on se, mikä tekee semantiikasta oikean. Skannausreunat kuljetaan likaisuuden etenemisessä, joten muokkaus missä tahansa kohteessa B:B merkitsee yhä B7:n likaiseksi ja B7 laskee uudelleen. Skannausreunoja ei koskaan lasketa saapuvien kaarien määrään eikä ne koskaan mene komponentinrakentajaan, joten ne eivät voi luoda topologista umpikujaa eikä niitä voida luokitella kehäksi. Molemmat kirjaston graafitoteutukset, klassinen työkirjakohtainen graafi ja työkirjojen välinen työtilagraafi, joka kantaa komponenttianalyysin, muutettiin yhdessä; niiden erkaneminen tuottaisi työkirjan, joka laskee uudelleen eri tavalla riippuen siitä, avattiinko se yksin vai osana työtilaa

Skannausreunat kohteesta TXLSDepRange.LookupScan ajavat likaisuuden etenemistä kohteisiin ScanPrecedents ja ScanDependents, mutta eivät koskaan laske saapuvien kaarien määrään tai kehiin
Muokkaukset kohteessa B:B merkitsevät yhä kaavan likaiseksi, mutta skannausreunat eivät voi umpikujaista topologista ajoa eivätkä valmistaa kehää
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;
    // Hakualue kattaa sarakkeen B, ja tämä kaava asuu siinä
    Sheet.Cells[7, 2].Formula := 'VLOOKUP(A1,B:B,1)';

    case Book.Recalculate of
      lxOk:
        // Ennen versiota v2.361.98 tämä haara oli saavuttamaton
        // tälle taulukkovälilehdelle
        SaveReport(Book);
      lxErrorRef:
        LogWarning('Genuine circular reference - review model inputs');
    end;
  finally
    Book.Free;
  end;
end;

Mistä luovut sulkiessasi skannausreunat järjestyksestä

Täsmälleen yhden asian, ja se kannattaa sanoa suoraan eikä piilottaa. Koska skannausreunat eivät osallistu topologiseen järjestykseen, hakukaava voidaan arvioida samassa ajossa ennen kuin jotkin sen hakualueen solut on laskettu uudelleen, ja se lukee silloin niiden aiemmat arvot. Tulos konvergoituu seuraavassa uudelleenlaskennassa

Se on hyväksyttävää, koska se on sitä, mitä Excel tekee. Työkirjalle ilman iteroivan laskennan käyttöönottoa Excelin oma vastaus arvolle, jota ei ole vielä laskettu uudelleen nykyisessä ajossa, on viimeksi laskettu arvo, joten kone, joka toistaa tämän käyttäytymisen, täsmää vertailutoteutukseen sen likiarvioimisen sijaan. Jos tarvitset aidosti konvergoituneen vastauksen itseensä viittaavan mallin yllä, mekanismi siihen on iteroiva laskenta eksplisiittisellä iteraatiorajalla, mistä kerrotaan artikkelissa iteroiva laskenta, ja se koskee oikeita kehiä eikä skannauspäällekkäisyyksiä

Regressioriski, joka piiloutuu korjauksen sisään

Arvon LookupScan lisääminen kohteeseen TXLSDepRange toi riskin, jolla ei ole mitään tekemistä hakujen kanssa ja kaikkea tekemistä Pascalin kanssa. TXLSDepRange on hallitsematon tietue, joten kyseisen tyypin lokaali muuttuja ei ole nolla-alustettu. Jokainen paikka koodikannassa, joka rakentaa yhden käsin, mukaan lukien datataulukon riippuvuuslohkot ja useat testiavustajat, piti siksi päivittää asettamaan uusi kenttä eksplisiittisesti. Ohita yksi, ja se tavu, joka sattui olemaan pinossa, päättää, käsitelläänkö kyseinen viittaus skannausreunana, mikä tuottaa uudelleenlaskentavirheen, joka ilmestyy ja katoaa asiaankuulumattomien koodimuutosten mukana

// Uusi Boolean-kenttä hallitsemattomassa tietueessa tekee jokaisesta
// manuaalisesta rakennuspaikasta latentin vian. Kaksi turvallista tapaa:
var
  R: TXLSDepRange;
begin
  FillChar(R, SizeOf(R), 0);      // nollaa kaikki, täytä sitten
  R.Sheet1 := SheetIndex;
  R.Sheet2 := SheetIndex;
  R.Row1 := Row; R.Col1 := Col;
  R.Row2 := Row; R.Col2 := Col;

  // tai aseta jokainen kenttä, myös uusi, jokaisella paikalla
  R.LookupScan := False;
end;

Yleinen sääntö, jonka tämä ansaitsi: kentän lisääminen tietueeseen, joka rakennetaan pinossa useammissa kuin kourallisessa paikkaa, on korkeampiriskinen muutos kuin se näyttää, eikä kääntäjä auta sinua löytämään paikkoja. Jos tietue on saavutettavissa kuumasta polusta, suosi apuria, joka alustaa sen kokonaan, sen sijaan että luottaisit jokaisen kutsupaikan päivittyvän

Oikean kehän erottaminen skannauspäällekkäisyydestä

Mikään tässä muutoksessa ei heikennä kehätunnistusta. =B7+1 solussa B7 on yhä kehää, kolmen kaavan ketju, joka sulkeutuu itseensä, on yhä kehää, ja molemmat raportoidaan yhä uudelleenlaskennan tuloksen kautta siten, että kehän jäsenet säilyttävät aiemmat välimuistiarvonsa, kun taas kaikki kehän ulkopuolella pysyy ajan tasalla. Se, mikä muuttui, on vain se, ettei hakutaulukkoargumentti enää valmista kehää, jota Excel ei näe

Jos auditoit työkirjaa ja haluat tietää, mitkä viittaukset kone oikeasti ratkaisi ja missä järjestyksessä, arviointiseurain on siihen työkalu; artikkeli kaavan arviointiseurain kattaa, miten sen tuloste luetaan. HotXLS on natiivi Delphi- ja C++Builder-laskentataulukkokomponentti, joka lukee ja kirjoittaa muodot XLS, XLSX, ODS ja CSV ilman asennettua Exceliä, ja uudelleenlaskentakone on sama jokaisella muodolla; nykyinen funktio- ja konekattavuus on lueteltu HotXLS Delphi spreadsheet -komponentin tuotesivulla