1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>`gt` calculator - a calculator built with local LLMs</title>
<link rel="shortcut icon" type="image/gif" href="/favicon.ico" />
<link rel="stylesheet" href="../style.css" />
<link rel="stylesheet" href="style-override.css" />
</head>
<body>
<p class="header">
<a href="https://foo.zone">Home</a> | <a href="https://codeberg.org/snonux/foo.zone/src/branch/content-md/gemfeed/2026-06-01-gt-calculator.md">Markdown</a> | <a href="gemini://foo.zone/gemfeed/2026-06-01-gt-calculator.gmi">Gemini</a> | <a href="https://snonux.foo">Microblog</a> | <a href="https://irregular.ninja">Street photography</a>
</p>
<h1 style='display: inline' id='gt-calculator---a-calculator-built-with-local-llms'><span class='inlinecode'>gt</span> calculator - a calculator built with local LLMs</h1><br />
<br />
<span class='quote'>Published at 2026-05-31T14:24:10+03:00</span><br />
<br />
<span>I created a calculator. Not because the world needed another one, but because I wanted to test something: how well do local LLMs hold up as pair programmers on a real project?</span><br />
<br />
<span>The answer is: well enough for small projects like this.</span><br />
<br />
<span><span class='inlinecode'>gt</span> is a command-line calculator written in Go that does RPN (Reverse Polish Notation), percentage calculations, unit conversion, and a fair bit more. The name stands for "greater than" — <span class='inlinecode'>gt</span> is a comparison operator the calculator supports. Plus it was free in my shell (<span class='inlinecode'>gt</span> command wasn't used yet by another tool) and I liked the short name.</span><br />
<br />
<span>If you want the full feature guide, the README links to a detailed doc for every feature covered here and more:</span><br />
<br />
<a class='textlink' href='https://codeberg.org/snonux/gt'>gt on Codeberg</a><br />
<a href='./gt-calculator/logo.svg'><img alt='gt logo' title='gt logo' src='./gt-calculator/logo.svg' /></a><br />
<br />
<span>The whole thing — code, tests, documentation, even the logo — was built using only LLMs that can run locally on reasonable hardware: Qwen, Gemma, Nemotron, GPT-OSS. To be honest, I didn't run them locally either — I rented a Hyperstack VMs with NVidia GPU just to get a feel for the quality before investing in hardware. The point was to test models that don't require a cloud API and could realistically run on your own box.</span><br />
<br />
<a class='textlink' href='https://www.hyperstack.cloud/'>https://www.hyperstack.cloud/</a><br />
<br />
<span>This post is about the calculator and what it does. My experience running those LLMs as pair programmers will be a separate post later.</span><br />
<br />
<span>And no, this wasn't vibe-coded. I used a specific technique and a set of AI skills to drive the LLMs. The codebase came out well-structured and maintainable — not the "prompt it and pray" mess. </span><br />
<br />
<h2 style='display: inline' id='table-of-contents'>Table of Contents</h2><br />
<br />
<ul>
<li><a href='#gt-calculator---a-calculator-built-with-local-llms'><span class='inlinecode'>gt</span> calculator - a calculator built with local LLMs</a></li>
<li>⇢ <a href='#the-motivation'>The motivation</a></li>
<li>⇢ <a href='#what-it-does'>What it does</a></li>
<li>⇢ <a href='#percentage-calculations'>Percentage calculations</a></li>
<li>⇢ <a href='#rpn-arithmetic'>RPN arithmetic</a></li>
<li>⇢ ⇢ <a href='#modulo'>Modulo</a></li>
<li>⇢ ⇢ <a href='#logarithms'>Logarithms</a></li>
<li>⇢ ⇢ <a href='#hyper-operators-n-ary'>Hyper operators (n-ary)</a></li>
<li>⇢ ⇢ <a href='#comparisons-and-booleans'>Comparisons and booleans</a></li>
<li>⇢ <a href='#variables-and-symbols'>Variables and symbols</a></li>
<li>⇢ <a href='#built-in-constants'>Built-in constants</a></li>
<li>⇢ <a href='#the-metrics-system'>The metrics system</a></li>
<li>⇢ ⇢ <a href='#suffix-notation'>Suffix notation</a></li>
<li>⇢ ⇢ <a href='#unit-conversion'>Unit conversion</a></li>
<li>⇢ ⇢ <a href='#metric-aware-arithmetic'>Metric-aware arithmetic</a></li>
<li>⇢ ⇢ <a href='#custom-metrics'>Custom metrics</a></li>
<li>⇢ ⇢ <a href='#si-vs-iec-modes'>SI vs IEC modes</a></li>
<li>⇢ ⇢ <a href='#discovering-metrics'>Discovering metrics</a></li>
<li>⇢ <a href='#stack-manipulation'>Stack manipulation</a></li>
<li>⇢ <a href='#rational-number-mode'>Rational number mode</a></li>
<li>⇢ <a href='#the-repl'>The REPL</a></li>
<li>⇢ <a href='#some-more-usage-examples'>Some more usage examples</a></li>
<li>⇢ <a href='#fish-shell-completions'>Fish shell completions</a></li>
<li>⇢ <a href='#installation'>Installation</a></li>
<li>⇢ <a href='#wrapping-up'>Wrapping up</a></li>
</ul><br />
<h2 style='display: inline' id='the-motivation'>The motivation</h2><br />
<br />
<span>Four things drove this.</span><br />
<br />
<span>First, I wanted to test local LLMs as coding partners. Not the cloud-hosted ones with infinite context and billions of parameters — the ones you can actually run yourself. I figured a calculator project is big enough to be interesting but small enough to finish.</span><br />
<br />
<span>Second, cloud independence is a thing I care about. I build tools that don't need a network connection to function. Writing software that talks to OpenAI or Anthropic APIs doesn't count as "running locally." Everything here runs offline.</span><br />
<br />
<span>Third, I wanted to learn more about how these models actually work in practice. Not benchmarks or leaderboard scores — the day-to-day experience. How do you operate them? How do you structure prompts? When do they produce clean code versus garbage? Where do they struggle?</span><br />
<br />
<span>Finally, the tool needed to be genuinely useful. A toy that calculates <span class='inlinecode'>2 + 2</span> isn't worth the disk space. I aimed for a calculator I'd actually reach for.</span><br />
<br />
<h2 style='display: inline' id='what-it-does'>What it does</h2><br />
<br />
<span>At its core, <span class='inlinecode'>gt</span> is a stack-based RPN calculator with percentage support and a full metrics system. It runs as a single binary, has no dependencies, and works three ways:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'3 4 +'</font> <i><font color="silver"># one-liner: RPN</font></i>
gt <font color="#808080">'20% of 150'</font> <i><font color="silver"># one-liner: percentage</font></i>
gt <i><font color="silver"># interactive REPL</font></i>
</pre>
<br />
<span>You can also pipe into it: <span class='inlinecode'>echo '1000Mbps @Gbps convert' | gt</span> → <span class='inlinecode'>1</span>.</span><br />
<br />
<h2 style='display: inline' id='percentage-calculations'>Percentage calculations</h2><br />
<br />
<span>This is the simplest entry point. Three forms, all case-insensitive, all with step-by-step output:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'20% of 150'</font> <i><font color="silver"># → 30.00</font></i>
gt <font color="#808080">'30 is what % of 150'</font> <i><font color="silver"># → 20.00%</font></i>
gt <font color="#808080">'30 is 20% of what'</font> <i><font color="silver"># → 150.00</font></i>
</pre>
<br />
<span>Every percentage result shows the formula and intermediate values, so you can verify the math. Useful for tips, discounts, tax, and any "what's the actual number?" moment.</span><br />
<br />
<h2 style='display: inline' id='rpn-arithmetic'>RPN arithmetic</h2><br />
<br />
<span>The main engine uses Reverse Polish Notation. No parentheses needed — the order of tokens determines the order of operations.</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'3 4 +'</font> <i><font color="silver"># 7</font></i>
gt <font color="#808080">'2 10 ^'</font> <i><font color="silver"># 1024</font></i>
gt <font color="#808080">'100 10 / 5 +'</font> <i><font color="silver"># 15</font></i>
gt <font color="#808080">'3 4 + 5 6 + *'</font> <i><font color="silver"># (3+4) × (5+6) = 77</font></i>
</pre>
<br />
<span>Six basic operators: <span class='inlinecode'>+</span>, <span class='inlinecode'>-</span>, <span class='inlinecode'>*</span>, <span class='inlinecode'>/</span>, <span class='inlinecode'>^</span>, <span class='inlinecode'>%</span>. All work on the stack, popping operands and pushing the result.</span><br />
<br />
<span>The fast integer power operator <span class='inlinecode'>**</span> uses binary exponentiation (O(log n) instead of O(n)). So <span class='inlinecode'>2 100 **</span> does about 7 multiplications instead of 99. It only accepts integer exponents — use <span class='inlinecode'>^</span> for fractional powers.</span><br />
<br />
<h3 style='display: inline' id='modulo'>Modulo</h3><br />
<br />
<span><span class='inlinecode'>%</span> gives the remainder after division:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'17 5 %'</font> <i><font color="silver"># → 2</font></i>
gt <font color="#808080">'100 7 %'</font> <i><font color="silver"># → 2</font></i>
</pre>
<br />
<h3 style='display: inline' id='logarithms'>Logarithms</h3><br />
<br />
<span>Three unary operators for when you need them:</span><br />
<br />
<span>- <span class='inlinecode'>lg</span> — base 2 (information theory, algorithm complexity)</span><br />
<span>- <span class='inlinecode'>log</span> — base 10 (decibels, pH, order of magnitude)</span><br />
<span>- <span class='inlinecode'>ln</span> — natural log (continuous growth, statistics)</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'1024 lg'</font> <i><font color="silver"># → 10</font></i>
gt <font color="#808080">'1000 log'</font> <i><font color="silver"># → 3</font></i>
gt <font color="#808080">'e ln'</font> <i><font color="silver"># → 1.0000000000</font></i>
</pre>
<br />
<h3 style='display: inline' id='hyper-operators-n-ary'>Hyper operators (n-ary)</h3><br />
<br />
<span>Want to add everything on the stack at once? Square-bracket operators pop the entire stack and reduce left-associatively:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'1 2 3 4 5 [+]'</font> <i><font color="silver"># → 15 (sum of all)</font></i>
gt <font color="#808080">'100 10 20 30 5 [-]'</font> <i><font color="silver"># → 35 (100-10-20-30-5)</font></i>
gt <font color="#808080">'2 5 10 [*]'</font> <i><font color="silver"># → 100 (product)</font></i>
gt <font color="#808080">'1000 2 2 2 2 [/]'</font> <i><font color="silver"># → 62.5</font></i>
</pre>
<br />
<span>Full set: <span class='inlinecode'>[+]</span>, <span class='inlinecode'>[-]</span>, <span class='inlinecode'>[*]</span>, <span class='inlinecode'>[/]</span>, <span class='inlinecode'>[^]</span>, <span class='inlinecode'>[%]</span> for arithmetic, plus <span class='inlinecode'>[lg]</span>, <span class='inlinecode'>[log]</span>, <span class='inlinecode'>[ln]</span> for logarithms. The log hyper operators work differently from the arithmetic ones — they compute the sum of the log function applied to each value, not a left-associative reduction. A quick entropy calculation:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'0.25 0.5 0.25 [lg]'</font> <i><font color="silver"># → -5 (information theory entropy bits)</font></i>
</pre>
<br />
<span>The square-bracket syntax is inspired by Raku's hyper operators.</span><br />
<br />
<a class='textlink' href='https://raku.org'>https://raku.org</a><br />
<br />
<h3 style='display: inline' id='comparisons-and-booleans'>Comparisons and booleans</h3><br />
<br />
<span>Six comparison operators, each with a symbolic alias:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'5 3 gt'</font> <i><font color="silver"># → true</font></i>
gt <font color="#808080">'3 5 <'</font> <i><font color="silver"># → true</font></i>
gt <font color="#808080">'5 5 =='</font> <i><font color="silver"># → true</font></i>
</pre>
<br />
<span>Results are <span class='inlinecode'>true</span> or <span class='inlinecode'>false</span>, which coerce into arithmetic (true = 1, false = 0). That means you can do inline conditionals:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'85 80 gt 10 *'</font> <i><font color="silver"># → 10 (85 > 80, so 1 × 10)</font></i>
gt <font color="#808080">'50 80 gt 10 *'</font> <i><font color="silver"># → 0 (50 < 80, so 0 × 10)</font></i>
</pre>
<br />
<span>Range validation works by summing boolean results:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'72 68 gte 100 lte +'</font> <i><font color="silver"># → 2 (both checks pass, temp is in range)</font></i>
gt <font color="#808080">'105 68 gte 100 lte +'</font> <i><font color="silver"># → 1 (out of range)</font></i>
</pre>
<br />
<span>Booleans also do plain arithmetic, which is occasionally useful:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'true true +'</font> <i><font color="silver"># → 2 (1 + 1)</font></i>
gt <font color="#808080">'false 5 +'</font> <i><font color="silver"># → 5 (0 + 5)</font></i>
</pre>
<br />
<h2 style='display: inline' id='variables-and-symbols'>Variables and symbols</h2><br />
<br />
<span>Store values with three assignment styles:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'x 10 :='</font> <i><font color="silver"># right assignment</font></i>
gt <font color="#808080">'20 y =:'</font> <i><font color="silver"># left assignment</font></i>
gt <font color="#808080">'rate 100Mbps ='</font> <i><font color="silver"># standard (or rate = 100Mbps)</font></i>
</pre>
<br />
<span><span class='inlinecode'>vars</span> lists them, <span class='inlinecode'>clear</span> wipes all variables and constants, <span class='inlinecode'>:name d</span> deletes one. In REPL mode, variables persist to disk between sessions.</span><br />
<br />
<span>Symbols (the <span class='inlinecode'>:x</span> syntax) are named placeholders on the stack. The <span class='inlinecode'>:</span> prefix makes intent explicit: <span class='inlinecode'>:x</span> always pushes the symbol <span class='inlinecode'>x</span>, even if a variable named <span class='inlinecode'>x</span> already exists. This is how you delete a variable without ambiguity, and how you push a name onto the stack without resolving it.</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>> x <font color="#000000">10</font> := <i><font color="silver"># define x</font></i>
> x <i><font color="silver"># pushes 10 (variable resolved)</font></i>
> :x <i><font color="silver"># pushes :x (the symbol itself)</font></i>
> :x d <i><font color="silver"># deletes the variable x</font></i>
</pre>
<br />
<span>Bare identifiers that don't match any variable or constant also push as symbols.</span><br />
<br />
<h2 style='display: inline' id='built-in-constants'>Built-in constants</h2><br />
<br />
<span>Thirty-six of them. Use them directly as tokens:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'pi 2 *'</font> <i><font color="silver"># → 6.283185307</font></i>
gt <font color="#808080">'euler'</font> <i><font color="silver"># → 2.718281828</font></i>
gt <font color="#808080">'phi 10 *'</font> <i><font color="silver"># → 16.18 (golden rectangle)</font></i>
gt <font color="#808080">'sqrt2 sqrt3 *'</font> <i><font color="silver"># → 2.449 (√6)</font></i>
</pre>
<br />
<span>Greek letter aliases work too: <span class='inlinecode'>π</span>, <span class='inlinecode'>τ</span>, <span class='inlinecode'>φ</span>, <span class='inlinecode'>√2</span>, <span class='inlinecode'>√3</span>, <span class='inlinecode'>√5</span>.</span><br />
<br />
<span>There's also a <span class='inlinecode'>constants</span> command that lists all 36 in one shot. Edge cases are covered too — <span class='inlinecode'>inf</span>, <span class='inlinecode'>-inf</span>, and <span class='inlinecode'>nan</span> exist as constants if you ever need them.</span><br />
<br />
<h2 style='display: inline' id='the-metrics-system'>The metrics system</h2><br />
<br />
<span>This is where <span class='inlinecode'>gt</span> earns its swiss army knife title. Every number carries a unit of measurement, and arithmetic understands those units.</span><br />
<br />
<span>Six built-in categories, plus <span class='inlinecode'>Cool</span> — the default unitless metric for plain numbers. The name comes from Raku's <span class='inlinecode'>Cool</span> role, which represents things that are "cool enough" to do basic operations (strings, numbers, etc.). In <span class='inlinecode'>gt</span>, Cool values absorb into any metric category during arithmetic, so <span class='inlinecode'>5 100Mbps +</span> treats the <span class='inlinecode'>5</span> as <span class='inlinecode'>5Mbps</span>.</span><br />
<br />
<span>- *DataRate*: bps, Kbps, Mbps, Gbps, Tbps</span><br />
<span>- *DataSize*: bits, bytes, KB/MB/GB/TB/PB (SI), KiB/MiB/GiB/TiB/PiB (IEC)</span><br />
<span>- *Time*: ms, s, min, hr, day</span><br />
<span>- *Weight*: mg, g, kg, lb, oz, ton</span><br />
<span>- *Speed*: mps, kmh, mph, knots</span><br />
<span>- *Distance*: m, km, mi, ft, in, nm (nautical miles)</span><br />
<br />
<h3 style='display: inline' id='suffix-notation'>Suffix notation</h3><br />
<br />
<span>Attach units directly to numbers:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'100Mbps'</font> <i><font color="silver"># 100 megabits per second</font></i>
gt <font color="#808080">'5GB'</font> <i><font color="silver"># 5 gigabytes</font></i>
gt <font color="#808080">'1hr'</font> <i><font color="silver"># 1 hour</font></i>
gt <font color="#808080">'70kg'</font> <i><font color="silver"># 70 kilograms</font></i>
</pre>
<br />
<h3 style='display: inline' id='unit-conversion'>Unit conversion</h3><br />
<br />
<span>Use <span class='inlinecode'>@<target> convert</span>:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'1000Mbps @Gbps convert'</font> <i><font color="silver"># → 1</font></i>
gt <font color="#808080">'1km @mi convert'</font> <i><font color="silver"># → 0.6213711922</font></i>
gt <font color="#808080">'60mph @kmh convert'</font> <i><font color="silver"># → 96.56</font></i>
gt <font color="#808080">'3day @s convert'</font> <i><font color="silver"># → 259200</font></i>
</pre>
<br />
<h3 style='display: inline' id='metric-aware-arithmetic'>Metric-aware arithmetic</h3><br />
<br />
<span>Addition and subtraction auto-convert within categories:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'1km 500m +'</font> <i><font color="silver"># → 1.5 (converted to km)</font></i>
gt <font color="#808080">'1Gbps 500Mbps -'</font> <i><font color="silver"># → 500 (in Mbps)</font></i>
</pre>
<br />
<span>Multiplication and division do cross-category inference:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'100Mbps 1hr *'</font> <i><font color="silver"># rate × time = data transferred</font></i>
gt <font color="#808080">'10GB 2hr /'</font> <i><font color="silver"># data / time = rate</font></i>
gt <font color="#808080">'100kmh 1hr * @mi convert'</font> <i><font color="silver"># → 62.14 miles traveled</font></i>
</pre>
<br />
<span>Comparison operators are metric-aware too:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>gt <font color="#808080">'1km 1000m eq'</font> <i><font color="silver"># → true</font></i>
gt <font color="#808080">'1GB 1024MB eq'</font> <i><font color="silver"># → false (SI: 1GB = 1000MB)</font></i>
</pre>
<br />
<h3 style='display: inline' id='custom-metrics'>Custom metrics</h3><br />
<br />
<span>Define your own units:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>custom define reel <font color="#000000">304.8</font> Distance <i><font color="silver"># surveyor's reel</font></i>
custom define fortnight <font color="#000000">1209600</font> Time <i><font color="silver"># 14 days</font></i>
custom define cup <font color="#000000">240</font> Weight <i><font color="silver"># cooking measure</font></i>
</pre>
<br />
<span>Then use them like built-ins:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>> 5reel @m convert
<font color="#000000">1524</font>
> 2fortnight @day convert
<font color="#000000">28</font>
> 3cup @g convert
<font color="#000000">720</font>
</pre>
<br />
<h3 style='display: inline' id='si-vs-iec-modes'>SI vs IEC modes</h3><br />
<br />
<span>Data size units have two modes. SI (default) uses powers of 1000. IEC uses powers of 1024. Switch with <span class='inlinecode'>metric decimal set</span> / <span class='inlinecode'>metric binary set</span>. The dedicated IEC units (KiB, MiB, GiB) are always unambiguous.</span><br />
<br />
<h3 style='display: inline' id='discovering-metrics'>Discovering metrics</h3><br />
<br />
<span>You can explore what's available without leaving the REPL:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>> metric list
DataRate, DataSize, Distance, Speed, Time, Universal, Weight
> metric DataRate
Gbps, Kbps, Mbps, Tbps, bps
</pre>
<br />
<span><span class='inlinecode'>metric compatible</span> checks whether two values can be combined before you try:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>> 1km 5mi metric compatible
km (Distance) and mi (Distance): <b><u><font color="#000000">true</font></u></b>
> 100Mbps 2hr metric compatible
Mbps (DataRate) and hr (Time): <b><u><font color="#000000">false</font></u></b>
</pre>
<br />
<h2 style='display: inline' id='stack-manipulation'>Stack manipulation</h2><br />
<br />
<span>Five operators for managing the RPN stack:</span><br />
<br />
<span>- <span class='inlinecode'>dup</span> — duplicate the top value</span><br />
<span>- <span class='inlinecode'>swap</span> — swap top two values</span><br />
<span>- <span class='inlinecode'>pop</span> — discard the top value</span><br />
<span>- <span class='inlinecode'>show</span> / <span class='inlinecode'>showstack</span> / <span class='inlinecode'>print</span> — display the stack without modifying it</span><br />
<span>- <span class='inlinecode'>clear</span> — clear all variables and constants</span><br />
<br />
<span><span class='inlinecode'>dup</span> and <span class='inlinecode'>swap</span> come up a lot. Square a number: <span class='inlinecode'>7 dup *</span> → 49. Reverse operand order: <span class='inlinecode'>2 10 swap /</span> → 5 (instead of 0.2). <span class='inlinecode'>pop</span> discards the top value if you pushed something by accident: <span class='inlinecode'>5 6 pop</span> → 5.</span><br />
<br />
<h2 style='display: inline' id='rational-number-mode'>Rational number mode</h2><br />
<br />
<span>"Rational" refers to rational numbers — numbers that can be expressed as an exact fraction of two integers (numerator/denominator). The name "rat" is just the shorthand command.</span><br />
<br />
<span>In the default float64 mode, numbers are stored as binary floating-point approximations. <span class='inlinecode'>0.1</span> cannot be represented exactly in binary, so it becomes something like <span class='inlinecode'>0.1000000000000000055511151231257827...</span>. This causes the classic problem:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>> rat off
Rational mode disabled (using float64)
> <font color="#000000">0.3</font> <font color="#000000">0.1</font> - <font color="#000000">0.2</font> -
-<font color="#000000">2.775557562e-17</font>
</pre>
<br />
<span>The result should be <span class='inlinecode'>0</span>, but floating-point rounding errors accumulated. Silent wrong answer.</span><br />
<br />
<span>Rational mode stores numbers as exact fractions using Go's <span class='inlinecode'>math/big.Rat</span>. <span class='inlinecode'>0.1</span> is stored as <span class='inlinecode'>1/10</span>, <span class='inlinecode'>0.2</span> as <span class='inlinecode'>2/10</span> (simplified to <span class='inlinecode'>1/5</span>), and all arithmetic operates on those exact values. No binary approximation, no silent drift.</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>> rat on
Rational mode enabled
> <font color="#000000">0.1</font> <font color="#000000">0.2</font> +
<font color="#000000">0.3000000000</font>
</pre>
<br />
<span>Internally, <span class='inlinecode'>1/3</span> stays as the exact fraction <span class='inlinecode'>1/3</span>, and <span class='inlinecode'>1/3 * 3</span> computes to exactly <span class='inlinecode'>3/3 = 1</span>. No binary conversion, no rounding.</span><br />
<br />
<span>REPL-only. Has a known limitation with non-dyadic decimals and metric operations — the docs explain the why.</span><br />
<br />
<h2 style='display: inline' id='the-repl'>The REPL</h2><br />
<br />
<span>Run <span class='inlinecode'>gt</span> with no arguments when attached to a terminal and you get the interactive session. Command history (1000 entries, persisted to <span class='inlinecode'>~/.gt_history</span>), tab completion, Emacs-style line editing, Ctrl+R reverse search.</span><br />
<br />
<span>Variables save to disk between sessions. Session state lives in <span class='inlinecode'>~/.local/state/gt/vars</span>. For auditing or note-taking, session logging works like this:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>$ gt --log calc-session.log
> 1Gbps 1hr *
> @GB convert
> quit
</pre>
<br />
<span>Built-in REPL commands: <span class='inlinecode'>help</span>, <span class='inlinecode'>clear</span>, <span class='inlinecode'>quit</span>/<span class='inlinecode'>exit</span>, <span class='inlinecode'>rpn</span>/<span class='inlinecode'>calc</span>, <span class='inlinecode'>rat</span>, <span class='inlinecode'>stack</span>. <span class='inlinecode'>stack</span> is a shorthand hint for viewing the RPN stack. Tab-completes.</span><br />
<br />
<span>Here's what a session looks like:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>$ gt
> rate 100Mbps =
rate = <font color="#000000">100</font>
> time 2hr =
time = <font color="#000000">2</font>
> rate time *
<font color="#000000">200</font> Mbps
> metric show
Mbps, DataRate, base: bps, factor: <font color="#000000">1e+06</font>
> download 50GB =
download = <font color="#000000">50</font>
> speed 100Mbps =
speed = <font color="#000000">100</font>
> download speed / @min convert
<font color="#000000">83.33333333</font>
> custom define reel <font color="#000000">304.8</font> Distance
defined custom metric <font color="#808080">"reel"</font> (factor: <font color="#000000">304.8</font>, category: Distance)
> 5reel @m convert
<font color="#000000">1524</font>
> 100Mbps 50Mbps swap -
<font color="#000000">50</font> Mbps
> show
<font color="#000000">50</font> Mbps
> <font color="#000000">20</font>% of <font color="#000000">150</font>
<font color="#000000">20.00</font>% of <font color="#000000">150.00</font> = <font color="#000000">30.00</font>
Steps: (<font color="#000000">20.00</font> / <font color="#000000">100</font>) * <font color="#000000">150.00</font> = <font color="#000000">0.20</font> * <font color="#000000">150.00</font> = <font color="#000000">30.00</font>
> rat on
Rational mode enabled
> <font color="#000000">1</font> <font color="#000000">3</font> / <font color="#000000">3</font> *
<font color="#000000">1.0000000000</font>
> vars
rate = <font color="#000000">100</font>
time = <font color="#000000">2</font>
download = <font color="#000000">50</font>
speed = <font color="#000000">100</font>
</pre>
<br />
<span>Inline help is built in. Bare <span class='inlinecode'>help</span> lists all commands, and <span class='inlinecode'>help <command></span> drills into one topic:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre>> <b><u><font color="#000000">help</font></u></b> rat
rat on/off/toggle - Switch between float64 and rational number modes
rat on Enable rational mode (exact fractions)
rat off Disable rational mode (use float64)
rat toggle Toggle current mode
> <b><u><font color="#000000">help</font></u></b> clear
clear - Clear the screen
Usage: clear
</pre>
<br />
<span>No need to leave the REPL or dig through docs when you forget a subcommand.</span><br />
<br />
<h2 style='display: inline' id='some-more-usage-examples'>Some more usage examples</h2><br />
<br />
<span>Here are some more <span class='inlinecode'>gt</span> usage examples:</span><br />
<br />
<!-- Generator: GNU source-highlight 3.1.9
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><i><font color="silver"># Download v
|