eyeling 1.16.3 → 1.16.4
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 +0 -1
- package/package.json +2 -3
- package/arctifacts/README.md +0 -59
- package/arctifacts/ackermann.html +0 -678
- package/arctifacts/auroracare.html +0 -1297
- package/arctifacts/bike-trip.html +0 -752
- package/arctifacts/binomial-theorem.html +0 -631
- package/arctifacts/bmi.html +0 -511
- package/arctifacts/building-performance.html +0 -750
- package/arctifacts/clinical-care.html +0 -726
- package/arctifacts/collatz.html +0 -403
- package/arctifacts/complex.html +0 -321
- package/arctifacts/control-system.html +0 -482
- package/arctifacts/delfour.html +0 -849
- package/arctifacts/earthquake-epicenter.html +0 -982
- package/arctifacts/eco-route.html +0 -662
- package/arctifacts/euclid-infinitude.html +0 -564
- package/arctifacts/euler-identity.html +0 -667
- package/arctifacts/exoplanet-transit.html +0 -1000
- package/arctifacts/faltings-theorem.html +0 -1046
- package/arctifacts/fibonacci.html +0 -299
- package/arctifacts/fundamental-theorem-arithmetic.html +0 -398
- package/arctifacts/godel-numbering.html +0 -743
- package/arctifacts/gps-bike.html +0 -759
- package/arctifacts/gps-clinical-bench.html +0 -792
- package/arctifacts/graph-french.html +0 -449
- package/arctifacts/grass-molecular.html +0 -592
- package/arctifacts/group-theory.html +0 -740
- package/arctifacts/health-info.html +0 -833
- package/arctifacts/kaprekar-constant.html +0 -576
- package/arctifacts/lee.html +0 -805
- package/arctifacts/linked-lists.html +0 -502
- package/arctifacts/lldm.html +0 -612
- package/arctifacts/matrix-multiplication.html +0 -502
- package/arctifacts/matrix.html +0 -651
- package/arctifacts/newton-raphson.html +0 -944
- package/arctifacts/peano-factorial.html +0 -456
- package/arctifacts/pi.html +0 -363
- package/arctifacts/polynomial.html +0 -646
- package/arctifacts/prime.html +0 -366
- package/arctifacts/pythagorean-theorem.html +0 -468
- package/arctifacts/rest-path.html +0 -469
- package/arctifacts/roots-of-unity.html +0 -363
- package/arctifacts/turing.html +0 -409
- package/arctifacts/wind-turbines.html +0 -726
|
@@ -1,667 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
<title>Euler's Identity</title>
|
|
7
|
-
<style>
|
|
8
|
-
:root {
|
|
9
|
-
--bg: #f7f9fc;
|
|
10
|
-
--card: #ffffff;
|
|
11
|
-
--text: #0f172a;
|
|
12
|
-
--muted: #475569;
|
|
13
|
-
--accent: #2563eb;
|
|
14
|
-
--good: #16a34a;
|
|
15
|
-
--bad: #dc2626;
|
|
16
|
-
--border: #e2e8f0;
|
|
17
|
-
--chip: #eef2ff;
|
|
18
|
-
--code: #111827;
|
|
19
|
-
}
|
|
20
|
-
html,
|
|
21
|
-
body {
|
|
22
|
-
background: var(--bg);
|
|
23
|
-
color: var(--text);
|
|
24
|
-
font-family:
|
|
25
|
-
ui-sans-serif,
|
|
26
|
-
system-ui,
|
|
27
|
-
-apple-system,
|
|
28
|
-
Segoe UI,
|
|
29
|
-
Roboto,
|
|
30
|
-
Helvetica,
|
|
31
|
-
Arial,
|
|
32
|
-
'Apple Color Emoji',
|
|
33
|
-
'Segoe UI Emoji';
|
|
34
|
-
}
|
|
35
|
-
* {
|
|
36
|
-
box-sizing: border-box;
|
|
37
|
-
}
|
|
38
|
-
.container {
|
|
39
|
-
max-width: 960px;
|
|
40
|
-
margin: 24px auto;
|
|
41
|
-
padding: 0 16px;
|
|
42
|
-
}
|
|
43
|
-
header {
|
|
44
|
-
display: flex;
|
|
45
|
-
flex-direction: column;
|
|
46
|
-
gap: 8px;
|
|
47
|
-
margin-bottom: 16px;
|
|
48
|
-
}
|
|
49
|
-
h1 {
|
|
50
|
-
font-size: 1.8rem;
|
|
51
|
-
margin: 0;
|
|
52
|
-
letter-spacing: -0.02em;
|
|
53
|
-
}
|
|
54
|
-
.subtitle {
|
|
55
|
-
color: var(--muted);
|
|
56
|
-
}
|
|
57
|
-
.card {
|
|
58
|
-
background: var(--card);
|
|
59
|
-
border: 1px solid var(--border);
|
|
60
|
-
border-radius: 16px;
|
|
61
|
-
padding: 16px;
|
|
62
|
-
box-shadow: 0 6px 20px rgba(2, 6, 23, 0.05);
|
|
63
|
-
}
|
|
64
|
-
.stack {
|
|
65
|
-
display: flex;
|
|
66
|
-
flex-direction: column;
|
|
67
|
-
gap: 16px;
|
|
68
|
-
}
|
|
69
|
-
.pill {
|
|
70
|
-
display: inline-flex;
|
|
71
|
-
align-items: center;
|
|
72
|
-
gap: 8px;
|
|
73
|
-
padding: 4px 10px;
|
|
74
|
-
background: var(--chip);
|
|
75
|
-
color: #1e3a8a;
|
|
76
|
-
border-radius: 999px;
|
|
77
|
-
font-size: 12px;
|
|
78
|
-
font-weight: 600;
|
|
79
|
-
border: 1px solid #c7d2fe;
|
|
80
|
-
}
|
|
81
|
-
.row {
|
|
82
|
-
display: flex;
|
|
83
|
-
gap: 12px;
|
|
84
|
-
align-items: center;
|
|
85
|
-
min-width: 0;
|
|
86
|
-
flex-wrap: wrap;
|
|
87
|
-
}
|
|
88
|
-
input[type='number'] {
|
|
89
|
-
width: 160px;
|
|
90
|
-
padding: 10px 12px;
|
|
91
|
-
border-radius: 10px;
|
|
92
|
-
border: 1px solid var(--border);
|
|
93
|
-
background: #fbfdff;
|
|
94
|
-
}
|
|
95
|
-
button {
|
|
96
|
-
appearance: none;
|
|
97
|
-
border: none;
|
|
98
|
-
background: var(--accent);
|
|
99
|
-
color: white;
|
|
100
|
-
padding: 10px 14px;
|
|
101
|
-
border-radius: 12px;
|
|
102
|
-
font-weight: 700;
|
|
103
|
-
cursor: pointer;
|
|
104
|
-
box-shadow: 0 4px 14px rgba(37, 99, 235, 0.25);
|
|
105
|
-
}
|
|
106
|
-
button.secondary {
|
|
107
|
-
background: #0ea5e9;
|
|
108
|
-
}
|
|
109
|
-
button.ghost {
|
|
110
|
-
background: transparent;
|
|
111
|
-
color: var(--accent);
|
|
112
|
-
border: 1px solid var(--accent);
|
|
113
|
-
}
|
|
114
|
-
.muted {
|
|
115
|
-
color: var(--muted);
|
|
116
|
-
}
|
|
117
|
-
.mono {
|
|
118
|
-
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
119
|
-
color: var(--code);
|
|
120
|
-
word-break: break-word;
|
|
121
|
-
overflow-wrap: anywhere;
|
|
122
|
-
white-space: normal;
|
|
123
|
-
}
|
|
124
|
-
.kpi {
|
|
125
|
-
display: flex;
|
|
126
|
-
gap: 16px;
|
|
127
|
-
flex-wrap: wrap;
|
|
128
|
-
}
|
|
129
|
-
.kpi .card {
|
|
130
|
-
padding: 12px 14px;
|
|
131
|
-
}
|
|
132
|
-
.k {
|
|
133
|
-
font-weight: 700;
|
|
134
|
-
}
|
|
135
|
-
.v {
|
|
136
|
-
font-variant-numeric: tabular-nums;
|
|
137
|
-
word-break: break-word;
|
|
138
|
-
overflow-wrap: anywhere;
|
|
139
|
-
}
|
|
140
|
-
.list {
|
|
141
|
-
display: flex;
|
|
142
|
-
flex-direction: column;
|
|
143
|
-
gap: 12px;
|
|
144
|
-
}
|
|
145
|
-
.term {
|
|
146
|
-
padding: 10px;
|
|
147
|
-
background: #f8fafc;
|
|
148
|
-
border: 1px dashed var(--border);
|
|
149
|
-
border-radius: 12px;
|
|
150
|
-
}
|
|
151
|
-
details {
|
|
152
|
-
border: 1px solid var(--border);
|
|
153
|
-
border-radius: 12px;
|
|
154
|
-
padding: 10px 12px;
|
|
155
|
-
background: #fafcff;
|
|
156
|
-
}
|
|
157
|
-
details summary {
|
|
158
|
-
cursor: pointer;
|
|
159
|
-
font-weight: 700;
|
|
160
|
-
color: #0b3eaa;
|
|
161
|
-
}
|
|
162
|
-
.badge {
|
|
163
|
-
padding: 2px 8px;
|
|
164
|
-
border-radius: 999px;
|
|
165
|
-
font-weight: 700;
|
|
166
|
-
font-size: 12px;
|
|
167
|
-
border: 1px solid #cbd5e1;
|
|
168
|
-
background: #f1f5f9;
|
|
169
|
-
color: #0f172a;
|
|
170
|
-
}
|
|
171
|
-
.ok {
|
|
172
|
-
background: #dcfce7;
|
|
173
|
-
color: #166534;
|
|
174
|
-
border: 1px solid #86efac;
|
|
175
|
-
}
|
|
176
|
-
.fail {
|
|
177
|
-
background: #fee2e2;
|
|
178
|
-
color: #991b1b;
|
|
179
|
-
border: 1px solid #fecaca;
|
|
180
|
-
}
|
|
181
|
-
.harness {
|
|
182
|
-
border-left: 6px solid #c7d2fe;
|
|
183
|
-
}
|
|
184
|
-
.h-title {
|
|
185
|
-
display: flex;
|
|
186
|
-
align-items: center;
|
|
187
|
-
justify-content: space-between;
|
|
188
|
-
gap: 8px;
|
|
189
|
-
}
|
|
190
|
-
.small {
|
|
191
|
-
font-size: 12px;
|
|
192
|
-
}
|
|
193
|
-
code {
|
|
194
|
-
background: #f1f5f9;
|
|
195
|
-
padding: 2px 6px;
|
|
196
|
-
border-radius: 6px;
|
|
197
|
-
}
|
|
198
|
-
footer {
|
|
199
|
-
color: var(--muted);
|
|
200
|
-
font-size: 12px;
|
|
201
|
-
text-align: center;
|
|
202
|
-
margin: 16px 0 40px;
|
|
203
|
-
}
|
|
204
|
-
.divider {
|
|
205
|
-
height: 1px;
|
|
206
|
-
background: var(--border);
|
|
207
|
-
margin: -4px 0 8px;
|
|
208
|
-
}
|
|
209
|
-
svg {
|
|
210
|
-
width: 100%;
|
|
211
|
-
height: auto;
|
|
212
|
-
background: #ffffff;
|
|
213
|
-
border: 1px solid var(--border);
|
|
214
|
-
border-radius: 12px;
|
|
215
|
-
}
|
|
216
|
-
.input-grid {
|
|
217
|
-
flex-wrap: nowrap;
|
|
218
|
-
gap: 10px;
|
|
219
|
-
}
|
|
220
|
-
.field {
|
|
221
|
-
display: flex;
|
|
222
|
-
align-items: center;
|
|
223
|
-
gap: 6px;
|
|
224
|
-
}
|
|
225
|
-
input.short {
|
|
226
|
-
width: 110px;
|
|
227
|
-
padding: 6px 8px;
|
|
228
|
-
}
|
|
229
|
-
.buttons-row {
|
|
230
|
-
gap: 8px;
|
|
231
|
-
}
|
|
232
|
-
@media (max-width: 520px) {
|
|
233
|
-
.input-grid {
|
|
234
|
-
flex-wrap: wrap;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
</style>
|
|
238
|
-
</head>
|
|
239
|
-
<body>
|
|
240
|
-
<div class="container stack">
|
|
241
|
-
<header class="card stack">
|
|
242
|
-
<div class="row" style="justify-content: space-between; align-items: flex-start; width: 100%">
|
|
243
|
-
<div>
|
|
244
|
-
<h1>Euler's identity</h1>
|
|
245
|
-
</div>
|
|
246
|
-
</div>
|
|
247
|
-
<span class="badge">Problem: e^{iπ} + 1 = 0</span>
|
|
248
|
-
<p class="muted">
|
|
249
|
-
This page states Euler's identity, explains why <span class="mono">e^{iπ} = -1</span> in mathematical English,
|
|
250
|
-
illustrates it on the unit circle, and verifies it numerically with a small test harness.
|
|
251
|
-
</p>
|
|
252
|
-
</header>
|
|
253
|
-
|
|
254
|
-
<!-- SVG ILLUSTRATION -->
|
|
255
|
-
<section class="card stack">
|
|
256
|
-
<h2 style="margin: 0">Illustration</h2>
|
|
257
|
-
<div class="divider"></div>
|
|
258
|
-
<svg viewBox="0 0 600 300" role="img" aria-label="Unit circle with angle π showing e^{iπ} at (-1,0)">
|
|
259
|
-
<defs>
|
|
260
|
-
<marker
|
|
261
|
-
id="arrow"
|
|
262
|
-
markerWidth="8"
|
|
263
|
-
markerHeight="8"
|
|
264
|
-
refX="6"
|
|
265
|
-
refY="3"
|
|
266
|
-
orient="auto"
|
|
267
|
-
markerUnits="strokeWidth">
|
|
268
|
-
<path d="M0,0 L0,6 L6,3 z" fill="#0b3eaa" />
|
|
269
|
-
</marker>
|
|
270
|
-
</defs>
|
|
271
|
-
<!-- background grid -->
|
|
272
|
-
<rect x="0" y="0" width="600" height="300" fill="#fff" rx="12" />
|
|
273
|
-
<!-- axes -->
|
|
274
|
-
<g stroke="#cbd5e1" stroke-width="1">
|
|
275
|
-
<line x1="50" y1="150" x2="550" y2="150" />
|
|
276
|
-
<line x1="300" y1="20" x2="300" y2="280" />
|
|
277
|
-
</g>
|
|
278
|
-
<!-- unit circle -->
|
|
279
|
-
<circle cx="300" cy="150" r="100" fill="none" stroke="#94a3b8" stroke-width="2" />
|
|
280
|
-
<!-- angle arc π from +x to -x -->
|
|
281
|
-
<path d="M 400 150 A 100 100 0 0 1 200 150" fill="none" stroke="#0b3eaa" stroke-width="3" />
|
|
282
|
-
<text x="300" y="125" fill="#0b3eaa" text-anchor="middle" font-size="12">θ = π</text>
|
|
283
|
-
<!-- vector e^{iπ} -->
|
|
284
|
-
<line x1="300" y1="150" x2="200" y2="150" stroke="#0b3eaa" stroke-width="3" marker-end="url(#arrow)" />
|
|
285
|
-
<!-- points 1 and -1 -->
|
|
286
|
-
<circle cx="400" cy="150" r="4" fill="#22c55e" />
|
|
287
|
-
<text x="400" y="140" fill="#166534" text-anchor="middle" font-size="12">1</text>
|
|
288
|
-
<circle cx="200" cy="150" r="4" fill="#ef4444" />
|
|
289
|
-
<text x="200" y="140" fill="#991b1b" text-anchor="middle" font-size="12">−1 = e^{iπ}</text>
|
|
290
|
-
<!-- tip annotation e^{iπ}+1=0 showing cancellation -->
|
|
291
|
-
<g>
|
|
292
|
-
<line x1="200" y1="150" x2="400" y2="150" stroke="#10b981" stroke-dasharray="4 4" />
|
|
293
|
-
<text x="300" y="170" fill="#0f172a" text-anchor="middle" font-size="12">e^{iπ} + 1 → 0</text>
|
|
294
|
-
</g>
|
|
295
|
-
<!-- axis labels -->
|
|
296
|
-
<text x="555" y="160" fill="#475569" font-size="12">Re</text>
|
|
297
|
-
<text x="310" y="25" fill="#475569" font-size="12">Im</text>
|
|
298
|
-
</svg>
|
|
299
|
-
<p class="small muted">
|
|
300
|
-
The complex exponential <span class="mono">e^{iθ}</span> traces the unit circle. At
|
|
301
|
-
<span class="mono">θ=π</span> the point is <span class="mono">−1</span>, so
|
|
302
|
-
<span class="mono">e^{iπ}+1=0</span>.
|
|
303
|
-
</p>
|
|
304
|
-
</section>
|
|
305
|
-
|
|
306
|
-
<!-- INPUT -->
|
|
307
|
-
<section class="card stack" id="input-card">
|
|
308
|
-
<h2 style="margin: 0">Input</h2>
|
|
309
|
-
<div class="divider"></div>
|
|
310
|
-
<div class="row input-grid">
|
|
311
|
-
<div class="field">
|
|
312
|
-
<label class="mono" for="kInput">k (integer)</label
|
|
313
|
-
><input class="short" id="kInput" type="number" step="1" value="0" />
|
|
314
|
-
</div>
|
|
315
|
-
<div class="field">
|
|
316
|
-
<label class="mono" for="epsInput">ε (tolerance)</label
|
|
317
|
-
><input class="short" id="epsInput" type="number" step="any" value="1e-12" />
|
|
318
|
-
</div>
|
|
319
|
-
<div class="field">
|
|
320
|
-
<label class="mono" for="NInput">Series terms N</label
|
|
321
|
-
><input class="short" id="NInput" type="number" min="1" step="1" value="40" />
|
|
322
|
-
</div>
|
|
323
|
-
</div>
|
|
324
|
-
<div class="row buttons-row">
|
|
325
|
-
<button type="button" id="solve">Evaluate</button>
|
|
326
|
-
<button type="button" id="clear">Clear</button>
|
|
327
|
-
</div>
|
|
328
|
-
<p class="small muted">
|
|
329
|
-
We evaluate at <span class="mono">θ = π + 2πk</span>. <strong>N</strong> is the number of terms used in the
|
|
330
|
-
power‑series expansions for <span class="mono">cos</span> and <span class="mono">sin</span>; higher
|
|
331
|
-
<strong>N</strong> gives a tighter approximation (30–50 is typically plenty after angle reduction to
|
|
332
|
-
<span class="mono">[−π,π]</span>). The tolerance <span class="mono">ε</span> is used by the numerical checks.
|
|
333
|
-
</p>
|
|
334
|
-
</section>
|
|
335
|
-
|
|
336
|
-
<!-- OUTPUT -->
|
|
337
|
-
<section class="card stack" id="output-card" aria-live="polite">
|
|
338
|
-
<h2 style="margin: 0">Output</h2>
|
|
339
|
-
<div class="divider"></div>
|
|
340
|
-
|
|
341
|
-
<!-- Answer KPIs -->
|
|
342
|
-
<section class="stack">
|
|
343
|
-
<div class="kpi">
|
|
344
|
-
<div class="card">
|
|
345
|
-
<div class="k">Answer</div>
|
|
346
|
-
<div id="answer" class="v mono">—</div>
|
|
347
|
-
</div>
|
|
348
|
-
<div class="card">
|
|
349
|
-
<div class="k">Angle θ</div>
|
|
350
|
-
<div id="theta" class="v mono">—</div>
|
|
351
|
-
</div>
|
|
352
|
-
<div class="card">
|
|
353
|
-
<div class="k">e^{iθ} (cos/sin)</div>
|
|
354
|
-
<div id="cis" class="v mono">—</div>
|
|
355
|
-
</div>
|
|
356
|
-
<div class="card">
|
|
357
|
-
<div class="k">Series approx</div>
|
|
358
|
-
<div id="seriesVal" class="v mono">—</div>
|
|
359
|
-
</div>
|
|
360
|
-
</div>
|
|
361
|
-
</section>
|
|
362
|
-
|
|
363
|
-
<!-- Reason Why (mathematical English) -->
|
|
364
|
-
<section class="stack">
|
|
365
|
-
<h3 style="margin: 0">Reason Why</h3>
|
|
366
|
-
<div class="list">
|
|
367
|
-
<div class="term">
|
|
368
|
-
<strong>Power‑series derivation.</strong>
|
|
369
|
-
The exponential, sine, and cosine have the absolutely convergent series for real
|
|
370
|
-
<span class="mono">x</span>:
|
|
371
|
-
<div class="mono">
|
|
372
|
-
e^z = Σ_{n≥0} z^n/n!, cos x = Σ_{n≥0} (−1)^n x^{2n}/(2n)!, sin x = Σ_{n≥0} (−1)^n x^{2n+1}/(2n+1)!.
|
|
373
|
-
</div>
|
|
374
|
-
Substituting <span class="mono">z = ix</span> and regrouping even/odd powers gives
|
|
375
|
-
<span class="mono">e^{ix} = cos x + i sin x</span> (Euler's formula). Taking
|
|
376
|
-
<span class="mono">x = π</span> yields <span class="mono">e^{iπ} = cos π + i sin π = −1 + i·0</span>,
|
|
377
|
-
hence <span class="mono">e^{iπ} + 1 = 0</span>.
|
|
378
|
-
</div>
|
|
379
|
-
<div class="term">
|
|
380
|
-
<strong>Differential‑equation proof.</strong>
|
|
381
|
-
Define <span class="mono">f(x) = e^{-ix}(cos x + i sin x)</span>. Then
|
|
382
|
-
<span class="mono">f'(x) = 0</span>, so <span class="mono">f</span> is constant. As
|
|
383
|
-
<span class="mono">f(0)=1</span>, we have <span class="mono">f(x)=1</span> for all
|
|
384
|
-
<span class="mono">x</span>, and again <span class="mono">e^{ix} = cos x + i sin x</span>.
|
|
385
|
-
</div>
|
|
386
|
-
<div class="term">
|
|
387
|
-
<strong>Geometric picture.</strong>
|
|
388
|
-
The map <span class="mono">x ↦ e^{ix}</span> parametrizes the unit circle counterclockwise. The angle
|
|
389
|
-
<span class="mono">π</span> lands at <span class="mono">−1</span> on the real axis, so adding
|
|
390
|
-
<span class="mono">1</span> returns the origin.
|
|
391
|
-
</div>
|
|
392
|
-
</div>
|
|
393
|
-
</section>
|
|
394
|
-
|
|
395
|
-
<!-- Check (harness) for the user's inputs -->
|
|
396
|
-
<section class="stack">
|
|
397
|
-
<h3 style="margin: 0">Check (harness)</h3>
|
|
398
|
-
<div id="checks" class="list"></div>
|
|
399
|
-
</section>
|
|
400
|
-
</section>
|
|
401
|
-
|
|
402
|
-
<!-- PRELOADED HARNESS CASES (≥ 8) -->
|
|
403
|
-
<section class="card stack harness" id="preloaded">
|
|
404
|
-
<div class="h-title">
|
|
405
|
-
<h2 style="margin: 0">Preloaded Checks (harness)</h2>
|
|
406
|
-
<div class="row">
|
|
407
|
-
<button id="runAll">Run all</button>
|
|
408
|
-
<button class="ghost" id="clearHarness">Clear results</button>
|
|
409
|
-
</div>
|
|
410
|
-
</div>
|
|
411
|
-
<p class="small muted">
|
|
412
|
-
Each block checks that <span class="mono">|e^{iθ}+1| ≤ ε</span> for <span class="mono">θ = π + 2πk</span> and
|
|
413
|
-
fails for a noncongruent angle.
|
|
414
|
-
</p>
|
|
415
|
-
<div id="harnesses" class="stack"></div>
|
|
416
|
-
</section>
|
|
417
|
-
|
|
418
|
-
<footer>
|
|
419
|
-
<div>Built as a self‑checking artifact: program → <em>Answer</em>, <em>Reason Why</em>, <em>Check</em>.</div>
|
|
420
|
-
<div class="small">This page performs only on‑device computation.</div>
|
|
421
|
-
</footer>
|
|
422
|
-
</div>
|
|
423
|
-
|
|
424
|
-
<script>
|
|
425
|
-
// ---------- Math helpers ----------
|
|
426
|
-
const TAU = Math.PI * 2;
|
|
427
|
-
const normAngle = (t) => {
|
|
428
|
-
// wrap to [-π, π]
|
|
429
|
-
let x = ((((t + Math.PI) % TAU) + TAU) % TAU) - Math.PI; // robust modulo
|
|
430
|
-
// handle −0
|
|
431
|
-
return x === 0 ? 0 : x;
|
|
432
|
-
};
|
|
433
|
-
const cis = (t) => ({ re: Math.cos(t), im: Math.sin(t) });
|
|
434
|
-
const add = (a, b) => ({ re: a.re + b.re, im: a.im + b.im });
|
|
435
|
-
const abs = (z) => Math.hypot(z.re, z.im);
|
|
436
|
-
const mul = (a, b) => ({ re: a.re * b.re - a.im * b.im, im: a.re * b.im + a.im * b.re });
|
|
437
|
-
const powComplex = (z, n) => {
|
|
438
|
-
let r = { re: 1, im: 0 };
|
|
439
|
-
for (let i = 0; i < n; i++) r = mul(r, z);
|
|
440
|
-
return r;
|
|
441
|
-
};
|
|
442
|
-
|
|
443
|
-
// power series for cos/sin with N terms and range reduction
|
|
444
|
-
function cosSeries(x, N) {
|
|
445
|
-
x = normAngle(x);
|
|
446
|
-
let term = 1,
|
|
447
|
-
sum = 1; // k=0
|
|
448
|
-
for (let k = 1; k < N; k++) {
|
|
449
|
-
term *= (-x * x) / ((2 * k - 1) * (2 * k));
|
|
450
|
-
sum += term;
|
|
451
|
-
}
|
|
452
|
-
return sum;
|
|
453
|
-
}
|
|
454
|
-
function sinSeries(x, N) {
|
|
455
|
-
x = normAngle(x);
|
|
456
|
-
let term = x,
|
|
457
|
-
sum = x; // k=0
|
|
458
|
-
for (let k = 1; k < N; k++) {
|
|
459
|
-
term *= (-x * x) / (2 * k * (2 * k + 1));
|
|
460
|
-
sum += term;
|
|
461
|
-
}
|
|
462
|
-
return sum;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
function evaluate() {
|
|
466
|
-
const k = Number(document.getElementById('kInput').value || 0);
|
|
467
|
-
const eps = Number(document.getElementById('epsInput').value || 1e-12);
|
|
468
|
-
const N = Math.max(1, Number(document.getElementById('NInput').value || 40));
|
|
469
|
-
|
|
470
|
-
const theta = Math.PI + TAU * k;
|
|
471
|
-
const z = cis(theta);
|
|
472
|
-
const sRe = cosSeries(theta, N),
|
|
473
|
-
sIm = sinSeries(theta, N);
|
|
474
|
-
const zSeries = { re: sRe, im: sIm };
|
|
475
|
-
|
|
476
|
-
const ans = { re: z.re + 1, im: z.im };
|
|
477
|
-
const ansSeries = { re: zSeries.re + 1, im: zSeries.im };
|
|
478
|
-
|
|
479
|
-
document.getElementById('answer').textContent = `|e^{iπ+2πi·${k}} + 1| ≈ ${abs(ans).toExponential(3)}`;
|
|
480
|
-
document.getElementById('theta').textContent = `θ = π + 2π·${k} ≈ ${theta.toPrecision(6)}`;
|
|
481
|
-
document.getElementById('cis').textContent =
|
|
482
|
-
`cos θ + i sin θ ≈ ${z.re.toPrecision(12)} + ${z.im.toPrecision(12)} i`;
|
|
483
|
-
document.getElementById('seriesVal').textContent =
|
|
484
|
-
`series_N=${N} ⇒ ${zSeries.re.toPrecision(12)} + ${zSeries.im.toPrecision(12)} i`;
|
|
485
|
-
|
|
486
|
-
renderChecks(k, eps, N, theta, z, zSeries, ans, ansSeries);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
function renderChecks(k, eps, N, theta, z, zSeries, ans, ansSeries) {
|
|
490
|
-
const checks = document.getElementById('checks');
|
|
491
|
-
const list = [];
|
|
492
|
-
|
|
493
|
-
const eq = abs(ans) <= eps;
|
|
494
|
-
list.push(row(eq, `Equality |e^{iθ}+1| ≤ ε`, `|⋅| ≈ ${abs(ans).toExponential(6)} ≤ ${eps}`));
|
|
495
|
-
|
|
496
|
-
const reOk = Math.abs(z.re + 1) <= eps;
|
|
497
|
-
list.push(
|
|
498
|
-
row(reOk, `Real part ≈ −1`, `Re ≈ ${z.re.toPrecision(12)}, |Re+1| ≈ ${Math.abs(z.re + 1).toExponential(6)}`),
|
|
499
|
-
);
|
|
500
|
-
|
|
501
|
-
const imOk = Math.abs(z.im) <= eps;
|
|
502
|
-
list.push(row(imOk, `Imag part ≈ 0`, `Im ≈ ${z.im.toPrecision(12)}`));
|
|
503
|
-
|
|
504
|
-
const seriesOk = abs(ansSeries) <= Math.max(eps, 1e-15);
|
|
505
|
-
list.push(row(seriesOk, `Series (N=${N})`, `|series+1| ≈ ${abs(ansSeries).toExponential(6)}`));
|
|
506
|
-
|
|
507
|
-
const squareOk = abs(add(mul(z, z), { re: -1, im: 0 })) <= eps * 10; // |(e^{iπ})^2 - 1| small
|
|
508
|
-
list.push(
|
|
509
|
-
row(
|
|
510
|
-
squareOk,
|
|
511
|
-
`Square check`,
|
|
512
|
-
`|(e^{iθ})^2 − 1| ≈ ${abs(add(mul(z, z), { re: -1, im: 0 })).toExponential(6)}`,
|
|
513
|
-
),
|
|
514
|
-
);
|
|
515
|
-
|
|
516
|
-
const periodicOk = abs(cis(theta + TAU)).toExponential
|
|
517
|
-
? abs(add(cis(theta + TAU), { re: 1, im: 0 })) <= eps
|
|
518
|
-
: true;
|
|
519
|
-
list.push(
|
|
520
|
-
row(
|
|
521
|
-
periodicOk,
|
|
522
|
-
`Periodicity`,
|
|
523
|
-
`θ → θ+2π ⇒ |e^{i(θ+2π)}+1| ≈ ${abs(add(cis(theta + TAU), { re: 1, im: 0 })).toExponential(6)}`,
|
|
524
|
-
),
|
|
525
|
-
);
|
|
526
|
-
|
|
527
|
-
list.push(
|
|
528
|
-
el('div', { class: 'row' }, [
|
|
529
|
-
el('span', { class: 'badge ok' }, ['FACT']),
|
|
530
|
-
el('span', { class: 'small muted' }, ['Euler’s formula: e^{ix}=cos x+i sin x; at x=π we get −1.']),
|
|
531
|
-
]),
|
|
532
|
-
);
|
|
533
|
-
|
|
534
|
-
checks.replaceChildren(...list);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const row = (ok, label, msg) =>
|
|
538
|
-
el('div', { class: 'row' }, [
|
|
539
|
-
el('span', { class: 'badge ' + (ok ? 'ok' : 'fail') }, [ok ? 'PASS' : 'FAIL']),
|
|
540
|
-
el('span', { class: 'mono' }, [label]),
|
|
541
|
-
document.createTextNode(' — '),
|
|
542
|
-
el('span', { class: 'mono' }, [msg]),
|
|
543
|
-
]);
|
|
544
|
-
|
|
545
|
-
// ---------- UI helper ----------
|
|
546
|
-
const el = (tag, attrs = {}, children = []) => {
|
|
547
|
-
const node = document.createElement(tag);
|
|
548
|
-
Object.entries(attrs).forEach(([k, v]) => {
|
|
549
|
-
if (k === 'class') node.className = v;
|
|
550
|
-
else if (k === 'html') node.innerHTML = v;
|
|
551
|
-
else if (k.startsWith('on')) node.addEventListener(k.slice(2).toLowerCase(), v);
|
|
552
|
-
else node.setAttribute(k, v);
|
|
553
|
-
});
|
|
554
|
-
children.forEach((c) => node.appendChild(typeof c === 'string' ? document.createTextNode(c) : c));
|
|
555
|
-
return node;
|
|
556
|
-
};
|
|
557
|
-
|
|
558
|
-
document.getElementById('solve').onclick = evaluate;
|
|
559
|
-
document.getElementById('clear').onclick = () => {
|
|
560
|
-
document.getElementById('kInput').value = '0';
|
|
561
|
-
document.getElementById('epsInput').value = '1e-12';
|
|
562
|
-
document.getElementById('NInput').value = '40';
|
|
563
|
-
document.getElementById('answer').textContent = '—';
|
|
564
|
-
document.getElementById('theta').textContent = '—';
|
|
565
|
-
document.getElementById('cis').textContent = '—';
|
|
566
|
-
document.getElementById('seriesVal').textContent = '—';
|
|
567
|
-
document.getElementById('checks').replaceChildren();
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
// ---------- Preloaded harnesses (≥ 9 including one invalid) ----------
|
|
571
|
-
const harnessList = [
|
|
572
|
-
{ k: 0, title: 'θ = π (k=0) ⇒ pass' },
|
|
573
|
-
{ k: 1, title: 'θ = π + 2π (k=1) ⇒ pass' },
|
|
574
|
-
{ k: -1, title: 'θ = π − 2π (k=−1) ⇒ pass' },
|
|
575
|
-
{ k: 6, title: 'θ = π + 12π (k=6) ⇒ pass' },
|
|
576
|
-
{ k: 123, title: 'θ = π + 2π·123 ⇒ pass' },
|
|
577
|
-
{ k: 10 ** 6, title: 'θ = π + 2π·10^6 ⇒ pass (reduced)' },
|
|
578
|
-
{ k: 0, off: Math.PI / 2, title: 'Invalid (should fail): θ = π/2', negative: true },
|
|
579
|
-
{ k: 0, off: Math.PI / 3, title: 'Invalid (should fail): θ = π/3', negative: true },
|
|
580
|
-
{ k: 0, off: 355 / 113 - Math.PI, title: 'θ ≈ 355/113 (π approx) ⇒ nearly pass' },
|
|
581
|
-
];
|
|
582
|
-
|
|
583
|
-
const harnessDiv = document.getElementById('harnesses');
|
|
584
|
-
|
|
585
|
-
function makeHarnessCard(h) {
|
|
586
|
-
const card = el('section', { class: 'card stack' });
|
|
587
|
-
const head = el('div', { class: 'h-title' }, [
|
|
588
|
-
el('div', {}, [el('strong', {}, [h.title])]),
|
|
589
|
-
el('div', { class: 'small muted' }, ['Check (harness)']),
|
|
590
|
-
]);
|
|
591
|
-
const kpis = el('div', { class: 'kpi' });
|
|
592
|
-
const ans = el('div', { class: 'card' });
|
|
593
|
-
ans.append(el('div', { class: 'k' }, ['Answer']), el('div', { class: 'v mono' }, ['—']));
|
|
594
|
-
const thetaCard = el('div', { class: 'card' });
|
|
595
|
-
thetaCard.append(el('div', { class: 'k' }, ['Angle θ']), el('div', { class: 'v mono' }, ['—']));
|
|
596
|
-
const method = el('div', { class: 'card' });
|
|
597
|
-
method.append(el('div', { class: 'k' }, ['Method']), el('div', { class: 'v mono' }, ['cos/sin + series']));
|
|
598
|
-
kpis.append(ans, thetaCard, method);
|
|
599
|
-
|
|
600
|
-
const reason = el('p', { class: 'muted small' }, [
|
|
601
|
-
'We check |e^{iθ}+1| ≤ ε with ε=1e−12, also confirm real/imag parts and series agreement.',
|
|
602
|
-
]);
|
|
603
|
-
const checks = el('div', { class: 'list' });
|
|
604
|
-
const run = el('button', { class: 'secondary' }, ['Run']);
|
|
605
|
-
|
|
606
|
-
run.onclick = () => {
|
|
607
|
-
const eps = 1e-12;
|
|
608
|
-
const N = 40;
|
|
609
|
-
const theta = h.off !== undefined ? h.off : Math.PI + TAU * h.k;
|
|
610
|
-
const z = cis(theta);
|
|
611
|
-
const sRe = cosSeries(theta, N),
|
|
612
|
-
sIm = sinSeries(theta, N);
|
|
613
|
-
const zSeries = { re: sRe, im: sIm };
|
|
614
|
-
const ansZ = { re: z.re + 1, im: z.im };
|
|
615
|
-
const ansSeriesZ = { re: zSeries.re + 1, im: zSeries.im };
|
|
616
|
-
|
|
617
|
-
ans.querySelector('.v').textContent = `|e^{iθ}+1| ≈ ${abs(ansZ).toExponential(6)}`;
|
|
618
|
-
thetaCard.querySelector('.v').textContent = `θ ≈ ${theta.toPrecision(8)}`;
|
|
619
|
-
|
|
620
|
-
const list = [];
|
|
621
|
-
const eq = abs(ansZ) <= eps;
|
|
622
|
-
list.push(row(eq, 'Equality |e^{iθ}+1| ≤ ε', `|⋅| ≈ ${abs(ansZ).toExponential(6)} ≤ ${eps}`));
|
|
623
|
-
const reOk = Math.abs(z.re + 1) <= eps;
|
|
624
|
-
list.push(row(reOk, 'Real ≈ −1', `|Re+1| ≈ ${Math.abs(z.re + 1).toExponential(6)}`));
|
|
625
|
-
const imOk = Math.abs(z.im) <= eps;
|
|
626
|
-
list.push(row(imOk, 'Imag ≈ 0', `|Im| ≈ ${Math.abs(z.im).toExponential(6)}`));
|
|
627
|
-
const seriesOk = abs(ansSeriesZ) <= Math.max(eps, 1e-15);
|
|
628
|
-
list.push(row(seriesOk, `Series (N=${N})`, `|series+1| ≈ ${abs(ansSeriesZ).toExponential(6)}`));
|
|
629
|
-
const squareOk = abs(add(mul(z, z), { re: -1, im: 0 })) <= eps * 10;
|
|
630
|
-
list.push(
|
|
631
|
-
row(
|
|
632
|
-
squareOk,
|
|
633
|
-
'Square check',
|
|
634
|
-
`|(e^{iθ})^2 − 1| ≈ ${abs(add(mul(z, z), { re: -1, im: 0 })).toExponential(6)}`,
|
|
635
|
-
),
|
|
636
|
-
);
|
|
637
|
-
const periodicOk = abs(add(cis(theta + TAU), { re: 1, im: 0 })) <= eps;
|
|
638
|
-
list.push(row(periodicOk, 'Periodicity', `θ→θ+2π check`));
|
|
639
|
-
|
|
640
|
-
checks.replaceChildren(...list);
|
|
641
|
-
};
|
|
642
|
-
|
|
643
|
-
if (h.negative) {
|
|
644
|
-
const warn = el('div', { class: 'small muted' }, [
|
|
645
|
-
'This case is intentionally invalid and should report a failure.',
|
|
646
|
-
]);
|
|
647
|
-
card.append(head, kpis, reason, warn, checks, run);
|
|
648
|
-
} else {
|
|
649
|
-
card.append(head, kpis, reason, checks, run);
|
|
650
|
-
}
|
|
651
|
-
return card;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
harnessList.forEach((h) => harnessDiv.appendChild(makeHarnessCard(h)));
|
|
655
|
-
document.getElementById('runAll').onclick = () => {
|
|
656
|
-
[...harnessDiv.querySelectorAll('button.secondary')].forEach((b) => b.click());
|
|
657
|
-
};
|
|
658
|
-
document.getElementById('clearHarness').onclick = () => {
|
|
659
|
-
harnessDiv.querySelectorAll('.list').forEach((div) => div.replaceChildren());
|
|
660
|
-
harnessDiv.querySelectorAll('.v').forEach((div) => (div.textContent = '—'));
|
|
661
|
-
};
|
|
662
|
-
|
|
663
|
-
// auto-evaluate initial sample
|
|
664
|
-
evaluate();
|
|
665
|
-
</script>
|
|
666
|
-
</body>
|
|
667
|
-
</html>
|