metanum 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -172
- package/format-metanum.js +354 -141
- package/metanum.js +629 -247
- package/package.json +1 -1
- package/test-interface.html +1 -0
- package/test_mixed.js +1000 -31
package/format-metanum.js
CHANGED
|
@@ -7,20 +7,20 @@ let FORMAT_DEBUG = 0
|
|
|
7
7
|
|
|
8
8
|
// ─── Configuration Options ────────────────────────────────────────
|
|
9
9
|
const FORMAT_OPTIONS = {
|
|
10
|
-
smallNotationUseE: true,
|
|
11
|
-
smallNotationThreshold: 4,
|
|
12
|
-
decimalPlaces: 3,
|
|
13
|
-
decimalThreshold: 3,
|
|
14
|
-
useCommas: true,
|
|
15
|
-
sciThreshold: 9,
|
|
16
|
-
sciSignificantDigits: 3,
|
|
17
|
-
sciDecimalThreshold: 3,
|
|
18
|
-
singleLetterDigits: 3,
|
|
19
|
-
repeatLetterThreshold: 3,
|
|
20
|
-
multiLetterDigits: 3,
|
|
21
|
-
multiLetterRepeatThreshold: 3
|
|
22
|
-
multiLetterLimit: 4,
|
|
23
|
-
epsilonSignificantDigits: 6
|
|
10
|
+
smallNotationUseE: true, //true/false
|
|
11
|
+
smallNotationThreshold: 4, //0~9
|
|
12
|
+
decimalPlaces: 3, //0~9
|
|
13
|
+
decimalThreshold: 3, //0~15
|
|
14
|
+
useCommas: true, //true/false
|
|
15
|
+
sciThreshold: 9, //0~15
|
|
16
|
+
sciSignificantDigits: 3, //0~9
|
|
17
|
+
sciDecimalThreshold: 3, //0~15
|
|
18
|
+
singleLetterDigits: 3, //0~9
|
|
19
|
+
repeatLetterThreshold: 3, //2~9
|
|
20
|
+
multiLetterDigits: 3, //0~9
|
|
21
|
+
multiLetterRepeatThreshold: 3,//2~9
|
|
22
|
+
multiLetterLimit: 4, //2~9
|
|
23
|
+
epsilonSignificantDigits: 6 //0~9
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// ─── Utility Functions ───────────────────────────────────────────
|
|
@@ -300,13 +300,25 @@ function letterTokenOf(height) {
|
|
|
300
300
|
let plain = letterName(height)
|
|
301
301
|
let limit = Math.max(2, FORMAT_OPTIONS.multiLetterLimit | 0)
|
|
302
302
|
if (plain.length <= limit) return { sym: "", letter: plain, arg: 0, mant: null }
|
|
303
|
+
// The carried form is "!" + the SINGLE-letter form αΓβ: "!" adds one ω^
|
|
304
|
+
// layer on top of the level Γ names, so a diagonal Aaa…a (= ω^k, too long
|
|
305
|
+
// for multiLetterLimit) becomes !αHβ with H = the finite level k —
|
|
306
|
+
// !2.000Aa4 = !1H10 = 10{ω^4}10, 2.000Aa4 = 1H10 = 10{4}10
|
|
307
|
+
// and β is the argument, which keeps ω³*50 / ω³*100 / ω³*200 apart
|
|
308
|
+
// (!1H51 / !1H101 / !1H201). Only once the single-letter chain itself is
|
|
309
|
+
// exhausted (!ZZZYYY{maxSafeInteger}) does the notation fall back to the
|
|
310
|
+
// coarser !αAaβ form.
|
|
311
|
+
let expo = plain.length - 1
|
|
312
|
+
if (expo >= 1 && expo <= 22) {
|
|
313
|
+
return { sym: "!", letter: letterName(expo), arg: expo, mant: 1, useBeta: true }
|
|
314
|
+
}
|
|
303
315
|
let mant = plain.charCodeAt(0) - 64 // coefficient of ω^(k-1)
|
|
304
316
|
for (let i = 1; i < plain.length; i++) {
|
|
305
317
|
mant += (plain.charCodeAt(i) - 97) * Math.pow(10, -i)
|
|
306
318
|
}
|
|
307
319
|
if (mant < 2) mant = 2 // diagonal [2,10) anchor
|
|
308
320
|
if (mant >= 10) mant = 9 + (mant - 10) / 170 // keep α ∈ [2,10)
|
|
309
|
-
return { sym: "!", letter: "Aa", arg:
|
|
321
|
+
return { sym: "!", letter: "Aa", arg: expo, mant: mant }
|
|
310
322
|
}
|
|
311
323
|
|
|
312
324
|
// Emit α·letter·β for a token: the plain form is αΓβ, the carried form is the
|
|
@@ -315,6 +327,9 @@ function emitLetterToken(tok, alphaStr, betaStr, precision) {
|
|
|
315
327
|
if (!tok.sym) return alphaStr + tok.letter + betaStr
|
|
316
328
|
let a = (tok.mant === null || tok.mant === undefined) ? alphaStr
|
|
317
329
|
: regularFormat(tok.mant, precision)
|
|
330
|
+
// the single-letter carried form keeps the caller's argument (!1H51), the
|
|
331
|
+
// Aa form carries the ω-exponent instead
|
|
332
|
+
if (tok.useBeta) return tok.sym + a + tok.letter + betaStr
|
|
318
333
|
return tok.sym + a + tok.letter + formatR0Arg(tok.arg, precision)
|
|
319
334
|
}
|
|
320
335
|
|
|
@@ -337,6 +352,36 @@ function symbolName(layer) {
|
|
|
337
352
|
// count = repetition count at ω-level
|
|
338
353
|
// value = ordinal level number (e.g., 901 means ω*901)
|
|
339
354
|
// Letter is always "Aa" (base ω-level)
|
|
355
|
+
|
|
356
|
+
// Snap CNF coefficients (little-endian [a1, a2, …, ak], ordinal
|
|
357
|
+
// ω^(k-1)·ak + … + ω·a2 + a1) to the ones the letter grid can name:
|
|
358
|
+
// every ai must satisfy 0 ≤ ai ≤ 25 and the top ak ≤ 26. Larger
|
|
359
|
+
// coefficients carry UP — ω*2+96 → ω*3 (Ca), ω*99 → ω² (Aaa),
|
|
360
|
+
// ω²*100 → ω³ (Aaaa) — so an unnamed ordinal displays as the next
|
|
361
|
+
// nameable one above it, never as a lower/wrong letter.
|
|
362
|
+
function snapCoeffsToGrid(coeffs) {
|
|
363
|
+
let r = (coeffs || []).slice()
|
|
364
|
+
// little-endian ORDINAL carry: index 0 is the constant term. A term above
|
|
365
|
+
// its grid bound absorbs everything below it (ω^i·c + lower < ω^(i+1)) and
|
|
366
|
+
// bumps the next power — ω*2+99 → ω*3 (Ca), ω*99+9 → ω² (Aaa),
|
|
367
|
+
// ω²*100 → ω³ (Aaaa) — so the snapped ordinal is the TIGHTEST nameable
|
|
368
|
+
// ordinal above the original one.
|
|
369
|
+
for (let i = 0; i < r.length; i++) {
|
|
370
|
+
let c = r[i]
|
|
371
|
+
if (typeof c !== 'number' || !isFinite(c) || c < 0) { r[i] = 0; continue }
|
|
372
|
+
c = Math.round(c) // integer coefficients only
|
|
373
|
+
let bound = (i === r.length - 1) ? 26 : 25 // top may reach 26 (A-Z)
|
|
374
|
+
if (c <= bound) { r[i] = c; continue }
|
|
375
|
+
for (let j = 0; j <= i; j++) r[j] = 0 // the carry absorbs the tail
|
|
376
|
+
if (i === r.length - 1) r.push(1) // ω^k·(bound+1) → ω^(k+1)
|
|
377
|
+
else r[i + 1] = (r[i + 1] || 0) + 1 // … → ω^(i+1)·(+1)
|
|
378
|
+
// keep scanning: the bumped slot may carry in turn
|
|
379
|
+
}
|
|
380
|
+
while (r.length > 1 && r[r.length - 1] === 0) r.pop()
|
|
381
|
+
if (r.length === 0) r = [1]
|
|
382
|
+
return r
|
|
383
|
+
}
|
|
384
|
+
|
|
340
385
|
function getOrdinalLetter(ordRows) {
|
|
341
386
|
if (!ordRows || ordRows.length === 0) return null
|
|
342
387
|
|
|
@@ -620,7 +665,7 @@ function format(num, precision=3, small=false) {
|
|
|
620
665
|
var expPart = Math.floor(magNum)
|
|
621
666
|
if (mant < 1) { mant *= 10; expPart -= 1 }
|
|
622
667
|
if (mant >= 9.999999999999999) { mant = 1; expPart += 1 }
|
|
623
|
-
return prefix + regularFormat(mant,
|
|
668
|
+
return prefix + regularFormat(mant, sciMantissaPrecision(expPart)) + "E-" + commaFormat(expPart)
|
|
624
669
|
}
|
|
625
670
|
}
|
|
626
671
|
// Tier 2: mag is large → "E-" + letter-law form of mag =
|
|
@@ -670,7 +715,7 @@ function format(num, precision=3, small=false) {
|
|
|
670
715
|
// Normalize: ensure m in [1, 10)
|
|
671
716
|
if (m < 1) { m *= 10; e -= 1 }
|
|
672
717
|
if (m >= 9.999999999999999) { m = 1; e += 1 }
|
|
673
|
-
return regularFormat(m,
|
|
718
|
+
return regularFormat(m, sciMantissaPrecision(e)) + "E-" + commaFormat(e)
|
|
674
719
|
}
|
|
675
720
|
// Fallback for non-simple values: use ⁻¹ notation
|
|
676
721
|
if (num.layer === 0 && num.array.length === 1 && num.array[0].length === 1) {
|
|
@@ -811,13 +856,14 @@ function formatLayer(num, precision, precision2, precision3, precision4) {
|
|
|
811
856
|
// This check must come before the compact !Aa form, otherwise ε layers
|
|
812
857
|
// get mis-rendered as "Aa..." (e.g. 1ε500 → "1.000Aa10")
|
|
813
858
|
if (num.layer > SYMBOLS.length) {
|
|
859
|
+
let epsPrecision = FORMAT_OPTIONS.epsilonSignificantDigits | 0
|
|
814
860
|
if (canCompact && compactBase >= 2 && Math.floor(compactBase) === compactBase) {
|
|
815
861
|
// Compact Aa form at ε layers folds into one more ε level:
|
|
816
862
|
// layer n + Aa-form ≡ ε(n+1) with mantissa 10^frac(compactBase)
|
|
817
863
|
let bottom = Math.pow(10, compactBase - Math.floor(compactBase))
|
|
818
|
-
return regularFormat(bottom,
|
|
864
|
+
return regularFormat(bottom, epsPrecision) + "ε" + commaFormat(num.layer + 1)
|
|
819
865
|
}
|
|
820
|
-
let innerStr = format(inner,
|
|
866
|
+
let innerStr = format(inner, epsPrecision, false)
|
|
821
867
|
return innerStr + "ε" + commaFormat(num.layer)
|
|
822
868
|
}
|
|
823
869
|
|
|
@@ -838,8 +884,13 @@ function formatLayer(num, precision, precision2, precision3, precision4) {
|
|
|
838
884
|
let mant = 2 * Math.pow(5, frac)
|
|
839
885
|
let limit = Math.max(2, FORMAT_OPTIONS.multiLetterLimit | 0)
|
|
840
886
|
if (mInt + 1 > limit) {
|
|
887
|
+
// Carry to the SINGLE-letter form sym αΓβ — same rule as "!":
|
|
888
|
+
// Γ is the finite level the diagonal names (10{ω^m}10 → letter of
|
|
889
|
+
// m) and β is the diagonal's argument, so the symbols stack
|
|
890
|
+
// identically: 10{ω^10}10 → !1.000N10, 10{ω^(ω^10)}10 → @1.000N10
|
|
841
891
|
let total = num.layer + 1
|
|
842
|
-
let body = regularFormat(
|
|
892
|
+
let body = regularFormat(1, precision4) + letterName(mInt) +
|
|
893
|
+
formatR0Arg(10, precision4)
|
|
843
894
|
if (total <= SYMBOLS.length) return SYMBOLS[total - 1] + body
|
|
844
895
|
return body + "ε" + commaFormat(total)
|
|
845
896
|
}
|
|
@@ -863,6 +914,23 @@ function formatLayer(num, precision, precision2, precision3, precision4) {
|
|
|
863
914
|
return sym + innerStr
|
|
864
915
|
}
|
|
865
916
|
|
|
917
|
+
// ─── Option-driven mantissa precisions ───────────────────────────
|
|
918
|
+
// Decimal places of the mantissa α in an αEβ form: sciSignificantDigits, but
|
|
919
|
+
// once the exponent β reaches 10^sciDecimalThreshold only the integer part of
|
|
920
|
+
// α is shown (the low digits carry no information at that height).
|
|
921
|
+
function sciMantissaPrecision(exponent) {
|
|
922
|
+
let t = FORMAT_OPTIONS.sciDecimalThreshold | 0
|
|
923
|
+
if (t > 0 && isFinite(exponent) && exponent >= Math.pow(10, t)) return 0
|
|
924
|
+
return FORMAT_OPTIONS.sciSignificantDigits | 0
|
|
925
|
+
}
|
|
926
|
+
// Decimal places of the mantissa α in αΓβ: E → sciSignificantDigits,
|
|
927
|
+
// F..Z → singleLetterDigits, Aa and beyond → multiLetterDigits.
|
|
928
|
+
function letterMantissaPrecision(level) {
|
|
929
|
+
if (level <= 1) return FORMAT_OPTIONS.sciSignificantDigits | 0
|
|
930
|
+
if (level <= 22) return FORMAT_OPTIONS.singleLetterDigits | 0
|
|
931
|
+
return FORMAT_OPTIONS.multiLetterDigits | 0
|
|
932
|
+
}
|
|
933
|
+
|
|
866
934
|
// ─── Format r0 Argument (plain number) ───────────────────────────
|
|
867
935
|
// Formats a plain numeric argument as either a plain number or αEβ notation.
|
|
868
936
|
// The mantissa α is always shown (even when 1.000).
|
|
@@ -879,7 +947,7 @@ function formatR0Arg(value, precision) {
|
|
|
879
947
|
if (m < 1) { m *= 10; e -= 1 }
|
|
880
948
|
if (m >= 9.999999999999999) { m = 1; e += 1 }
|
|
881
949
|
// Always show mantissa (αEβ format, e.g. 1.000E700)
|
|
882
|
-
return regularFormat(m,
|
|
950
|
+
return regularFormat(m, sciMantissaPrecision(e)) + "E" + commaFormat(e)
|
|
883
951
|
}
|
|
884
952
|
|
|
885
953
|
// ─── Gamma-Arg Recovery ─────────────────────────────────────────
|
|
@@ -928,7 +996,7 @@ function formatGammaBinary(x, level, precision) {
|
|
|
928
996
|
return letterName(level) + formatR0Arg(beta, precision)
|
|
929
997
|
}
|
|
930
998
|
let alpha = Math.pow(10, frac)
|
|
931
|
-
return regularFormat(alpha,
|
|
999
|
+
return regularFormat(alpha, letterMantissaPrecision(level)) + letterName(level) + formatR0Arg(beta, precision)
|
|
932
1000
|
}
|
|
933
1001
|
|
|
934
1002
|
// Distinct letter types in a display string: single-uppercase letters and
|
|
@@ -950,8 +1018,27 @@ function distinctLetterTypes(str) {
|
|
|
950
1018
|
// Format pattern: outerLetters + α + lastLetter + β
|
|
951
1019
|
// where α = 10^(base - floor(base)), β = floor(base) formatted as number or αEβ
|
|
952
1020
|
// e.g. EE200 → "E1.000E200", F300 → "1.000F300", FE400 → "F1.000E400"
|
|
953
|
-
|
|
1021
|
+
// Mantissa of a binary form αΓβ. A letter whose name ends in "a" is a
|
|
1022
|
+
// diagonal letter (Aa = ω, Ba = ω·2, Aaa = ω², …) and its binary form has
|
|
1023
|
+
// α = 2·5^f ∈ [2,10) — the diagonal 10{23}10 reads "2.000Aa23", never
|
|
1024
|
+
// "1.000Aa23". Every other letter keeps the ordinary [1,10) mantissa.
|
|
1025
|
+
function diagonalMantissa(letter, mantissa) {
|
|
1026
|
+
if (letter && letter.charAt(letter.length - 1) === 'a') {
|
|
1027
|
+
let f = mantissa - Math.floor(mantissa)
|
|
1028
|
+
if (!(f >= 0 && f < 1)) f = 0
|
|
1029
|
+
return 2 * Math.pow(5, f)
|
|
1030
|
+
}
|
|
1031
|
+
let mantVal = Math.pow(10, mantissa - Math.floor(mantissa))
|
|
1032
|
+
if (mantVal < 1) mantVal *= 10
|
|
1033
|
+
return mantVal
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// `used` = how many copies of the letter the caller already emitted: an inner
|
|
1037
|
+
// level may only promote to the next letter while the total stays within
|
|
1038
|
+
// repeatLetterThreshold, otherwise it saturates (see the noPromote block below).
|
|
1039
|
+
function formatR0AsChain(r0, precision, used) {
|
|
954
1040
|
if (r0.length === 0) r0 = [0]
|
|
1041
|
+
let usedCount = used || 0
|
|
955
1042
|
|
|
956
1043
|
// Find maxLevel (highest non-zero index in r0[1..])
|
|
957
1044
|
let maxLevel = 0
|
|
@@ -1026,23 +1113,43 @@ function formatR0AsChain(r0, precision) {
|
|
|
1026
1113
|
if (innerR0[maxLevel] === 0) {
|
|
1027
1114
|
innerR0 = innerR0.slice(0, maxLevel)
|
|
1028
1115
|
}
|
|
1029
|
-
let innerStr = formatR0AsChain(innerR0, precision)
|
|
1030
|
-
|
|
1031
|
-
//
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
let
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1116
|
+
let innerStr = formatR0AsChain(innerR0, precision, usedCount + 1)
|
|
1117
|
+
|
|
1118
|
+
// null = the inner level would need one more copy of the outer letter
|
|
1119
|
+
// than repeatLetterThreshold allows (3{3}6 = FFF(E^7.6e12) would spell a
|
|
1120
|
+
// fourth F). An inner level propagates it; the OUTERMOST call instead
|
|
1121
|
+
// falls through to the Γ-canonical collapse below, which renders the
|
|
1122
|
+
// whole value at the next letter by its real argument: "2.045G5".
|
|
1123
|
+
if (innerStr !== null) {
|
|
1124
|
+
// Check if innerStr already has letters (meaning deeper operations exist)
|
|
1125
|
+
let hasLetter = /[A-Z]/.test(innerStr)
|
|
1126
|
+
|
|
1127
|
+
if (!hasLetter) {
|
|
1128
|
+
// innerStr is a plain number: this is the innermost operation
|
|
1129
|
+
// Format: α + letterName(maxLevel) + innerStr
|
|
1130
|
+
let base = r0[0]
|
|
1131
|
+
let alpha = Math.pow(10, base - Math.floor(base))
|
|
1132
|
+
if (alpha < 1) alpha *= 10
|
|
1133
|
+
// an E letter's αEβ obeys sciDecimalThreshold: β ≥ 10^n → α
|
|
1134
|
+
// keeps only its integer part
|
|
1135
|
+
let mantPrec = (maxLevel === 1)
|
|
1136
|
+
? sciMantissaPrecision(Number(String(innerStr).replace(/,/g, '')))
|
|
1137
|
+
: letterMantissaPrecision(maxLevel)
|
|
1138
|
+
let alphaStr = regularFormat(alpha, mantPrec)
|
|
1139
|
+
return alphaStr + letterName(maxLevel) + innerStr
|
|
1140
|
+
} else {
|
|
1141
|
+
// innerStr already has α and letters: just prepend the outer letter
|
|
1142
|
+
return letterName(maxLevel) + innerStr
|
|
1143
|
+
}
|
|
1045
1144
|
}
|
|
1145
|
+
if (usedCount > 0) return null
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// count > effThreshold and the promotion would exceed repeatLetterThreshold
|
|
1149
|
+
// copies of the letter in front of it: signal the caller (the structural
|
|
1150
|
+
// spelling is impossible) instead of spelling an extra copy.
|
|
1151
|
+
if (usedCount + 1 > effThreshold) {
|
|
1152
|
+
return null
|
|
1046
1153
|
}
|
|
1047
1154
|
|
|
1048
1155
|
// count >= effThreshold: promote to next level (maxLevel + 1)
|
|
@@ -1076,7 +1183,7 @@ function formatR0AsChain(r0, precision) {
|
|
|
1076
1183
|
// Format: α + letter + β (always show α)
|
|
1077
1184
|
let alpha = Math.pow(10, arg - Math.floor(arg))
|
|
1078
1185
|
if (alpha < 1) alpha *= 10
|
|
1079
|
-
let alphaStr = regularFormat(alpha,
|
|
1186
|
+
let alphaStr = regularFormat(alpha, letterMantissaPrecision(level))
|
|
1080
1187
|
let betaStr = formatR0Arg(Math.floor(arg), precision)
|
|
1081
1188
|
return alphaStr + letter + betaStr
|
|
1082
1189
|
}
|
|
@@ -1105,13 +1212,13 @@ function formatR0AsChain(r0, precision) {
|
|
|
1105
1212
|
if (innerR0[maxLevel] === 0) {
|
|
1106
1213
|
innerR0 = innerR0.slice(0, maxLevel)
|
|
1107
1214
|
}
|
|
1108
|
-
let innerStr = formatR0AsChain(innerR0, precision)
|
|
1215
|
+
let innerStr = formatR0AsChain(innerR0, precision, true)
|
|
1109
1216
|
let hasLetter = /[A-Z]/.test(innerStr)
|
|
1110
1217
|
if (!hasLetter) {
|
|
1111
1218
|
let base = r0[0]
|
|
1112
1219
|
let alpha = Math.pow(10, base - Math.floor(base))
|
|
1113
1220
|
if (alpha < 1) alpha *= 10
|
|
1114
|
-
return regularFormat(alpha,
|
|
1221
|
+
return regularFormat(alpha, letterMantissaPrecision(maxLevel)) + letterName(maxLevel) + innerStr
|
|
1115
1222
|
}
|
|
1116
1223
|
// inner carries letters: bare outer letter (2-letter rule) — the
|
|
1117
1224
|
// inner top must be LOWER (descending chain); ascending or same-level
|
|
@@ -1472,7 +1579,19 @@ function formatOrdinal(num, precision, precision4) {
|
|
|
1472
1579
|
// as one more symbol with the chain as its argument
|
|
1473
1580
|
return tokAa.sym + regularFormat(2, precision4) + tokAa.letter + argStr
|
|
1474
1581
|
}
|
|
1475
|
-
|
|
1582
|
+
// past the collapse threshold the repeats shift the argument and
|
|
1583
|
+
// advance the letter — a raw repeat would try to build a string
|
|
1584
|
+
// with `count` copies (Aaa repeated 1e9 times cannot be built)
|
|
1585
|
+
let repArgStr = argStr
|
|
1586
|
+
if (totalAaCount > 64) {
|
|
1587
|
+
let r0Bottom = Math.pow(10, r0[0] - Math.floor(r0[0]))
|
|
1588
|
+
let repParam = totalAaCount + 1
|
|
1589
|
+
let mantissa = Math.log10(Math.max(r0Bottom, 0.001)) +
|
|
1590
|
+
Math.log10(Math.max(repParam, 1)) * 0.4 + 1.6
|
|
1591
|
+
return regularFormat(mantissa, precision4) +
|
|
1592
|
+
letterName(baseHeight + 1) + commaFormat(repParam)
|
|
1593
|
+
}
|
|
1594
|
+
return letter.repeat(totalAaCount) + repArgStr
|
|
1476
1595
|
} else {
|
|
1477
1596
|
// Single Aa
|
|
1478
1597
|
let tokAa = letterTokenOf(baseHeight)
|
|
@@ -1494,11 +1613,16 @@ function formatOrdinal(num, precision, precision4) {
|
|
|
1494
1613
|
let collapseAt = effThreshold + 1
|
|
1495
1614
|
|
|
1496
1615
|
if (totalAaCount >= collapseAt) {
|
|
1497
|
-
// Collapse to next letter (Aa→Ab, Ab→Ac, etc.)
|
|
1498
|
-
|
|
1616
|
+
// Collapse to next letter (Aa→Ab, Ab→Ac, etc.): the repeats
|
|
1617
|
+
// shift the argument (arg = count+1) and the mantissa keeps
|
|
1618
|
+
// the [1,10) convention (2.398Ab99 — the same α the GRAHAMS
|
|
1619
|
+
// branch above produces), never the raw count as α
|
|
1620
|
+
let arg = totalAaCount + 1
|
|
1621
|
+
let mantVal = Math.log10(Math.max(alpha, 0.001)) +
|
|
1622
|
+
Math.log10(Math.max(arg, 1)) * 0.4 + 1.6
|
|
1499
1623
|
let newHeight = baseHeight + 1
|
|
1500
1624
|
let newLetter = letterName(newHeight)
|
|
1501
|
-
return regularFormat(
|
|
1625
|
+
return regularFormat(mantVal, precision4) + newLetter + formatR0Arg(arg, precision4)
|
|
1502
1626
|
} else if (totalAaCount > 1) {
|
|
1503
1627
|
// Repeated letters: outerLetters + α + lastLetter + β
|
|
1504
1628
|
let outerLetters = letter.repeat(totalAaCount - 1)
|
|
@@ -1514,18 +1638,89 @@ function formatOrdinal(num, precision, precision4) {
|
|
|
1514
1638
|
let diagMant = 2 * Math.pow(5, base - Math.floor(base))
|
|
1515
1639
|
let diagBeta = (base === aaZeroCount) ? 10 : top
|
|
1516
1640
|
// multiLetterLimit symbol carry: A + aaZeroCount a's is
|
|
1517
|
-
// aaZeroCount+1 letters — past the limit the diagonal reads
|
|
1518
|
-
//
|
|
1519
|
-
// (10{ω^10}10 → !
|
|
1641
|
+
// aaZeroCount+1 letters — past the limit the diagonal reads as
|
|
1642
|
+
// one more symbol with the SINGLE letter of the finite level
|
|
1643
|
+
// aaZeroCount (10{ω^10}10 → !1.000N10)
|
|
1520
1644
|
if (aaZeroCount + 1 > Math.max(2, FORMAT_OPTIONS.multiLetterLimit | 0)) {
|
|
1521
|
-
return "!" + regularFormat(
|
|
1522
|
-
|
|
1645
|
+
return "!" + regularFormat(1, precision4) +
|
|
1646
|
+
letterName(aaZeroCount) + formatR0Arg(10, precision4)
|
|
1523
1647
|
}
|
|
1524
1648
|
return regularFormat(diagMant, precision4) + letter + commaFormat(diagBeta)
|
|
1525
1649
|
}
|
|
1526
1650
|
}
|
|
1527
1651
|
}
|
|
1528
|
-
|
|
1652
|
+
|
|
1653
|
+
// ── Unnamed-level display (v2.0.2) ──
|
|
1654
|
+
// The letter grid only names ordinals with coefficients ≤ 25 (top ≤ 26).
|
|
1655
|
+
// When the TOP row's ordinal is above that (ω*2+96, ω*99, ω²*100, …), every
|
|
1656
|
+
// row of the cascade snaps up to the SAME next nameable level, and summing
|
|
1657
|
+
// their counts would collapse the letter further (243 Ca's → Cb(244)) —
|
|
1658
|
+
// overstating the level and hiding the argument. Instead the value reads
|
|
1659
|
+
// as level-arg: the snapped level with the operation's own argument —
|
|
1660
|
+
// 10{ω*2+100}100 → "1.000Ca100", 10{ω*100}100 → "1.000Aaa100",
|
|
1661
|
+
// 10{ω²*100+ω*100+100}1000 → "1.000Aaaa1,000".
|
|
1662
|
+
let gapStr = null
|
|
1663
|
+
{
|
|
1664
|
+
let topRow = ordRows[ordRows.length - 1]
|
|
1665
|
+
if (topRow && topRow.length >= 3) {
|
|
1666
|
+
let oc = topRow.slice(1)
|
|
1667
|
+
let carried = false
|
|
1668
|
+
for (let gi = 0; gi < oc.length; gi++) {
|
|
1669
|
+
let gc = oc[gi]
|
|
1670
|
+
let gbound = (gi === oc.length - 1) ? 26 : 25
|
|
1671
|
+
if (typeof gc !== 'number' || !isFinite(gc) || gc < 0 ||
|
|
1672
|
+
Math.round(gc) > gbound) { carried = true; break }
|
|
1673
|
+
}
|
|
1674
|
+
if (carried) {
|
|
1675
|
+
let g = snapCoeffsToGrid(oc)
|
|
1676
|
+
let gdiag = g[g.length - 1]
|
|
1677
|
+
let gvals = g.slice(0, g.length - 1)
|
|
1678
|
+
let gh = 23 + (gdiag - 1) * 26 + (gvals.length ? gvals[0] : 0)
|
|
1679
|
+
if (gvals.length >= 2) {
|
|
1680
|
+
let goffset = 0
|
|
1681
|
+
for (let gk = 2; gk <= gvals.length; gk++) goffset += Math.pow(26, gk)
|
|
1682
|
+
let gn = (gdiag - 1) * Math.pow(26, gvals.length)
|
|
1683
|
+
for (let gj = 0; gj < gvals.length; gj++) gn += gvals[gj] * Math.pow(26, gj)
|
|
1684
|
+
gh = 23 + goffset + gn
|
|
1685
|
+
}
|
|
1686
|
+
// β = the fundamental-sequence index that recovers the ordinal
|
|
1687
|
+
// from the snapped level. When the carry is in the TOP
|
|
1688
|
+
// coefficient (ω^p·c → ω^(p+1)) that index is c+1:
|
|
1689
|
+
// 10{ω²·50+ω·100+100}100 → "2.000Aaaa51"
|
|
1690
|
+
// 10{ω²·100+ω·100+100}100 → "2.000Aaaa101"
|
|
1691
|
+
// 10{ω²·200+…}100 → "2.000Aaaa201"
|
|
1692
|
+
// (taking the largest coefficient instead collapsed all three
|
|
1693
|
+
// of 50/60/100 into one string). When the carry is BELOW the
|
|
1694
|
+
// top (ω·2+100 → ω·3) the index is the operation's argument.
|
|
1695
|
+
let gbeta = (topRow[0] || 1) + 2
|
|
1696
|
+
for (let g2 = oc.length - 1; g2 >= 0; g2--) {
|
|
1697
|
+
let gc2 = Math.round(oc[g2])
|
|
1698
|
+
let gbound = (g2 === oc.length - 1) ? 26 : 25
|
|
1699
|
+
if (isFinite(gc2) && gc2 > gbound) { gbeta = gc2 + 1; break }
|
|
1700
|
+
}
|
|
1701
|
+
let gtok = letterTokenOf(gh)
|
|
1702
|
+
let gbase = r0[0]
|
|
1703
|
+
let galpha = Math.pow(10, gbase - Math.floor(gbase))
|
|
1704
|
+
if (galpha < 1) galpha *= 10
|
|
1705
|
+
if (gtok.sym) {
|
|
1706
|
+
// the carried !αAaβ form: β is the ω-EXPONENT of the
|
|
1707
|
+
// snapped level (ω³·50+… → ω⁴ → "!2.000Aa4"), not the
|
|
1708
|
+
// fundamental-sequence index — !2.000Aa51 would read as
|
|
1709
|
+
// the ω⁵¹ level (README: !αAaβ = ω^β + digits of α)
|
|
1710
|
+
gapStr = emitLetterToken(gtok, regularFormat(gtok.mant, precision4),
|
|
1711
|
+
formatR0Arg(gbeta, precision4), precision4)
|
|
1712
|
+
} else {
|
|
1713
|
+
// a diagonal letter ("Ca", "Aaa", …) carries α = 2·5^f ∈
|
|
1714
|
+
// [2,10) — never the [1,10) mantissa of the other letters
|
|
1715
|
+
gapStr = regularFormat(
|
|
1716
|
+
diagonalMantissa(gtok.letter, Math.log10(galpha)), precision4) +
|
|
1717
|
+
gtok.letter + formatR0Arg(gbeta, precision4)
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
if (gapStr !== null) return gapStr
|
|
1723
|
+
|
|
1529
1724
|
// ── Check for repeated non-ω letters → advance to next letter ──
|
|
1530
1725
|
// AbAb→Ac, AcAc→Ad, ..., AzAz→Ba, BaBa→Bb, etc.
|
|
1531
1726
|
// Only applies when repeat count >= multiLetterRepeatThreshold
|
|
@@ -1536,8 +1731,13 @@ function formatOrdinal(num, precision, precision4) {
|
|
|
1536
1731
|
for (let i = 0; i < ordRows.length; i++) {
|
|
1537
1732
|
let row = ordRows[i]
|
|
1538
1733
|
if (row.length < 3) { allSameLetter = false; break }
|
|
1539
|
-
|
|
1540
|
-
|
|
1734
|
+
// The letter grid only names ordinals whose coefficients are ≤ 25 (the
|
|
1735
|
+
// top one ≤ 26); anything larger (ω*2+96, ω*99, ω²*100, …) is rounded UP
|
|
1736
|
+
// to the next nameable ordinal — ω*2+96 → ω*3 (Ca), ω*99 → ω² (Aaa),
|
|
1737
|
+
// ω²*100 → ω³ (Aaaa) — never clamped down, never wrapped.
|
|
1738
|
+
let g = snapCoeffsToGrid(row.slice(1))
|
|
1739
|
+
let diag = g[g.length - 1]
|
|
1740
|
+
let vals = g.slice(0, g.length - 1)
|
|
1541
1741
|
let nVals = vals.length
|
|
1542
1742
|
|
|
1543
1743
|
// Calculate height for this letter
|
|
@@ -1591,19 +1791,24 @@ function formatOrdinal(num, precision, precision4) {
|
|
|
1591
1791
|
let letter = letterName(baseLetterHeight)
|
|
1592
1792
|
let tokAdv = letterTokenOf(baseLetterHeight + 1)
|
|
1593
1793
|
if (totalRepeat >= collapseAt && tokAdv.sym) {
|
|
1594
|
-
// Collapse to next letter — carried when it exceeds the limit
|
|
1595
|
-
//
|
|
1596
|
-
|
|
1597
|
-
|
|
1794
|
+
// Collapse to next letter — carried when it exceeds the limit.
|
|
1795
|
+
// !αAaβ takes the ω-EXPONENT as β (README: !αAaβ = ω^β + the
|
|
1796
|
+
// digits of α), not the r0 chain.
|
|
1797
|
+
return emitLetterToken(tokAdv, regularFormat(tokAdv.mant, precision4),
|
|
1798
|
+
r0Str, precision4)
|
|
1598
1799
|
}
|
|
1599
1800
|
if (totalRepeat >= collapseAt) {
|
|
1600
|
-
// Collapse to next letter
|
|
1801
|
+
// Collapse to next letter — the repeat count shifts the
|
|
1802
|
+
// argument, so the mantissa keeps the [1,10) convention
|
|
1601
1803
|
let mantissa = Math.log10(Math.max(alpha, 0.001)) + totalRepeat
|
|
1602
1804
|
let newLetter = letterName(baseLetterHeight + 1)
|
|
1603
|
-
|
|
1805
|
+
let mantVal = diagonalMantissa(newLetter, mantissa)
|
|
1806
|
+
return regularFormat(mantVal, precision4) + newLetter + r0Str
|
|
1604
1807
|
} else if (totalRepeat > 1) {
|
|
1605
|
-
// Repeated letters + chain
|
|
1606
|
-
|
|
1808
|
+
// Repeated letters + chain: one token per application, the
|
|
1809
|
+
// innermost one in front of the chain (Ba(Ba(1e16)) → the
|
|
1810
|
+
// stacked "BaBa1.000E16" — apea(apea(a)) must stay visible)
|
|
1811
|
+
let outerLetters = letter.repeat(totalRepeat)
|
|
1607
1812
|
return outerLetters + r0Str
|
|
1608
1813
|
} else {
|
|
1609
1814
|
// Single letter + chain
|
|
@@ -1622,7 +1827,9 @@ function formatOrdinal(num, precision, precision4) {
|
|
|
1622
1827
|
let mantissa = Math.log10(Math.max(alpha, 0.001)) + totalRepeat
|
|
1623
1828
|
let newHeight = baseLetterHeight + 1
|
|
1624
1829
|
let letter = letterName(newHeight)
|
|
1625
|
-
|
|
1830
|
+
let mantVal = diagonalMantissa(letter, mantissa)
|
|
1831
|
+
return regularFormat(mantVal, precision4) + letter +
|
|
1832
|
+
formatR0Arg(totalRepeat + 1, precision4)
|
|
1626
1833
|
} else if (totalRepeat > 1) {
|
|
1627
1834
|
// Repeated letters: outerLetters + α + lastLetter + β
|
|
1628
1835
|
let letter = letterName(baseLetterHeight)
|
|
@@ -1674,16 +1881,24 @@ function formatOrdinal(num, precision, precision4) {
|
|
|
1674
1881
|
if (row.length === 2) {
|
|
1675
1882
|
height = 23 // ω-level (Aa)
|
|
1676
1883
|
} else {
|
|
1677
|
-
|
|
1678
|
-
|
|
1884
|
+
// round the ordinal UP to the next one the letter grid can name
|
|
1885
|
+
// (ω*2+96 → ω*3 = Ca, ω*99 → ω² = Aaa, ω²*100 → ω³ = Aaaa)
|
|
1886
|
+
let g2 = snapCoeffsToGrid(row.slice(1))
|
|
1887
|
+
let diag = g2[g2.length - 1]
|
|
1888
|
+
let vals = g2.slice(0, g2.length - 1)
|
|
1679
1889
|
let nVals = vals.length
|
|
1680
1890
|
if (nVals === 1) {
|
|
1891
|
+
// 2-letter: Aa=23, Ab=24, ..., Az=48, Ba=49, ...
|
|
1681
1892
|
height = 23 + (diag - 1) * 26 + vals[0]
|
|
1682
1893
|
} else {
|
|
1894
|
+
// vals are the CNF coefficients a1, a2, …, a(x-1) of
|
|
1895
|
+
// ord = ω^(x-1)·ax + … + ω·a2 + a1 — little-endian, the same
|
|
1896
|
+
// order letterName()/getOrdinalLetter() decode the letter:
|
|
1897
|
+
// the LAST val is the first lowercase letter of the token.
|
|
1683
1898
|
let offset = 0
|
|
1684
1899
|
for (let k = 2; k <= nVals; k++) offset += Math.pow(26, k)
|
|
1685
1900
|
let n = (diag - 1) * Math.pow(26, nVals)
|
|
1686
|
-
for (let j = 0; j < nVals; j++) n += vals[j] * Math.pow(26,
|
|
1901
|
+
for (let j = 0; j < nVals; j++) n += vals[j] * Math.pow(26, j)
|
|
1687
1902
|
height = 23 + offset + n
|
|
1688
1903
|
}
|
|
1689
1904
|
}
|
|
@@ -1694,109 +1909,107 @@ function formatOrdinal(num, precision, precision4) {
|
|
|
1694
1909
|
letterCounts[height] = (letterCounts[height] || 0) + count
|
|
1695
1910
|
}
|
|
1696
1911
|
|
|
1697
|
-
if (heights.length >=
|
|
1912
|
+
if (heights.length >= 1) {
|
|
1698
1913
|
// Sort heights ascending
|
|
1699
1914
|
heights.sort((a, b) => a - b)
|
|
1700
1915
|
|
|
1701
1916
|
// README: at most TWO finite letter types survive — a longer
|
|
1702
|
-
// cascade keeps only its top two levels
|
|
1703
|
-
// into the second letter's
|
|
1917
|
+
// cascade keeps only its top two levels, every lower row
|
|
1918
|
+
// compresses into the second letter's argument (they are below
|
|
1919
|
+
// display precision, and folding them into its repeat COUNT would
|
|
1920
|
+
// overstate the level: 8 ω's + 8 (ω+1)'s ≠ 16 more (ω+2)'s).
|
|
1704
1921
|
if (heights.length > 2) {
|
|
1705
1922
|
let keepLo = heights[heights.length - 2]
|
|
1706
|
-
for (let i = 0; i < heights.length - 2; i++)
|
|
1707
|
-
letterCounts[keepLo] = (letterCounts[keepLo] || 0) + (letterCounts[heights[i]] || 0)
|
|
1708
|
-
delete letterCounts[heights[i]]
|
|
1709
|
-
}
|
|
1923
|
+
for (let i = 0; i < heights.length - 2; i++) delete letterCounts[heights[i]]
|
|
1710
1924
|
heights = Object.keys(letterCounts).map(Number).sort((a, b) => a - b)
|
|
1711
1925
|
}
|
|
1712
1926
|
|
|
1713
|
-
// Collapse from lowest to highest
|
|
1714
|
-
let effThreshold = Math.max(2, FORMAT_OPTIONS.multiLetterRepeatThreshold)
|
|
1715
|
-
let collapseAt = effThreshold + 1
|
|
1716
|
-
let collapseInfo = {} // height -> collapsedFromCount
|
|
1717
|
-
|
|
1718
|
-
for (let h of heights.slice()) {
|
|
1719
|
-
let count = letterCounts[h] || 0
|
|
1720
|
-
if (count >= collapseAt) {
|
|
1721
|
-
let nextH = h + 1
|
|
1722
|
-
if (!(nextH in letterCounts) && heights.indexOf(nextH) < 0) heights.push(nextH)
|
|
1723
|
-
letterCounts[nextH] = (letterCounts[nextH] || 0) + 1
|
|
1724
|
-
collapseInfo[nextH] = count
|
|
1725
|
-
delete letterCounts[h]
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
// Re-sort after collapse
|
|
1730
|
-
heights = Object.keys(letterCounts).map(Number).sort((a, b) => a - b)
|
|
1731
|
-
|
|
1732
1927
|
if (heights.length >= 1) {
|
|
1733
1928
|
// ── Display rules (README "format-metanum rules (v2.0)") ──
|
|
1734
|
-
// *
|
|
1735
|
-
//
|
|
1736
|
-
// the
|
|
1737
|
-
//
|
|
1929
|
+
// * the rows are a COMPOSITION: the top row is the outermost
|
|
1930
|
+
// operation, so it leads the display and the row below it
|
|
1931
|
+
// supplies the single α and β (at most TWO letter types —
|
|
1932
|
+
// every lower row compresses into that inner argument);
|
|
1933
|
+
// * "+count collapse": count >= multiLetterRepeatThreshold+1
|
|
1934
|
+
// repeats of a letter collapse to ONE next letter with
|
|
1935
|
+
// arg count+1 (F⁴(G(1.3796)) = G(5.3796));
|
|
1936
|
+
// * stacking the same function therefore nests the letter:
|
|
1937
|
+
// poea(10,poea(10,100)) = Ad(Ad(99)) → "Ad1.000Ad99";
|
|
1738
1938
|
// * a combination longer than multiLetterLimit carries to the
|
|
1739
|
-
// symbol notation !αAa
|
|
1939
|
+
// symbol notation !αAaβ.
|
|
1740
1940
|
let effTh = Math.max(2, FORMAT_OPTIONS.multiLetterRepeatThreshold)
|
|
1941
|
+
let collapseAt = effTh + 1
|
|
1741
1942
|
|
|
1742
|
-
// (1) the single α / β pair
|
|
1743
1943
|
let base = r0[0]
|
|
1744
1944
|
let r0Alpha = Math.pow(10, base - Math.floor(base))
|
|
1745
1945
|
if (r0Alpha < 1) r0Alpha *= 10
|
|
1746
1946
|
let frac = base - Math.floor(base)
|
|
1747
1947
|
if (frac < 0) frac += 1
|
|
1748
1948
|
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1949
|
+
// α of a "+count collapse" (the ω-level form recovers the base
|
|
1950
|
+
// mantissa the way the single-row Aa cascade does: 2.398Ab99)
|
|
1951
|
+
let collapseMant = function (h, count) {
|
|
1952
|
+
let arg = count + 1
|
|
1953
|
+
if (h === 23) {
|
|
1954
|
+
return regularFormat(Math.log10(Math.max(r0Alpha, 0.001)) +
|
|
1955
|
+
Math.log10(Math.max(arg, 1)) * 0.4 + 1.6, precision4)
|
|
1956
|
+
}
|
|
1957
|
+
return regularFormat(r0Alpha, precision4)
|
|
1958
|
+
}
|
|
1959
|
+
// one collapsed level: α + next letter + (count+1)
|
|
1960
|
+
let collapseStr = function (h, count) {
|
|
1961
|
+
let tok = letterTokenOf(h + 1)
|
|
1962
|
+
if (tok.sym) {
|
|
1963
|
+
return tok.sym + regularFormat(tok.mant, precision4) +
|
|
1964
|
+
tok.letter + formatR0Arg(count + 1, precision4)
|
|
1965
|
+
}
|
|
1966
|
+
return collapseMant(h, count) + tok.letter + formatR0Arg(count + 1, precision4)
|
|
1752
1967
|
}
|
|
1753
1968
|
|
|
1754
|
-
let
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1969
|
+
let hTop = heights[heights.length - 1]
|
|
1970
|
+
let cTop = letterCounts[hTop] || 1
|
|
1971
|
+
let hLow = heights.length >= 2 ? heights[heights.length - 2] : -1
|
|
1972
|
+
let cLow = hLow < 0 ? 0 : (letterCounts[hLow] || 1)
|
|
1973
|
+
|
|
1974
|
+
// (1) a single row level: collapse, or repeats with α + letter + β
|
|
1975
|
+
if (hLow < 0) {
|
|
1976
|
+
if (cTop >= collapseAt) return collapseStr(hTop, cTop)
|
|
1977
|
+
let tok = letterTokenOf(hTop)
|
|
1978
|
+
if (tok.sym) return emitLetterToken(tok, regularFormat(r0Alpha, precision4),
|
|
1979
|
+
formatR0Arg(Math.floor(base), precision4), precision4)
|
|
1980
|
+
let aStr = (tok.letter.length >= 2 && tok.letter[tok.letter.length - 1] === "a")
|
|
1981
|
+
? regularFormat(2 * Math.pow(5, frac), precision4)
|
|
1982
|
+
: regularFormat(r0Alpha, precision4)
|
|
1983
|
+
return tok.letter.repeat(Math.max(cTop - 1, 0)) + aStr + tok.letter +
|
|
1984
|
+
formatR0Arg(Math.floor(base), precision4)
|
|
1766
1985
|
}
|
|
1767
|
-
|
|
1768
|
-
//
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
return regularFormat(2 * Math.pow(5, frac), precision4)
|
|
1986
|
+
|
|
1987
|
+
// (2) the inner (second) level carries the single α and β
|
|
1988
|
+
let lowTok = letterTokenOf(hLow)
|
|
1989
|
+
let innerStr
|
|
1990
|
+
if (cLow >= collapseAt) {
|
|
1991
|
+
innerStr = collapseStr(hLow, cLow)
|
|
1992
|
+
} else {
|
|
1993
|
+
let aStr = regularFormat(r0Alpha, precision4)
|
|
1994
|
+
innerStr = lowTok.letter.repeat(Math.max(cLow - 1, 0)) + aStr + lowTok.letter +
|
|
1995
|
+
formatR0Arg(Math.floor(base), precision4)
|
|
1778
1996
|
}
|
|
1779
1997
|
|
|
1780
|
-
// (3)
|
|
1781
|
-
|
|
1782
|
-
|
|
1998
|
+
// (3) the top level leads: collapse when it repeats enough, else
|
|
1999
|
+
// one token per application (or the symbol-carried !αAaβ)
|
|
2000
|
+
if (cTop >= collapseAt) return collapseStr(hTop, cTop)
|
|
2001
|
+
let topTok = letterTokenOf(hTop)
|
|
1783
2002
|
if (topTok.sym) {
|
|
1784
|
-
//
|
|
1785
|
-
//
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
Math.min(letterCounts[descHeights[0]] || 1, effTh))
|
|
1790
|
-
if (descHeights.length >= 2) {
|
|
1791
|
-
let loH = descHeights[1]
|
|
1792
|
-
let loTok = letterTokenOf(loH)
|
|
1793
|
-
let loCnt = letterCounts[loH] || 1
|
|
1794
|
-
if (loCnt > 1) {
|
|
1795
|
-
outerLetters += loTok.letter.repeat(Math.min(loCnt - 1, effTh))
|
|
2003
|
+
// multiLetterLimit carry: !αAaβ, β = the ω-exponent; the
|
|
2004
|
+
// inner level only survives when it collapses on its own
|
|
2005
|
+
if (cLow >= collapseAt) {
|
|
2006
|
+
return topTok.sym + regularFormat(topTok.mant, precision4) +
|
|
2007
|
+
topTok.letter + collapseStr(hLow, cLow)
|
|
1796
2008
|
}
|
|
1797
|
-
return
|
|
2009
|
+
return topTok.sym + regularFormat(topTok.mant, precision4) +
|
|
2010
|
+
topTok.letter + formatR0Arg(topTok.arg, precision4)
|
|
1798
2011
|
}
|
|
1799
|
-
return
|
|
2012
|
+
return topTok.letter.repeat(Math.min(cTop, effTh)) + innerStr
|
|
1800
2013
|
}
|
|
1801
2014
|
}
|
|
1802
2015
|
}
|