İçeriğe geç
academia.sh

Ders 02 / 11

Temel İşlevler

60 hücrelik tek bir aralığa dört sayma işlevi uygulanıyor ve dört farklı sayı çıkıyor: 53 dolu hücre, 39 sayı, 29 sıfırdan büyük değer, 7 boş hücre. Aynı sütunun toplamı 708,5 m³; metin olarak yazılmış 14 sayı sessizce atlandığı için gerçek toplam 967,2 m³ ve fark yüzde 26,7. Ortalama paydası dört savunulabilir kararla 11,81 ile 24,43 arasında oynuyor, yani 2,07 kat; altı formülün 1'inde payda hiç görünmüyor, 3'ünde karar gömülü bir sabit, yalnız 1'inde parametre hücresine başvuru var.

İçindekiler

Önceki ders bir hesabın hangi hücrelere yayıldığını saydı, ama hesabın hangi hücreleri saydığını sormadı. toplam(E2:E61) yazıldığında aralıkta 60 hücre vardır; toplanan kaç tanesidir. Aralığın boyu bir sayıdır, aralıkta sayılan hücre başka bir sayıdır ve ikisi birbirine eşit değildir.

Bu ders aynı sayfaya bir sütun ekler: sayaç okuması. Okuma sütununda üç ayrı “hiçbir şey” yan yana durur. Dört sayma işlevi aynı aralığa uygulanınca dört farklı sayı çıkar, ardından o sayılardan biri bir ortalamanın paydası olur ve rapor edilen değer iki kattan fazla oynar.

  • TT7. Aralık işlevleri hücrenin ham içeriğini görür: boş hücre null, metin metin kalır. Sayısal bağlamda boş hücrenin 0 okunması (TT4) sürer; iki kural aynı modelde birlikte yaşar ve aşağıdaki kodda ayrı işlevlerle yazılıdır.
  • TT8. Okuma sütununun üç boşluk türü: boş hücre — okuma alınamadı; sıfır — sayaç dönmemiş, yani gerçek bir ölçüm; metin olarak yazılmış sayı — dışa aktarımdan ondalık ayırıcısı virgülle gelmiş bir dize. Sütun kurgudur ve kendi tohumuyla üretilir.
  • TT9. Ölçüt bir metindir (">0" gibi) ve modelde olc işlevi uygular. Bir hücrenin sayı mı metin mi olduğu türüyle belirlenir, görünüşüyle değil.

Aralıkta Üç Ayrı Hiçbir Şey

Aşağıdaki blok önceki dersin modelini genişletir. Sayfa üretici aynıdır ve aynı sırada çağrılır, bu yüzden tüketim sütunu değişmez. Okuma sütunu ayrı bir diziyle üretilir.

// sayim.mjs — elektronik tablo MODELI: 01'deki model, aralik islevleriyle genisletilmis.
// Aralik islevi hucrenin HAM icerigini gorur: bos hucre null, metin metin kalir.
export const TOHUM = 20260602, SATIR = 60;
const uretec = (t) => { let s = t >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };

const REF = /(\$?)([A-Z])(\$?)(\d+)/g;
const coz = (a) => ({ s: a.charCodeAt(a[0] === "$" ? 1 : 0) - 65, r: +a.replace(/\D/g, "") });
const adi = (s, r) => String.fromCharCode(65 + s) + r;
const ARALIK = /(\$?[A-Z]\$?\d+):(\$?[A-Z]\$?\d+)/g;
const ac = (a, b) => { const x = coz(a), y = coz(b), l = [];
  for (let s = x.s; s <= y.s; s++) for (let r = x.r; r <= y.r; r++) l.push(adi(s, r));
  return l; };

// Olcut metni: ">0" gibi bir esik ya da duz bir deger. Metin hucre metin olarak kalir.
const olc = (o, v) => { const m = /^([<>]=?|=)?(.*)$/.exec(o), s = +m[2];
  if (typeof v !== "number") return m[1] === undefined && v === m[2];
  return m[1] === ">" ? v > s : m[1] === "<" ? v < s : m[1] === ">=" ? v >= s
    : m[1] === "<=" ? v <= s : v === s; };

const say1 = (d) => d.filter((v) => v !== null && v !== "").length;
const sayi = (d) => d.filter((v) => typeof v === "number");
const ISLEV = {
  toplam: (d) => sayi(d).reduce((a, b) => a + b, 0),   // metin ve bos hucre atlanir
  say: say1,                                            // dolu hucre: metin de sayilir
  sayisay: (d) => sayi(d).length,                       // yalniz sayi turunde hucre
  bossay: (d) => d.length - say1(d),
  ortalama: (d) => sayi(d).reduce((a, b) => a + b, 0) / sayi(d).length,
  kosullusay: (d, o) => d.filter((v) => olc(o, v)).length,
  kosullutoplam: (d, o, t) => t.filter((_, i) => olc(o, d[i]))
    .filter((v) => typeof v === "number").reduce((a, b) => a + b, 0),
};

export function ham(H, ad) {
  const v = H[ad];
  if (v === undefined) return null;                   // bos hucre aralikta null gorunur
  return typeof v === "string" && v[0] === "=" ? deger(H, ad) : v;
}
export function deger(H, ad) {
  const v = H[ad];
  if (v === undefined) return 0;                      // sayisal baglamda bos hucre 0 (TT4)
  if (typeof v !== "string" || v[0] !== "=") return v;
  const ifade = v.slice(1)
    .replace(ARALIK, (_, a, b) => "[" + ac(a, b).map((c) => JSON.stringify(ham(H, c))).join(",") + "]")
    .replace(REF, (m) => JSON.stringify(deger(H, m.replace(/\$/g, ""))));
  return Function(...Object.keys(ISLEV), `return (${ifade});`)(...Object.values(ISLEV));
}

// Sayfa 01'deki sayfadir: A/B/C sutunlari ayni tohumla ayni sirada uretilir, bu yuzden
// tuketim degerleri (C2:C61 toplami 1419,9 m3) degismez. Okuma sutunu D ayri bir dizidir.
export function sayfa() {
  const r = uretec(TOHUM), H = {};
  H.A1 = "abone"; H.C1 = "tuketim"; H.D1 = "okuma";
  for (let i = 0; i < SATIR; i++) {
    const s = i + 2;
    H["A" + s] = "AB-" + String(1041 + i * 7).padStart(4, "0");
    r();                                    // 01'deki bolge sutunu: uretec ayni sirada calisir
    H["C" + s] = Math.round((2 + r() * r() * 78) * 10) / 10;
  }
  // Okuma sutunu: uc ayri "hicbir sey" bir arada durur.
  const o = uretec(TOHUM + 1);
  for (let i = 0; i < SATIR; i++) {
    const s = i + 2, t = H["C" + s], p = o();
    if (p < 0.14) continue;                            // bos hucre: okuma alinamadi
    if (p < 0.27) H["D" + s] = 0;                      // sayac donmemis: gercek sifir
    else if (p < 0.44) H["D" + s] = String(t).replace(".", ",");  // metin olarak yazilmis sayi
    else H["D" + s] = t;
  }
  // Parametre blogu 01'deki blogun aynisi: tarife basamaklari H6:H8'dedir.
  ["birim ucret", "sabit bedel", "sayac bakim", "kayip payi", "basamak 1", "basamak 2",
    "basamak 3", "indirim"].forEach((e, j) => { H["G" + (j + 2)] = e; });
  [8.4, 25, 3.5, 1.2, 10, 25, 40, 0.9].forEach((v, j) => { H["H" + (j + 2)] = v; });
  return H;
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const H = sayfa();
  const tur = (v) => v === undefined ? "bos" : typeof v === "number" ? "sayi" : "metin";
  const g = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
    : String(v).padEnd(B[0]))).join("");
  const y = g([8, 10, 10, 8]);
  console.log(y(["hucre", "tuketim", "okuma", "tur"]));
  for (const s of [2, 3, 5, 9, 61]) console.log(y(["D" + s, H["C" + s].toFixed(1),
    H["D" + s] === undefined ? "" : H["D" + s], tur(H["D" + s])]));
  const d = Array.from({ length: SATIR }, (_, i) => H["D" + (i + 2)]);
  const n = (f) => d.filter(f).length;
  console.log(`\nD2:D61 aralik boyu ${SATIR}; bos ${n((v) => v === undefined)}, ` +
    `sifir ${n((v) => v === 0)}, metin ${n((v) => typeof v === "string")}, ` +
    `sifirdan buyuk sayi ${n((v) => typeof v === "number" && v > 0)}`);
}
hucre      tuketim     okuma     tur
D2             9.8       9,8   metin
D3            71.6         0    sayi
D5            26.8      26.8    sayi
D9             5.5               bos
D61           21.2      21.2    sayi

D2:D61 aralik boyu 60; bos 7, sifir 10, metin 14, sifirdan buyuk sayi 29

Son sütun modelin verdiği bir kolaylıktır; gerçek bir sayfada tür yazmaz. D2 hücresinde 9,8, D5 hücresinde 26.8 görünür ve ikisi de bir okuma gibi okunur. D9 ile D3 arasındaki fark daha incedir: biri boş, öteki sıfırdır. Oysa D3 bir ölçümdür — sayaç dönmemiştir — D9 bir ölçümün yokluğudur.

Aynı Aralık, Dört Sayma İşlevi

“Bu dönem kaç okuma var” sorusunun tek cevabı yoktur. Aşağıdaki blok aynı aralığı dört ayrı sayma işlevine verir, ardından metin hücrelerin toplama ne yaptığını ölçer.

// islev.mjs — ayni aralik uc sayma islevine verilir, uc farkli sonuc doner.
import { sayfa, deger, SATIR } from "./sayim.mjs";

const H = sayfa();
const FORMUL = [
  ["=say(D2:D61)", "dolu hucre (metin dahil)"],
  ["=sayisay(D2:D61)", "sayi turunde hucre"],
  ["=kosullusay(D2:D61,\">0\")", "sifirdan buyuk sayi"],
  ["=bossay(D2:D61)", "bos hucre"],
];
const g = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");
const y = g([28, 8, 28]);
console.log(`D2:D61 araliginda ${SATIR} hucre var.\n`);
console.log(y(["formul", "sonuc", "ne saydi"]));
for (const [f, ne] of FORMUL) console.log(y([f, deger({ ...H, X1: f }, "X1"), ne]));

// Metin olarak yazilmis sayilar toplama girmiyor. Ayni sutun sayiya cevrilirse ne olurdu.
const T = { ...H };
for (let i = 0; i < SATIR; i++) { const c = "D" + (i + 2), v = T[c];
  if (typeof v === "string") T[c] = +v.replace(",", "."); }
const ham = deger({ ...H, X1: "=toplam(D2:D61)" }, "X1");
const cev = deger({ ...T, X1: "=toplam(D2:D61)" }, "X1");
console.log(`\ntoplam(D2:D61) ham sutunda ${ham.toFixed(1)} m3, metinler sayiya ` +
  `cevrilince ${cev.toFixed(1)} m3; fark ${(cev - ham).toFixed(1)} m3 ` +
  `(${(100 * (cev - ham) / cev).toFixed(1)} yuzde).`);
console.log(`01'de C2:C61 toplami 1419,9 m3 idi; ayni satirlarin okuma sutunu ` +
  `${ham.toFixed(1)} m3 gosteriyor.`);
D2:D61 araliginda 60 hucre var.

formul                         sonuc                    ne saydi
=say(D2:D61)                      53    dolu hucre (metin dahil)
=sayisay(D2:D61)                  39          sayi turunde hucre
=kosullusay(D2:D61,">0")          29         sifirdan buyuk sayi
=bossay(D2:D61)                    7                   bos hucre

toplam(D2:D61) ham sutunda 708.5 m3, metinler sayiya cevrilince 967.2 m3; fark 258.7 m3 (26.7 yuzde).
01'de C2:C61 toplami 1419,9 m3 idi; ayni satirlarin okuma sutunu 708.5 m3 gosteriyor.

Dördü de doğrudur ve dördü farklı bir soruyu cevaplar. 53, bir şey yazılmış hücrelerin sayısıdır. 39, sayı türünde olanların sayısıdır. 29, sıfırdan büyük bir okuma taşıyanların sayısıdır. 7, hiç okunmamış aboneleri verir. Rapora “bu dönem okuma sayısı” diye girecek değer bu dördünden biridir ve hangisi olduğu sorunun tanımına bağlıdır, işlevin adına değil.

Toplam satırı daha sessiz bir şey yapıyor. Toplama işlevi metin hücreleri atlar ve bunu söylemez; hata vermez, uyarı üretmez, yalnız 14 değeri hesaba katmaz. Sütunun gerçek toplamı 967,2 m³ iken sayfada 708,5 m³ yazar. Fark 258,7 m³, yani gerçek toplamın yüzde 26,7’si. Bir hata gösterilmiş olsaydı görülürdü; atlama görülmez.

Önceki ders aynı satırların tüketim toplamını 1419,9 m³ bulmuştu. Okuma sütunu dolu olduğu her satırda tüketimle aynı değeri taşır; yani 708,5 ile 1419,9 arasındaki fark bir ölçüm farkı değil, bir sayma farkıdır ve bunu söyleyen bir hücre yoktur.

Ortalamanın Paydası Nerede Duruyor

Toplam bir karara bağlıydı; ortalama iki karara bağlıdır, çünkü paydası ayrıca seçilir. Aşağıdaki blok aynı payı dört paydayla böler, ardından bir eşiğin iki yazımını karşılaştırır ve altı formülü kararın nerede durduğuna göre tarar.

// payda.mjs — ayni ortalama dort paydayla; ve olcut/payda kararlarinin geri okunabilirligi.
import { sayfa, deger } from "./sayim.mjs";

const H = sayfa();
const oku = (f) => deger({ ...H, X1: f }, "X1");
const g = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");

const ORT = [
  ["=ortalama(D2:D61)", "sayi turunde hucre"],
  ["=toplam(D2:D61)/say(D2:D61)", "dolu hucre"],
  ["=toplam(D2:D61)/kosullusay(D2:D61,\">0\")", "sifirdan buyuk"],
  ["=toplam(D2:D61)/60", "aralik boyu"],
];
const y = g([42, 10, 8, 20]), pay = oku("=toplam(D2:D61)");
console.log(y(["formul", "ortalama", "payda", "payda nedir"]));
for (const [f, ne] of ORT) console.log(y([f, oku(f).toFixed(2), Math.round(pay / oku(f)), ne]));
const v = ORT.map(([f]) => oku(f));
console.log(`\nEn kucuk ${Math.min(...v).toFixed(2)}, en buyuk ${Math.max(...v).toFixed(2)} m3; ` +
  `oran ${(Math.max(...v) / Math.min(...v)).toFixed(2)} kat.`);

// Ayni kosullu toplam iki yazimla: esik olcut metnine gomulu, ya da parametre hucresinden.
const A = "=kosullutoplam(C2:C61,\">25\",C2:C61)";
const B = "=kosullutoplam(C2:C61,\">\"+H7,C2:C61)";
const Z = { ...H, H7: 30 };                             // ikinci basamak 25 -> 30 m3
const z = g([44, 12, 12, 10]);
console.log("\n" + z(["formul", "toplam", "esik 30", "pesinden"]));
for (const f of [A, B]) {
  const once = deger({ ...H, X1: f }, "X1"), sonra = deger({ ...Z, X1: f }, "X1");
  // Esik 0,05 m3'tur: okumalar bir ondalikli tutuluyor, altindaki fark ayirt edilemez.
  console.log(z([f, once.toFixed(1), sonra.toFixed(1), Math.abs(once - sonra) >= 0.05 ? 1 : 0]));
}

// Tarama: her formul metni aralik adlari disindaki sabitler ve basvurular icin okunur.
const TARA = [...ORT.map(([f]) => f), A, B];
const s = g([44, 8, 8, 8]);
console.log("\n" + s(["formul", "gizli", "sabit", "basvuru"]));
const N = { gizli: 0, sabit: 0, basvuru: 0 };
for (const f of TARA) {
  const kalan = f.replace(/[A-Z]\d+:[A-Z]\d+/g, "");        // aralik adlari sayilmaz
  const gizli = f.includes("=ortalama(");                   // payda formul metninde yok
  const basvuru = (kalan.match(/[A-Z]\d+/g) ?? []).length;
  const sabit = (kalan.replace(/[A-Z]\d+/g, "").match(/\d+(\.\d+)?/g) ?? []).length;
  N.gizli += +gizli; N.sabit += +!!sabit; N.basvuru += +!!basvuru;
  console.log(s([f, gizli ? "evet" : "hayir", sabit, basvuru]));
}
console.log(`\n${TARA.length} formulun ${N.gizli} tanesinde payda hic gorunmuyor, ${N.sabit} ` +
  `tanesinde karar gomulu bir sabit, ${N.basvuru} tanesinde parametre hucresine basvuru, ` +
  `${TARA.length - N.gizli - N.sabit - N.basvuru} tanesinde bir islev adi.`);
formul                                      ortalama   payda         payda nedir
=ortalama(D2:D61)                              18.17      39  sayi turunde hucre
=toplam(D2:D61)/say(D2:D61)                    13.37      53          dolu hucre
=toplam(D2:D61)/kosullusay(D2:D61,">0")        24.43      29      sifirdan buyuk
=toplam(D2:D61)/60                             11.81      60         aralik boyu

En kucuk 11.81, en buyuk 24.43 m3; oran 2.07 kat.

formul                                            toplam     esik 30  pesinden
=kosullutoplam(C2:C61,">25",C2:C61)               1010.6      1010.6         0
=kosullutoplam(C2:C61,">"+H7,C2:C61)              1010.6       846.3         1

formul                                         gizli   sabit basvuru
=ortalama(D2:D61)                               evet       0       0
=toplam(D2:D61)/say(D2:D61)                    hayir       0       0
=toplam(D2:D61)/kosullusay(D2:D61,">0")        hayir       1       0
=toplam(D2:D61)/60                             hayir       1       0
=kosullutoplam(C2:C61,">25",C2:C61)            hayir       1       0
=kosullutoplam(C2:C61,">"+H7,C2:C61)           hayir       0       1

6 formulun 1 tanesinde payda hic gorunmuyor, 3 tanesinde karar gomulu bir sabit, 1 tanesinde parametre hucresine basvuru, 1 tanesinde bir islev adi.

Ortalama okuma 11,81 m³ ile 24,43 m³ arasında oynuyor: 2,07 kat. Pay hiç değişmedi, yalnız payda seçildi ve dört değerin hepsi savunulabilir. Rapora girecek olan, kimin ortalamasının sorulduğuna bağlıdır: okunan abonelerin mi, kayıtlı bütün abonelerin mi.

İkinci sayı üçüncü tabloda. Ortalama işlevi paydayı formül metnine hiç yazmıyor: sayfayı açan biri 18,17 değerini ve işlevin adını görür, 39 sayısını göremez. Bu karar geri okunamaz. Aynı sayıyı toplam(D2:D61)/sayisay(D2:D61) biçiminde yazmak sonucu değiştirmez, ama paydayı formül metnine taşır. Aynı sayıyı üreten iki yazımdan biri kararı saklar, öteki yazar.

Koşullu toplam tablosu aynı ayrımı eşik üzerinde tekrar ediyor. İki formül de 1010,6 m³ veriyor; ölçüt metnine gömülü ">25" ile parametre hücresine başvuran ">"+H7 sonuçtan ayırt edilemez. İkinci basamak 30 m³’e çıkarıldığında birincisi 1010,6’da kalıyor, ikincisi 846,3’e iniyor.

Tarama altı formülü dört öbeğe ayırdı: 1’inde karar hiç görünmüyor, 3’ünde gömülü bir sabit, 1’inde parametre hücresine başvuru, 1’inde karar bir işlev adının kendisi. Sonuncusu en ucuz kurtarılabilirlik biçimidir: sayisay yazan formül ne saydığını adıyla söyler.

Özet

  • Bir aralığın boyu ile sayılan hücre sayısı ayrı şeylerdir: 60 hücrelik aralıkta dört sayma işlevi 53, 39, 29 ve 7 verdi; dördü de doğru, dördü farklı soruya cevap.
  • Boş hücre, sıfır ve metin olarak yazılmış sayı hücrede birbirine benzer ama üçü ayrı şeydir; sıfır bir ölçümdür, boş hücre bir ölçümün yokluğudur.
  • Toplama işlevi metin hücreleri atlar ve bunu söylemez: sütun 708,5 m³ gösterirken gerçek toplam 967,2 m³, fark yüzde 26,7. Hata görülür, atlama görülmez.
  • Aynı payın dört paydası ortalamayı 11,81 ile 24,43 arasında oynattı: 2,07 kat. Ortalamanın paydası hesabın değil, tanımın parçasıdır.
  • Kurtarılabilirlik yazım biçimine bağlıdır: ortalama işlevi paydayı hiç yazmaz, gömülü eşik kaynağını yazmaz, işlev adı kararı kendi adıyla söyler. Altı formülün yalnız 1’i parametre hücresine başvuruyor.

Sonraki Adım

Bu ders bir aralığın kaç hücresinin sayıldığını ölçtü, ama hep tek bir eşikle: ">0" ya da ">25". Tarife tek eşikli değildir. Bir kaydın hangi basamağa düştüğü 10, 25 ve 40 m³ sınırlarının üçüne birden bakan iç içe bir koşulla belirlenir ve her katmanda bir karşılaştırma işareti seçilir. Sonraki ders aynı 60 kaydı iki kez basamaklara dağıtır — bir kez < ile, bir kez <= ile — ve sınıra tam oturan kayıtların kaçının basamak değiştirdiğini sayar.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat