The following is a Pi calculator delivered as a WebAssembly (WASM). Where our API based random Pi generator makes calls to a dedicated Pi calculation server, this WebAssembly approach embeds a Go based calculator that runs in a visitor’s browser.
The Go code for this web assembly is below:
Go
//go:build js && wasm
package main
import (
"math/big"
"syscall/js"
)
// CalculatePi returns Pi to `digits` decimal places using Gauss-Legendre algorithm.
func CalculatePi(this js.Value, args []js.Value) interface{} {
digits := args[0].Int()
precision := uint(digits * 4) // bits; not as fine as MPFR, but works for demo
one := big.NewFloat(1).SetPrec(precision)
two := big.NewFloat(2).SetPrec(precision)
four := big.NewFloat(4).SetPrec(precision)
// a = 1
a := new(big.Float).SetPrec(precision).Set(one)
// b = 1 / sqrt(2)
b := new(big.Float).SetPrec(precision)
b.Sqrt(two)
b.Quo(one, b)
// t = 1/4
t := new(big.Float).SetPrec(precision).Set(one)
t.Quo(t, four)
// p = 1
p := new(big.Float).SetPrec(precision).Set(one)
// Iterative Process (fixed 8-10 iterations for convergence)
var tmp, aNext, bNext, tNext, piApprox = new(big.Float), new(big.Float), new(big.Float), new(big.Float), new(big.Float)
for i := 0; i < 8; i++ {
// aNext = (a + b)/2
aNext.Add(a, b)
aNext.Quo(aNext, two)
// bNext = sqrt(a*b)
bNext.Mul(a, b)
bNext.Sqrt(bNext)
// tNext = t - p * (a - aNext)^2
tmp.Sub(a, aNext)
tmp.Mul(tmp, tmp)
tmp.Mul(tmp, p)
tNext.Sub(t, tmp)
// p = 2*p
p.Mul(p, two)
// update
a.Set(aNext)
b.Set(bNext)
t.Set(tNext)
}
// pi = (a + b)^2 / (4*t)
piApprox.Add(a, b)
piApprox.Mul(piApprox, piApprox)
tmp.Mul(four, t)
piApprox.Quo(piApprox, tmp)
// Format result
piStr := piApprox.Text('f', digits)
return js.ValueOf(piStr)
}
func main() {
js.Global().Set("calculatePiGo", js.FuncOf(CalculatePi))
select {} // prevent exit
}
The following can be used in a WordPress Guttenberg HTML block:
HTML
<div>
<label for="digits">Digits of π to calculate (max 500):</label>
<input id="digits" type="number" value="10" min="1" max="500" />
<button id="calc-btn">Calculate</button>
<pre id="result"></pre>
</div>
<script src="https://picalculator.app/wp-content/uploads/wasm_exec.js"></script>
<script>
window.addEventListener('DOMContentLoaded', () => {
const go = new Go();
WebAssembly.instantiateStreaming(
fetch("https://picalculator.app/wp-content/uploads/pi.wasm"),
go.importObject
).then((result) => {
go.run(result.instance);
document.getElementById('calc-btn').onclick = function () {
let digits = parseInt(document.getElementById('digits').value, 10);
// Enforce digit limits
if (digits > 500) digits = 500;
if (digits < 1 || isNaN(digits)) digits = 10;
document.getElementById('digits').value = digits;
const pi = window.calculatePiGo(digits);
// Format Pi into 20-digit blocks, 2 blocks per line
const raw = pi.toString(); // Full Pi string, e.g., "3.1415..."
const head = raw.slice(0, 2); // "3."
const rest = raw.slice(2); // Everything after "3."
const blocks = rest.match(/.{1,20}/g) || []; // Split into 20-digit blocks
let formattedRows = [];
for (let i = 0; i < blocks.length; i += 2) {
const block1 = blocks[i];
const block2 = blocks[i + 1] || '';
const row = (i === 0 ? '' : ' ') + block1 + ' ' + block2; // 2-space indent from 2nd line
formattedRows.push(row);
}
const formatted = head + formattedRows.join('\n'); // Combine with newlines
document.getElementById('result').textContent = formatted;
};
});
});
</script>
Compiling a WASM in Go can be accomplished with this BASH command. Don't forget to copy the execution JavaScript file that Go provides!
Bash
GOOS=js GOARCH=wasm go build -o main.wasm
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" /path/to/wordpress/js/