metanum 2.0.1 → 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/metanum.js CHANGED
@@ -2063,9 +2063,21 @@
2063
2063
  if (other.eq(MetaNum.ONE)) return self.clone();
2064
2064
  if (frac.eq(MetaNum.ZERO)) return self.arrow(nLev)(other);
2065
2065
  var target = self.arrow(nLev)(other);
2066
- var theta0 = target.hyper_log(self)(nLev.add(MetaNum.ONE));
2066
+ var lev1 = nLev.add(MetaNum.ONE);
2067
+ var theta0 = hyperAnchorReal(self, lev1, target);
2068
+ if (theta0 === null) theta0 = target.hyper_log(self)(lev1);
2069
+ if (theta0.isNaN() || !(theta0.gt(MetaNum.ZERO))) theta0 = MetaNum.ONE.clone();
2067
2070
  var theta = theta0.mul(other.div(theta0).pow(frac));
2068
- return self.arrow(nLev.add(MetaNum.ONE))(theta);
2071
+ var res = self.arrow(lev1)(theta);
2072
+ if (hasFractionOutsideR00(res)) {
2073
+ // levels that diagonalize into ordinal rows would keep the
2074
+ // interpolated argument as a fractional row count — fall back to the
2075
+ // integer argument so the "only array[0][0] is fractional" contract
2076
+ // holds (floor is exact again at f = 1, where θ = y)
2077
+ var ti = Math.max(1, Math.floor(theta.toNumber()));
2078
+ if (isFinite(ti)) res = self.arrow(lev1)(new MetaNum(ti));
2079
+ }
2080
+ return res;
2069
2081
  };
2070
2082
  }
2071
2083
  return function () { return MetaNum.NaN.clone(); };
@@ -2393,6 +2405,29 @@
2393
2405
  return hi;
2394
2406
  }
2395
2407
 
2408
+ // Continuous inverse used as the interpolation ANCHOR of a fractional level:
2409
+ // the real c with a{b}c = d, searched by bisection on doubles (arrow()
2410
+ // evaluates fractional arguments). hyperBisect only searches integers and
2411
+ // therefore overshoots (θ0 = 2 where the true value is 1.0414), which makes
2412
+ // the geometric interpolation θ = θ0·(y/θ0)^f run BACKWARDS (y/θ0 < 1) and
2413
+ // breaks the monotonicity of x{y}y — arrow(10,1.5,1.5) came out smaller than
2414
+ // arrow(10,1.1,1.1). Returns null when d cannot be bracketed.
2415
+ function hyperAnchorReal(a, b, d) {
2416
+ try {
2417
+ var lo = 0, hi = 1, it = 0;
2418
+ while (it++ < 60 && a.arrow(b)(new MetaNum(hi)).lt(d)) { lo = hi; hi = hi * 2; }
2419
+ if (!isFinite(hi) || hi > 1e15) return null;
2420
+ for (var k = 0; k < 80; k++) {
2421
+ var mid = (lo + hi) / 2;
2422
+ if (a.arrow(b)(new MetaNum(mid)).lt(d)) lo = mid; else hi = mid;
2423
+ }
2424
+ var r = new MetaNum((lo + hi) / 2);
2425
+ return r.isNaN() ? null : r;
2426
+ } catch (e) {
2427
+ return null;
2428
+ }
2429
+ }
2430
+
2396
2431
  P.hyper_log = function (a) {
2397
2432
  var d = this.clone();
2398
2433
  a = new MetaNum(a);
@@ -2814,6 +2849,22 @@
2814
2849
  for (var j = 0; j < keep.length; j++) arr.push(keep[j]);
2815
2850
  }
2816
2851
 
2852
+ // Layer marker WITHOUT the standard-form rewrites. hardy's tower rule needs
2853
+ // the layer to track the input's 10^ levels one-for-one — the standard
2854
+ // de-layer ((b) above) would fold a finite-bracket marker (e.g. the
2855
+ // layer-2 [[3086.036,9×8]] of eee10) down one layer and change the number
2856
+ // the rule is about. Same shape as _layerMarker, minus the rewrites.
2857
+ Q._rawLayerMarker = function (r0, layer, rows) {
2858
+ var v = new MetaNum(0);
2859
+ v.sign = 1;
2860
+ v.layer = layer > 0 ? layer : 0;
2861
+ v.array = [(r0 && r0.length) ? r0.slice() : [0]];
2862
+ for (var i = 0; i < (rows ? rows.length : 0); i++) {
2863
+ if (rows[i] && rows[i].length > 1) v.array.push(rows[i].slice());
2864
+ }
2865
+ return v;
2866
+ };
2867
+
2817
2868
  Q._standardizeLayerValue = function (v) {
2818
2869
  if (!v || v.layer < 1) return v.normalize();
2819
2870
  var L = v.layer;
@@ -2895,12 +2946,16 @@
2895
2946
  var V = V0.clone();
2896
2947
  var i = 0;
2897
2948
  var guard = 0;
2898
- while (i < iters) {
2899
- if (++guard > 200) return Q._applyOrdinalRows(V, beta, iters - i);
2949
+ // a fractional argument (yCnt - 1) still means a whole number of
2950
+ // applications, and the rows must carry INTEGER counts — ceil keeps the
2951
+ // step consistent with the expanded path (count = ceil(y)-2)
2952
+ var total = Math.ceil(iters);
2953
+ while (i < total) {
2954
+ if (++guard > 200) return Q._applyOrdinalRows(V, beta, total - i);
2900
2955
  var vCnt = metaFiniteCount(V);
2901
2956
  if (!(vCnt <= MAX_SAFE_INTEGER)) {
2902
2957
  // V is huge: every further application adds one β-row → fast-forward
2903
- return Q._applyOrdinalRows(V, beta, iters - i);
2958
+ return Q._applyOrdinalRows(V, beta, total - i);
2904
2959
  }
2905
2960
  V = Q._ordinalHyperop(x, V, beta, (depth || 0) + 1);
2906
2961
  i++;
@@ -2975,13 +3030,12 @@
2975
3030
  for (var bi = 2; bi < pred.length; bi++) if ((pred[bi] || 0) > 0) bigLevel = true;
2976
3031
  if (xOkS && bigLevel && ym <= 100000) {
2977
3032
  // successor rule written in the EXPANDED form (the same generator the
2978
- // integer arguments use): x{α}(m+f) = x{α-1}^m(x^f) means the α-1 row
2979
- // carries m applications — ceil(y)-2 = m-1 — and the cascade below it
2980
- // takes its first fundamental sequence at the fractional start value
2981
- // x^f, which is what interpolates the cascade depth between the two
2982
- // neighbouring integers (exactly what the finite levels do: 10{3}2.1
2983
- // starts from 10^0.1). The base is x{x^f}x when that descent is the
2984
- // ω one (ω+1 levels), x{x}x otherwise.
3033
+ // integer arguments use): the α-1 row carries the m applications as an
3034
+ // integer count ceil(y)-2 = m-1, and the fraction lives in the cascade
3035
+ // depth — the first fundamental sequence is taken at the fractional
3036
+ // start value x^f (x{α}(m+f) = x{α-1}^m(x^f) — exactly what the finite
3037
+ // levels do: 10{3}2.1 starts from 10^0.1). Whatever fraction is left
3038
+ // over lands in the base, i.e. in array[0][0].
2985
3039
  return Q._expandedHyperop(x, new MetaNum(ym + 1), cf0,
2986
3040
  Math.pow(xnfS, Number((yFracNum - ym).toPrecision(15))));
2987
3041
  }
@@ -3057,14 +3111,19 @@
3057
3111
  // into the base x and every row carries x-2 — including for 100 < y ≤ MSI
3058
3112
  // (h20(10,1000) stays an expanded cascade, not a one-row marker).
3059
3113
  // ---------------------------------------------------------------------------
3060
- // `fsOpd` is the operand of the FIRST fundamental-sequence step. The default
3061
- // is the base x; the fractional successor rule passes the fractional start
3062
- // value x^f instead (x{α}(m+f) = x{α-1}^m(x^f)), which is what interpolates the
3063
- // cascade depth between two integers. baseIdx (returned as `.baseIdx`) is the
3064
- // index used by the last descent — the finite level the cascade bottoms out at.
3114
+ // Only array[0][0] (the base's value slot) may ever be non-integer — the same
3115
+ // contract as arrow(): every row count and every row coefficient is an integer.
3116
+ // A fractional argument therefore enters in two integer-safe places:
3117
+ // - the outer count is `yn - 2` with yn = ceil(y) (an integer);
3118
+ // - the rest of the fraction sits in the CASCADE DEPTH: the first
3119
+ // fundamental sequence is taken at the fractional start value x^f
3120
+ // (x{α}(m+f) = x{α-1}^m(x^f)), and any fractional constant term left over
3121
+ // is carried into the base's finite level index (x{10.16}x), so it ends up
3122
+ // as the fractional array[0][0] exactly like arrow() does.
3123
+ // `fsOpd` is that fractional start value; `.baseIdx` returns the base index.
3065
3124
  Q._cascadeRows = function (xn, cf, yn, budget, fsOpd) {
3066
3125
  var rows = [];
3067
- if (!(budget >= 1)) return { rows: rows, baseIdx: xn };
3126
+ if (!(budget >= 1)) return rows;
3068
3127
  var cfs = trimCoeffs((cf || []).slice());
3069
3128
  var opd = Math.min(yn, MAX_SAFE_INTEGER);
3070
3129
  var first = (cfs[0] || 0) > 0; // successor: the outer count is y-2
@@ -3077,10 +3136,8 @@
3077
3136
  if ((cfs[0] || 0) > 0) {
3078
3137
  var mRaw = cfs[0];
3079
3138
  var m = Math.floor(mRaw);
3080
- // a fractional constant term (from a fundamental sequence taken at a
3081
- // fractional index) is not a valid CNF coefficient — keep the integer
3082
- // part as rows and carry the remainder into the base's finite level
3083
- // index (x{10.16}x), which is exactly how the ω level interpolates
3139
+ // a fractional constant term is not a valid CNF coefficient: keep the
3140
+ // integer part as rows and carry the remainder to the base
3084
3141
  var mFr = Number((mRaw - m).toPrecision(15));
3085
3142
  if (mFr > 1e-9) fracRem = mFr;
3086
3143
  var beta = trimCoeffs(cfs.slice());
@@ -3091,13 +3148,15 @@
3091
3148
  var j = m - 1 - s; // rows β+m-1 … β
3092
3149
  var cnt = (first ? opd : xn) - 2;
3093
3150
  first = false;
3094
- if (cnt < 1) continue;
3151
+ if (cnt < 1) continue; // no application to record
3095
3152
  if (cnt > MAX_SAFE_INTEGER) cnt = MAX_SAFE_INTEGER;
3096
3153
  var ord = beta.slice();
3097
3154
  if (j > 0) ord[0] = (ord[0] || 0) + j; // β + j
3098
3155
  ord = trimCoeffs(ord);
3099
3156
  if (!coeffsHaveOmegaPart(ord)) continue; // finite: lives in r0
3100
- rows.push([cnt].concat(ord));
3157
+ var row = [snapInt(cnt)];
3158
+ for (var oi = 0; oi < ord.length; oi++) row.push(snapInt(ord[oi]));
3159
+ rows.push(row);
3101
3160
  }
3102
3161
  cfs = beta; // continue below β
3103
3162
  opd = Math.min(xn, MAX_SAFE_INTEGER); // everything below the top
@@ -3127,7 +3186,9 @@
3127
3186
  Q._expandedHyperop = function (x, y, cf, fsOpd) {
3128
3187
  var maxRows = MetaNum.maxRows;
3129
3188
  var xn = Math.floor(metaFiniteCount(x));
3130
- var yn = Math.floor(metaFiniteCount(y));
3189
+ // ceil: the outer count must stay an integer (only array[0][0] may be
3190
+ // fractional), so the m applications of x{α}(m+f) give ceil(y)-2 = m-1
3191
+ var yn = Math.ceil(metaFiniteCount(y));
3131
3192
  var budget = maxRows - 1; // ordinal rows the array holds
3132
3193
  var desc = Q._cascadeRows(xn, cf, yn, budget + 1, fsOpd); // +1 detects truncation
3133
3194
  var truncated = desc.length > budget;
@@ -3153,6 +3214,28 @@
3153
3214
  return result.normalize();
3154
3215
  };
3155
3216
 
3217
+ // Floating-point residue: 2.1e-12 left where the exact value is an integer.
3218
+ // Only array[0][0] may be fractional, so snap everything else.
3219
+ function snapInt(v) {
3220
+ if (!isFinite(v)) return v;
3221
+ var r = Math.round(v);
3222
+ return Math.abs(v - r) < 1e-9 ? r : v;
3223
+ }
3224
+
3225
+ // Does any entry outside array[0][0] carry a fractional part?
3226
+ function hasFractionOutsideR00(v) {
3227
+ if (!v || !v.array) return false;
3228
+ for (var i = 0; i < v.array.length; i++) {
3229
+ var row = v.array[i];
3230
+ for (var j = 0; j < row.length; j++) {
3231
+ if (i === 0 && j === 0) continue;
3232
+ var c = row[j];
3233
+ if (typeof c === "number" && isFinite(c) && c !== Math.floor(c)) return true;
3234
+ }
3235
+ }
3236
+ return false;
3237
+ }
3238
+
3156
3239
  // Any coefficient with a non-zero fractional part?
3157
3240
  function coeffsHaveFraction(coeffs) {
3158
3241
  for (var i = 0; i < coeffs.length; i++) {
@@ -3667,6 +3750,17 @@
3667
3750
  cfw.push(cfac);
3668
3751
  return Q._hyperopFromOrdinal(x, x, cfw);
3669
3752
  }
3753
+ // marker form: ω^m·(x^f) — the count must stay an integer, so write the
3754
+ // fractional part out one level down: ω^m·floor(c) + ω^(m-1)·(x·frac),
3755
+ // the same resolution the CNF levels use
3756
+ if (mf >= MetaNum.maxCols) {
3757
+ var cfFl = Math.floor(cfac), cfFr = cfac - cfFl;
3758
+ var mkRows = [];
3759
+ if (cfFl >= 1) mkRows.push([cfFl, mf]);
3760
+ if (cfFr > 1e-9 && mf >= 2) mkRows.push([Math.max(1, Math.round(xnf * cfFr)), mf - 1]);
3761
+ if (mkRows.length === 0) mkRows.push([1, mf]);
3762
+ return Q._layerMarker([10], 1, mkRows);
3763
+ }
3670
3764
  return Q._layerMarker([10], 1, [[cfac, mf]]);
3671
3765
  }
3672
3766
  // ordinal / out-of-range operand: y plus one ω^ω marker row
@@ -4118,7 +4212,13 @@
4118
4212
  if (yc <= MAX_SAFE_INTEGER) {
4119
4213
  var m = Math.max(2, Math.floor(yc));
4120
4214
  if (m > MAX_SAFE_INTEGER) m = MAX_SAFE_INTEGER;
4121
- return Q._layerMarker([10], m, [[1, 1]]);
4215
+ // v2.0.2: a fractional height (hardy of anything between 10^^m and
4216
+ // 10^^(m+1)) interpolates through the base argument 10+f instead of being
4217
+ // flat across the whole range — and only array[0][0] stays fractional
4218
+ var marker = Q._layerMarker([10], m, [[1, 1]]);
4219
+ var mf = Number((yc - Math.floor(yc)).toPrecision(15));
4220
+ if (isFinite(mf) && mf > 0) marker.array[0][0] = 10 + mf; // stays in array[0][0]
4221
+ return marker;
4122
4222
  }
4123
4223
  // ordinal / out-of-range operand: ε₀ caps the library → the MSI ω-tower
4124
4224
  return Q._layerMarker([10], MAX_SAFE_INTEGER, [[1, 1]]);
@@ -4937,6 +5037,24 @@
4937
5037
  return x;
4938
5038
  }
4939
5039
 
5040
+ // v2.0.2: "1e10+0.5" / "1e10+11" / "1e16+1e13" — the digit paths (hardy)
5041
+ // need the exact decimal value and the plain float parse reads 0 here.
5042
+ // Split the sum and add the parts exactly; the '+' must not be the e+
5043
+ // exponent marker ("1e+21" keeps its old parsing).
5044
+ if (s.indexOf('+') > 0) {
5045
+ var sumParts = s.split('+');
5046
+ if (sumParts.length === 2 && sumParts[0] !== '' && sumParts[1] !== '' &&
5047
+ !/[eE]$/.test(sumParts[0]) && !/[eE]$/.test(sumParts[1])) {
5048
+ var sumA = Q.fromString(sumParts[0].trim());
5049
+ var sumB = Q.fromString(sumParts[1].trim());
5050
+ if (!sumA.isNaN() && !sumB.isNaN()) {
5051
+ var sumV = sumA.add(sumB);
5052
+ if (negateIt) sumV.sign = -sumV.sign;
5053
+ return sumV;
5054
+ }
5055
+ }
5056
+ }
5057
+
4940
5058
  var layerMatch = s.match(/^\u03C9\^(\d+)\s*/);
4941
5059
  if (layerMatch) {
4942
5060
  x.layer = parseInt(layerMatch[1], 10);
@@ -5807,6 +5925,19 @@
5807
5925
  n = nWf;
5808
5926
  continue;
5809
5927
  }
5928
+ if (j >= c.length) return n; // no positive term left (safety net)
5929
+ // A coefficient can turn FRACTIONAL because the fundamental-sequence step
5930
+ // writes the running base n — and n is 10+f for a fractional hardy input
5931
+ // (hardy(1000.5)). For 0 < c_j < 1 the "-1" step would go negative and
5932
+ // leave no positive term at all, so take the PARTIAL step instead:
5933
+ // ω^j·f contributes ω^(j-1)·(n·f) (continuous — f→1 is the full
5934
+ // ω^(j-1)·n step of the integer recursion, f→0 contributes nothing)
5935
+ var cjN = c[j].toNumber();
5936
+ if (isFinite(cjN) && cjN > 0 && cjN < 1 && j >= 2) {
5937
+ c[j] = MetaNum.ZERO.clone();
5938
+ c[j - 1] = n.mul(new MetaNum(Number(cjN.toPrecision(15))));
5939
+ continue;
5940
+ }
5810
5941
  if (c[j].gt(HARDY_EXACT_BOUND)) { // engine collapse
5811
5942
  // H_{β + ω^j·c}(n) ≈ H_β(2{c}j) — evaluate with the OLD c[j]
5812
5943
  var nCol = new MetaNum(2).arrow(j)(c[j]);
@@ -5825,11 +5956,124 @@
5825
5956
  return n;
5826
5957
  };
5827
5958
 
5959
+ // H_{ω^k}(n) for the from-below base of hardy (n ≥ 1e10).
5960
+ // The exact expansion writes a tower of level k-1 — H_{ω^10}(10) =
5961
+ // 10{9}(11…21), H_{ω^20}(20) = 10{19}(21…22) — so array[0] holds k entries
5962
+ // and the step-by-step expansion only fits while k ≤ maxCols. Above that
5963
+ // the running base turns structured, the coefficients the limit steps write
5964
+ // from it turn structured too, and every later comparison / collapse becomes
5965
+ // meaningless: hardy(1e10+11) (k = n1 = 22) collapsed to [[1],[2,20]] — a
5966
+ // destroyed base with a bogus row — and hardy(1e16+1e13) (k = 28) likewise.
5967
+ // There the from-below value is taken from the engine instead: 10{k-1}(n+1)
5968
+ // is exactly the lower bound the exact expansion stays strictly above, so
5969
+ // hardy stays monotone and keeps its "strictly below the engine" property.
5970
+ Q._hardyOmegaPower = function (n1) {
5971
+ var n1Num = (n1.layer === 0 && n1.array.length === 1 && n1.array[0].length === 1) ? n1.toNumber() : Infinity;
5972
+ if (isFinite(n1Num) && n1Num >= 2) {
5973
+ var kFit = Math.floor(n1Num);
5974
+ if (kFit <= MetaNum.maxCols + 1) {
5975
+ // exact expansion — a fractional base (hardy("1e10+0.5"), n = 10+f)
5976
+ // flows through the fundamental-sequence steps (the partial-step rule
5977
+ // keeps the coefficients sane) and collapses into ONE plain row: the
5978
+ // fractional hyper-operation result, between hardy(1e10) and
5979
+ // hardy(1e10+1)
5980
+ var ec = [];
5981
+ for (var zi = 0; zi < kFit; zi++) ec.push(0);
5982
+ ec.push(1);
5983
+ return Q._hardyH(ec, n1);
5984
+ }
5985
+ // n1 > maxCols+1: the exact tower [c0, (n1-1)×(n1-2)] no longer fits the
5986
+ // array (22 entries for n1 = 22, maxCols = 20). Keep the TRUNCATED
5987
+ // cascade instead of the engine value 10{n1-1}(n1+1): the tower level
5988
+ // n1-1 over the definitional base — hardy("1e10+11") =
5989
+ // [3086.036…, 21×19] (the user-visible [非整数, 21, 21, …, 21] shape),
5990
+ // strictly above hardy("1e10+10")'s exact [6313063, 19×18] (the level 21
5991
+ // dominates the level 19) and still far below the matching engine
5992
+ // ordinal op 10{ω^ω+ω+1}10.
5993
+ var lv = Math.floor(n1Num) - 1;
5994
+ var depth = Math.min(Math.floor(n1Num) - 2, MetaNum.maxCols - 1);
5995
+ var r0 = Q._hardyBaseR0();
5996
+ var arr = [r0[0]];
5997
+ for (var di = 0; di < depth; di++) arr.push(lv);
5998
+ var out = new MetaNum(0);
5999
+ out.array = [arr];
6000
+ return out.normalize();
6001
+ }
6002
+ // structured / fractional operand: one ω-diagonal row (engine convention)
6003
+ return Q._applyOrdinalRows(n1, [0, 1], 1);
6004
+ };
6005
+
6006
+ // Decimal digit string of a plain number stored as r0 = [v, 1] (= 10^v),
6007
+ // or null when the value is not in that form / has no finite exponent.
6008
+ // Only an actual POWER TOWER is excluded: 10^^k has the same r0 shape but
6009
+ // v ≥ 1e10, so "1e100000" (= 10^100000, v = 100000) is a plain number and
6010
+ // keeps the ordinary digit path — the old guard rejected exponents above
6011
+ // 1e5 and pushed hardy("1e100000") into the tower branch (layer 1).
6012
+ Q._hardyDigitsOfPowForm = function (r0) {
6013
+ if (!r0 || r0.length !== 2 || r0[1] !== 1 || !isFinite(r0[0])) return null;
6014
+ if (r0[0] >= 1e10) return null; // power tower → slog branch
6015
+ var exN = Math.floor(r0[0]);
6016
+ if (exN < 0 || exN > 1000000) return null; // digit string budget
6017
+ var mantN = Math.pow(10, r0[0] - exN);
6018
+ if (!isFinite(mantN)) return null;
6019
+ // the exponent is stored with ~15 significant digits, so the reconstructed
6020
+ // mantissa carries a rounding tail — 2e1000 is stored as 10^1000.301029995664
6021
+ // and 10^0.301029995664 = 1.9999999999999…, which would spell the digits
6022
+ // "19999…9" instead of "2000…0". Round the mantissa to the digits the
6023
+ // exponent can actually hold before spelling it out.
6024
+ if (mantN > 0) mantN = Number(mantN.toPrecision(12));
6025
+ if (mantN >= 10 - 1e-9) { mantN /= 10; exN += 1; }
6026
+ var digN = String(mantN).replace('.', '');
6027
+ var zeroN = exN - (digN.length - 1);
6028
+ if (zeroN < 0) return null;
6029
+ return digN + '0'.repeat(zeroN);
6030
+ };
6031
+
6032
+ // r0 of the definitional from-below base H_{ω^10}(10) = 10{9}(11…21) — the
6033
+ // base every hardy(n ≥ 1e10) value is built on.
6034
+ Q._hardyBaseR0 = function () {
6035
+ return Q._hardyOmegaPower(MetaNum.TEN.clone()).array[0].slice();
6036
+ };
6037
+
6038
+ // issues.md truncation marker: once the ordinal rows overflow, the engine
6039
+ // collapses the base to [10]. hardy keeps its definitional base instead —
6040
+ // every level above it is carried by the ordinal rows, so the truncation
6041
+ // loses nothing but the unnameable low levels, and the value stays bigger
6042
+ // than the marker base (hardy is monotone across the truncation point).
6043
+ Q._hardyKeepBase = function (v) {
6044
+ var r0 = v.array[0];
6045
+ if (r0 && r0.length === 1 && r0[0] === 10) v.array[0] = Q._hardyBaseR0();
6046
+ return v;
6047
+ };
6048
+
5828
6049
  // MetaNum.hardy(n): the Hardy level of n.
5829
6050
  // n < 10 → 10 + n; otherwise the decimal digits of n become the CNF
5830
6051
  // coefficients of an ordinal α (hardy(1234) = H_{ω³+ω²·2+ω·3+4}(10)) and
5831
6052
  // the result is H_α(10).
5832
6053
  Q.hardy = function (n) {
6054
+ // A plain JS number / numeric string keeps its own decimal expansion: from
6055
+ // 1e16 on the library stores the value as 10^v (r0 = [v,1]) and the way
6056
+ // back through the double loses the low digits — hardy(1e16+1e13) =
6057
+ // hardy(10010000000000000) reads back as 10010000000000014, so the digit
6058
+ // path would take 14 instead of 1e13 as the "rest" of the ordinal.
6059
+ var rawNum = (typeof n === 'number') ? n
6060
+ : (typeof n === 'string' ? Number(n) : null);
6061
+ // v2.0.2: "1e10+0.5" / "1e10+11" / "1e16+1e13" — the digit path needs the
6062
+ // exact decimal value, and Number('1e10+0.5') is NaN (the old path read 0 →
6063
+ // hardy(0) = 10 → the [10] base). Split the sum and add the parts exactly.
6064
+ if (typeof n === 'string' && n.indexOf('+') > 0) {
6065
+ var plusParts = n.split('+');
6066
+ if (plusParts.length === 2 && plusParts[0] !== '' && plusParts[1] !== '' &&
6067
+ !/[eE]$/.test(plusParts[0]) && !/[eE]$/.test(plusParts[1])) {
6068
+ var pvA = new MetaNum(plusParts[0].trim());
6069
+ var pvB = new MetaNum(plusParts[1].trim());
6070
+ if (!pvA.isNaN() && !pvB.isNaN()) {
6071
+ n = pvA.add(pvB);
6072
+ rawNum = null;
6073
+ }
6074
+ }
6075
+ }
6076
+ if (rawNum !== null && !isFinite(rawNum)) rawNum = null;
5833
6077
  n = new MetaNum(n);
5834
6078
  if (n.sign !== 1) {
5835
6079
  throw Error(metaNumError + 'hardy: n must be a non-negative integer');
@@ -5841,9 +6085,23 @@
5841
6085
  // hardy(10^^MSI) = the MetaNum limit exactly (slog(10^^MSI) = MSI).
5842
6086
  // Ordinal-row / ε-layer values sit at their own Hardy position
5843
6087
  // (H_{ω^β}(10) = 10{β}10) and map to themselves.
5844
- var num = (n.layer === 0 && n.array.length === 1) ? n.toNumber() : Infinity;
6088
+ var num = (rawNum !== null) ? rawNum
6089
+ : ((n.layer === 0 && n.array.length === 1) ? n.toNumber() : Infinity);
6090
+ // r0 = [v, 1] means 10^v — the plain-number form the library uses once a
6091
+ // value leaves the plain-integer range. Read the decimal expansion off
6092
+ // that mantissa/exponent pair when the double itself is unavailable
6093
+ // (hardy("1.8e308") — beyond Number.MAX_VALUE).
6094
+ var hStr = (rawNum === null && n.layer === 0 && n.array.length === 1)
6095
+ ? Q._hardyDigitsOfPowForm(n.array[0]) : null;
5845
6096
  if (!isFinite(num)) {
5846
6097
  if (n.layer === 0 && n.array.length === 1) {
6098
+ // v2.0.2: a PLAIN number that merely exceeds the double range (hardy
6099
+ // ("1.8e308") — 1.8e308 > Number.MAX_VALUE) is not a power tower, so it
6100
+ // must not fall into the tower branch: read its decimal expansion and
6101
+ // keep the ordinary digit path (hardy(1.8e308) stays layer 0).
6102
+ // (A tower 10^^k has the same shape but v ≥ 1e10, so the size guard
6103
+ // below keeps towers on the slog branch.)
6104
+ if (hStr === null) {
5847
6105
  var hVal = n.slog();
5848
6106
  // a clean power tower shadows to ω^ω^…^ω (k ω's); slog(10^^k) = [[k]]
5849
6107
  // (a plain single number — NOT the structured slog of, say, G600)
@@ -5851,20 +6109,82 @@
5851
6109
  var hNum = hVal.toNumber();
5852
6110
  if (isFinite(hNum) && hNum >= 2 && hNum <= Number.MAX_SAFE_INTEGER) {
5853
6111
  // k ≤ MSI: the tower fits the engine limit (f_ε₀); k > MSI is
5854
- // beyond ε₀ and the Hardy hierarchy is undefined there → Infinity
5855
- return MetaNum.TEN.epsilonate(hNum).normalize();
6112
+ // beyond ε₀ and the Hardy hierarchy is undefined there → Infinity.
6113
+ // The ordinal is read off the value itself: V = 10^W gives
6114
+ // α = ω^ord(W), so the result is the ordinary cascade on the
6115
+ // from-below base while the tower height still leaves a readable
6116
+ // exponent (k ≤ 3 — hardy(ee10) = H_{ω^(ω^ω)}(10) = the ω^ω
6117
+ // cascade, layer 0 like iterate(10), not a layer-2 marker).
6118
+ // Above that the level no longer fits into ordinal rows and the
6119
+ // value becomes a layer marker whose layer is ceil(k) - 3:
6120
+ // ee10 < 10^(1e10+1) < ee20 … eee10 → layer 1
6121
+ // eee20 … eeee10 → layer 2, and so on
6122
+ var r0T = n.array[0];
6123
+ // v2.0.2 (issues): clean power towers — EVERY extra 10^ level in
6124
+ // the input raises hardy's layer by ONE, the ordinal rows stay
6125
+ // those of the innermost readable expansion:
6126
+ // hardy("1e308") = the layer-0 digit-path cascade (…[8,6,0,3],[8,7,0,3])
6127
+ // hardy("e1e308") = the same rows at layer 1
6128
+ // hardy("ee1e308") = the same rows at layer 2, and so on.
6129
+ // The stored tower r0 = [v, k] is (k-1) further 10^ levels over
6130
+ // 10^v; a layer-L input adds L more levels on top.
6131
+ if (r0T && r0T.length === 2 && r0T[1] >= 1 &&
6132
+ r0T[1] === Math.floor(r0T[1]) &&
6133
+ isFinite(r0T[0]) && r0T[0] >= 10 &&
6134
+ (r0T[1] >= 2 || r0T[0] >= 1e10)) {
6135
+ var towerInner;
6136
+ if (r0T[1] >= 2) {
6137
+ // peel (k-1) levels at once: hardy = layerUp^(k-1)(hardy(10^v))
6138
+ var towerBase = new MetaNum(0);
6139
+ towerBase.sign = 1;
6140
+ towerBase.layer = 0;
6141
+ towerBase.array = [[r0T[0], 1]];
6142
+ towerInner = Q.hardy(towerBase); // hardy(10^v), layer 0/1
6143
+ return Q._rawLayerMarker(towerInner.array[0],
6144
+ n.layer + (r0T[1] - 1) + towerInner.layer,
6145
+ towerInner.array.slice(1));
6146
+ }
6147
+ // single 10^ level over a readable exponent: hardy(10^v) =
6148
+ // layerUp(hardy(v))
6149
+ towerInner = Q.hardy(r0T[0]);
6150
+ return Q._rawLayerMarker(towerInner.array[0], n.layer + 1,
6151
+ towerInner.array.slice(1));
6152
+ }
6153
+ if (hNum <= 3 && r0T && r0T.length === 2 && r0T[1] === 1 &&
6154
+ isFinite(r0T[0]) && r0T[0] >= 10) {
6155
+ return Q._hardyLeading(r0T[0], 1, MetaNum.TEN.clone());
6156
+ }
6157
+ var kc = Math.ceil(hNum - 1e-9);
6158
+ // position inside the band (kc-1, kc]: monotone in the tower height,
6159
+ // kept just below 1 so the layer does not jump at the band edge
6160
+ var kFrac = Math.min(Math.max(hNum - (kc - 1), 0), 0.999999);
6161
+ if (kc <= 4) {
6162
+ // layer 1: 10{ω^y}10 = L1 [[base],[1,y,1]] with y = ω + t, t
6163
+ // growing with the tower height so the band stays monotone —
6164
+ // the base is hardy's definitional from-below base, not the
6165
+ // bare [10] marker (issues: a truncated base keeps
6166
+ // [3086.036,9×8])
6167
+ var tv = Math.max(1, Math.round((hNum - 3) * 1e6));
6168
+ return Q._layerMarker(Q._hardyBaseR0(), 1, [[1, tv, 1]]);
6169
+ }
6170
+ // layer kc-3 ≥ 2: epsilonate(layer+1) carries the fractional tower
6171
+ // height in its base, so the band stays monotone as well
6172
+ // (beyond ~1e15 the fraction is not representable in the exponent)
6173
+ return MetaNum.TEN.epsilonate(
6174
+ kc > 1e15 ? (kc - 2) : (kc - 2 + kFrac)).normalize();
5856
6175
  }
5857
6176
  }
5858
6177
  // layer-0 value beyond a clean 10^^k with k ≤ MSI: finite
5859
6178
  // hyperoperations above tetration (G600, 3{9}3, …) or a tower taller
5860
6179
  // than 10^^MSI exceed the library's ε₀ ceiling → Infinity
5861
6180
  return new MetaNum(Infinity);
6181
+ }
5862
6182
  }
5863
6183
  // ordinal-row / ε-layer / letter-chain values sit at their own Hardy
5864
6184
  // position (H_{ω^β}(10) = 10{β}10): map to themselves
5865
- return n.clone().normalize();
6185
+ if (hStr === null) return n.clone().normalize();
5866
6186
  }
5867
- var s = String(num);
6187
+ var s = (hStr !== null) ? hStr : String(num);
5868
6188
  // > 1e20 arrives in scientific notation ('1e+21') — expand to the exact
5869
6189
  // decimal digits so the digit-reading stays monotone (issues.md v2.1:
5870
6190
  // hardy must support > 1e15 inputs)
@@ -5874,6 +6194,17 @@
5874
6194
  var eZeros = Number(eMatch[3]) - eFrac.length;
5875
6195
  if (eZeros > 0) s = eMatch[1] + eFrac + '0'.repeat(eZeros);
5876
6196
  }
6197
+ // v2.0.2: fractional argument. The ordinal is read from the INTEGER part's
6198
+ // digits while the base argument becomes 10+f, so H stays continuous in n:
6199
+ // hardy(10.38) = H_ω(10.38) = 10.38·2 = 20.76
6200
+ // hardy(100.1) = H_{ω²}(10.1) = 10.1·2^10.1 = 11084.709858935355
6201
+ var hFrac = 0;
6202
+ var hDot = s.indexOf('.');
6203
+ if (hDot >= 0) {
6204
+ hFrac = Number('0.' + s.slice(hDot + 1));
6205
+ s = s.slice(0, hDot);
6206
+ }
6207
+ var hArg = hFrac > 0 ? new MetaNum(10 + hFrac) : MetaNum.TEN.clone();
5877
6208
  if (s.length >= 11) {
5878
6209
  // n ≥ 1e10 (issues.md v2.0): the ordinal is built per definition, then
5879
6210
  // evaluated from below on the engine's own representation:
@@ -5894,41 +6225,62 @@
5894
6225
  var kExp = s.length - 1;
5895
6226
  var dk = s.charCodeAt(0) - 48;
5896
6227
  var restNum = Number(s.slice(1));
5897
- var n1 = MetaNum.TEN.clone();
5898
- if (restNum > 0) n1 = Q.hardy(restNum);
5899
- // from-below base: H_{ω^n1}(n1) — exact for small finite n1, one
5900
- // ω-diagonal row (engine convention) for huge n1
5901
- var base;
5902
- var n1Num = (n1.array.length === 1 && n1.layer === 0) ? n1.toNumber() : Infinity;
5903
- if (isFinite(n1Num) && n1Num === Math.floor(n1Num) && n1Num >= 2 && n1Num <= 100) {
5904
- var ec = [];
5905
- for (var zi = 0; zi < n1Num; zi++) ec.push(0);
5906
- ec.push(1);
5907
- base = Q._hardyH(ec, n1);
5908
- } else {
5909
- base = Q._applyOrdinalRows(n1, [0, 1], 1);
5910
- }
6228
+ var n1 = hArg.clone();
6229
+ // the fractional part flows into the rest part too: hardy("1e10+1.5")
6230
+ // = H_{ω^10}(hardy(1.5)) = H_{ω^10}(11.5) — dropping the fraction here
6231
+ // made every 1e10+k.f input behave like 1e10+k
6232
+ if (restNum > 0) n1 = Q.hardy(restNum + hFrac);
6233
+ return Q._hardyLeading(kExp, dk, n1);
6234
+ }
6235
+ if (num < 10) return new MetaNum(10 + num);
6236
+ var coeffs = [];
6237
+ for (var i = s.length - 1; i >= 0; i--) coeffs.push(s.charCodeAt(i) - 48);
6238
+ return Q._hardyH(coeffs, hArg);
6239
+ };
6240
+
6241
+ // The leading term ω^ord(kExp)·dk of hardy's ordinal, evaluated from below
6242
+ // on the already-computed lower part n1 = H_ord(rest)(10).
6243
+ Q._hardyLeading = function (kExp, dk, n1) {
6244
+ // a plain operand still has a single plain number as its whole array[0]
6245
+ var nPlain = (n1.layer === 0 && n1.array.length === 1 && n1.array[0].length === 1);
6246
+ var n1Num = nPlain ? n1.toNumber() : Infinity;
5911
6247
  if (kExp === 10) {
5912
- return Q._applyOrdinalRows(base, [0, 1], dk - 1).normalize();
5913
- }
5914
- // kExp ≥ 11 (ord = ω+c): mirror the engine's own ordinal rows for
5915
- // 10{ω+c}(9+dk) onto the from-below base — hardy(1e11) keeps
5916
- // expande(10,10)'s row structure with the strictly smaller
5917
- // definitional base, so hardy(1e11) < 10{ω+1}10 (issues.md)
6248
+ // H_{ω^ω·dk}(n1): the first ω^ω-segment is H_{ω^n1}(n1) (from below),
6249
+ // every further one adds one ω-row
6250
+ return Q._hardyKeepBase(
6251
+ Q._applyOrdinalRows(Q._hardyOmegaPower(n1), [0, 1], dk - 1)).normalize();
6252
+ }
6253
+ // kExp ≥ 11 (ord = ω+c): β = ord(kExp) and the leading term ω^β·dk is dk
6254
+ // APPLICATIONS of H_{ω^β}, one after the other on the running value:
6255
+ // hardy(1.1e11) = H_{ω^(ω+1)+ω^ω}(10) = H_{ω^(ω+1)}(H_{ω^ω}(10))
6256
+ // = [3086.036,9×8] [1,1,1] (one row per application)
6257
+ // hardy(2e11) = H_{ω^(ω+1)·2}(10) = H_{ω^(ω+1)}(H_{ω^(ω+1)}(10))
6258
+ // = [3086.036,9×8] [8,0,1] [1,1,1]
6259
+ // hardy(1e16+1e13) = H_{ω^(ω+6)}(H_{ω^(ω+3)}(10)) → … [1,6,1]
6260
+ // so an application is a row [1, β] — never a bump of the ω-row count
6261
+ // ([9,0,1] / [16,0,1] conflated dk with the rest-part). The FIRST
6262
+ // application on a plain operand is still expanded from below: the base
6263
+ // H_{ω^n1}(n1) plus the cascade of 10{β}10 (hardy(1e11) = [3086.036,9×8]
6264
+ // [8,0,1], strictly below 10{ω+1}10 — issues.md).
5918
6265
  var ks = String(kExp);
5919
6266
  var ordCoeffs = [];
5920
6267
  for (var oi = ks.length - 1; oi >= 0; oi--) ordCoeffs.push(ks.charCodeAt(oi) - 48);
5921
- var mir = Q._hyperopFromOrdinalRaw(MetaNum.TEN.clone(), new MetaNum(9 + dk), ordCoeffs);
5922
- var out = base.clone();
5923
- for (var ri = 1; ri < mir.array.length; ri++) {
5924
- out = Q._applyOrdinalRows(out, mir.array[ri].slice(1), mir.array[ri][0]);
6268
+ var out, extra;
6269
+ if (nPlain && isFinite(n1Num) && n1Num >= 2) {
6270
+ out = Q._hardyOmegaPower(n1);
6271
+ var mir = Q._hyperopFromOrdinalRaw(MetaNum.TEN.clone(), MetaNum.TEN.clone(), ordCoeffs);
6272
+ for (var ri = 1; ri < mir.array.length; ri++) {
6273
+ out = Q._applyOrdinalRows(out, mir.array[ri].slice(1), mir.array[ri][0]);
6274
+ }
6275
+ extra = dk - 1;
6276
+ } else {
6277
+ // structured operand: H_{ω^β} has no room left to expand into, so each
6278
+ // application is one more row [1, β]
6279
+ out = n1.clone();
6280
+ extra = dk;
5925
6281
  }
5926
- return out.normalize();
5927
- }
5928
- if (num < 10) return new MetaNum(10 + num);
5929
- var coeffs = [];
5930
- for (var i = s.length - 1; i >= 0; i--) coeffs.push(s.charCodeAt(i) - 48);
5931
- return Q._hardyH(coeffs, MetaNum.TEN.clone());
6282
+ if (extra > 0) out = Q._applyOrdinalRows(out, ordCoeffs, extra);
6283
+ return Q._hardyKeepBase(out).normalize();
5932
6284
  };
5933
6285
 
5934
6286
  // ==================== BEAF Array Notation ====================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metanum",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "A javascript library that handles numbers as large as f_ε₀(9e15)",
5
5
  "main": "metanum.js",
6
6
  "files": [
@@ -76,6 +76,7 @@
76
76
  <script src="./format-metanum.js"></script>
77
77
  <script>
78
78
  // test in console
79
+ // MetaNum v2.0.2
79
80
  console.log('=== MetaNum Library by dlsdl ===');
80
81
 
81
82
  </script>